Compare commits

..

2 Commits

Author SHA1 Message Date
Jason Turner
5852412d2c Merge branch 'develop' into Workaround_Thread_Local_MinGW 2016-01-12 15:00:45 -07:00
Jason Turner
21c3853537 Attempt to work around issue with thread_local in mingw` 2015-11-20 07:19:37 -06:00
160 changed files with 7151 additions and 9788 deletions

View File

@ -1,12 +1,11 @@
compilers: compilers:
- name: "clang" - name: "clang"
version: "3.6" version: "3.5"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
collect_performance_results: true
- name: "clang" - name: "clang"
build_tag: "LibC++" build_tag: "LibC++"
version: "3.6" version: "3.5"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "clang" - name: "clang"
@ -19,35 +18,13 @@ compilers:
version: "3.6" version: "3.6"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON
- name: "clang"
version: "3.7"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: "clang"
build_tag: "LibC++"
version: "3.7"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "gcc" - name: "gcc"
version: "4.9" version: "4.8"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON
collect_performance_results: true
- name: "gcc" - name: "gcc"
version: "4.9" version: "4.6"
skip_packaging: true skip_packaging: true
build_tag: "NoThreads" cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON -DMULTITHREAD_SUPPORT_ENABLED:BOOL=OFF
collect_performance_results: true
- name: "gcc"
version: "5"
skip_packaging: true
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: cppcheck - name: cppcheck
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:unittests/catch.hpp" --force --suppress="unusedFunction:*" compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force
- name: custom_check
commands:
- ./contrib/check_for_tabs.rb
- ./contrib/check_for_todos.rb

View File

@ -2,4 +2,8 @@ compilers:
- name: clang - name: clang
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
build_package_generator: TBZ2 build_package_generator: TBZ2
- name: clang
build_type: Debug
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
skip_packaging: true

View File

@ -11,11 +11,10 @@ compilers:
compiler_extra_flags: /analyze compiler_extra_flags: /analyze
skip_packaging: true skip_packaging: true
- name: Visual Studio - name: Visual Studio
version: 14 version: 12
build_type: Debug cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
- name: Visual Studio
version: 12
architecture: Win64 architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA% cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /analyze
skip_packaging: true

View File

@ -1,41 +0,0 @@
# Contributing to ChaiScript
Thank you for contributing!
# Pull Requests
Please follow the existing style in the code you are patching.
- two space indent
- no tabs EVER
- match the existing indentation level
All ChaiScript commits are run through a large set of builds and analysis on all supported platforms. Those results are posted on the
[build dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html). No PR will be accepted until all tests pass.
The build system has full integration with GitHub and you will be notified automatically if all tests have passed.
# Issues
Please do not post a "chaiscript is too slow", "chaiscript compiles too slowly", or "chaiscript needs more documentation" issue
without first reading the following notes.
## ChaiScript is Too Slow
We are actively working on constently improving the runtime performance of ChaiScript. With the performance being
[monitored with each commit](http://chaiscript.com/ChaiScript-BuildResults/performance.html).
If you feel you *must* post an issue about performance, please post a complete example that illustrates the exact case you
feel should be better optimized.
Any issue request regarding performance without a complete example of the issue experienced will be closed.
## ChaiScript Compiles Too Slowly
This is also something we are actively working on. If you need highly optimized build times, please see [this discussion
on the discourse site](http://discourse.chaiscript.com/t/slow-build-times/94).
## ChaiScript Needs More Documentation
If you have a question that is not addressed in the [cheatsheet](https://github.com/ChaiScript/ChaiScript/blob/develop/cheatsheet.md)
please open an issue so we can get the Cheatsheet updated.

View File

@ -1,10 +0,0 @@
* Compiler Used:
* Operating System:
* Architecture (ARM/x86/32bit/64bit/etc):
### Expected Behavior
### Actual Behavior
### Minimal Example to Reproduce Behavior

View File

@ -1,8 +0,0 @@
Issue this pull request references: #
Changes proposed in this pull request
-
-
-

View File

@ -1,62 +1,33 @@
language: cpp language: cpp
compiler:
- gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.9
- g++-5
coverity_scan:
project:
name: "ChaiScript/ChaiScript"
description: "Build submitted via Travis CI"
notification_email: jason@emptycrate.com
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
build_command: "cmake --build . -- -j2"
branch_pattern: coverity_scan
matrix:
include:
- os: linux
sudo: false
env: GCC_VER="4.9"
compiler: gcc
- os: linux
sudo: false
env: GCC_VER="4.9" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
compiler: gcc
- os: linux
sudo: false
env: GCC_VER="5" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
compiler: gcc
- os: osx
compiler: clang
osx_image: xcode8
- os: osx
compiler: clang
osx_image: xcode8
env: CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
env: env:
matrix:
- GCC_VER="4.6"
- GCC_VER="4.8"
global: global:
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU= - secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
- secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM=" - secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM="
before_install: before_install:
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi - export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER"
- pip install --user cpp-coveralls - if [ "$GCC_VER" = "4.8" ]; then export COVERAGE=1 CPPCHECK=1; fi
- if [ ${COVERAGE} = 1 ]; then export FUZZY_CMD="-D RUN_FUZZY_TESTS:BOOL=TRUE"; fi
- sudo pip install cpp-coveralls
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
- sudo apt-get update
- sudo apt-get install -qq g++-$GCC_VER
script: script:
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS . - if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $FUZZY_CMD . ; fi
- cmake --build . -- -j2 - if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -j2 ; fi
- if [ "${BUILD_ONLY}" != "1" ]; then ctest; fi - make test
- if [ "${COVERAGE}" = "1" ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi - if [ ${COVERAGE} = 1 ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
#after_script: after_script:
# - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
notifications: notifications:
@ -71,3 +42,15 @@ notifications:
on_success: change # options: [always|never|change] default: always on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always
on_start: false # default: false on_start: false # default: false
addons:
coverity_scan:
project:
name: "ChaiScript/ChaiScript"
description: "Build submitted via Travis CI"
notification_email: jason@emptycrate.com
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
build_command: "cmake --build . -- -j2"
branch_pattern: coverity_scan

View File

@ -14,14 +14,12 @@ ELSE()
project(chaiscript) project(chaiscript)
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE) option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE) option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
option(BUILD_SAMPLES "Build Samples Folder" FALSE) option(BUILD_SAMPLES "Build Samples Folder" FALSE)
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE) option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE) option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
mark_as_advanced(USE_STD_MAKE_SHARED) mark_as_advanced(USE_STD_MAKE_SHARED)
@ -102,9 +100,9 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md") set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 6) set(CPACK_PACKAGE_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 0) set(CPACK_PACKAGE_VERSION_MINOR 7)
set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_VERSION_PATCH 2)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com") set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@ -124,12 +122,16 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest) include(CTest)
include(CPack) include(CPack)
include(cmake/CheckCXX11Features.cmake)
if(NOT MINGW) if(NOT MINGW)
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib) find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
endif() endif()
if (UNIX AND NOT APPLE) if(HAS_CXX11_VARIADIC_TEMPLATES)
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin) message(STATUS "Variadic Template support detected")
else()
message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.")
endif() endif()
enable_testing() enable_testing()
@ -149,24 +151,21 @@ endif()
if(CMAKE_COMPILER_IS_GNUCC) if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_LESS 4.9) if(GCC_VERSION VERSION_LESS 4.8)
set(CPP11_FLAG "-std=c++1y") set(CPP11_FLAG "-std=c++0x")
else() else()
set(CPP11_FLAG "-std=c++14") set(CPP11_FLAG "-std=c++11")
endif() endif()
else() else()
set(CPP11_FLAG "-std=c++14") set(CPP11_FLAG "-std=c++11")
endif() endif()
if(MSVC) if(MSVC)
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928) add_definitions(/W4)
if (MSVC_VERSION STREQUAL "1800")
# VS2013 doesn't have magic statics # VS2013 doesn't have magic statics
if (MSVC_VERSION STREQUAL "1800")
add_definitions(/w44640) add_definitions(/w44640)
else()
# enum warnings are too noisy on MSVC2013
add_definitions(/w34062)
endif() endif()
add_definitions(/bigobj) add_definitions(/bigobj)
@ -179,10 +178,10 @@ if(MSVC)
# how to workaround or fix the error. So I'm disabling it globally. # how to workaround or fix the error. So I'm disabling it globally.
add_definitions(/wd4503) add_definitions(/wd4503)
else() else()
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG}) add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command) add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors)
else() else()
add_definitions(-Wnoexcept) add_definitions(-Wnoexcept)
endif() endif()
@ -214,7 +213,7 @@ endif()
include_directories(include) include_directories(include)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.hpp include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp) set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
@ -222,16 +221,10 @@ if(NOT MULTITHREAD_SUPPORT_ENABLED)
add_definitions(-DCHAISCRIPT_NO_THREADS) add_definitions(-DCHAISCRIPT_NO_THREADS)
endif() endif()
if(NOT DYNLOAD_ENABLED)
add_definitions(-DCHAISCRIPT_NO_DYNLOAD)
endif()
if(CMAKE_HOST_UNIX) if(CMAKE_HOST_UNIX)
if(DYNLOAD_ENABLED)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku") if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
list(APPEND LIBS "dl") list(APPEND LIBS "dl")
endif() endif()
endif()
if(MULTITHREAD_SUPPORT_ENABLED) if(MULTITHREAD_SUPPORT_ENABLED)
if(CMAKE_COMPILER_IS_GNUCC) if(CMAKE_COMPILER_IS_GNUCC)
@ -256,37 +249,31 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
add_library(stdlib STATIC static_libs/chaiscript_stdlib.cpp)
add_library(parser STATIC static_libs/chaiscript_parser.cpp)
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp) add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib.cpp)
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
set(CHAISCRIPT_LIBS stdlib parser)
add_executable(chai src/main.cpp ${Chai_INCLUDES}) add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(chai ${LIBS})
add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
if(BUILD_SAMPLES) if(BUILD_SAMPLES)
add_executable(example samples/example.cpp) add_executable(example samples/example.cpp)
target_link_libraries(example ${LIBS}) target_link_libraries(example ${LIBS})
add_executable(test_num_exceptions samples/test_num_exceptions.cpp) add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(test_num_exceptions ${LIBS})
add_executable(memory_leak_test samples/memory_leak_test.cpp) add_executable(memory_leak_test samples/memory_leak_test.cpp)
target_link_libraries(memory_leak_test ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(memory_leak_test ${LIBS})
add_executable(inheritance samples/inheritance.cpp) add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(inheritance ${LIBS})
add_executable(factory samples/factory.cpp) add_executable(factory samples/factory.cpp)
target_link_libraries(factory ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(factory ${LIBS})
add_executable(fun_call_performance samples/fun_call_performance.cpp) add_executable(fun_call_performance samples/fun_call_performance.cpp)
target_link_libraries(fun_call_performance ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(fun_call_performance ${LIBS})
endif() endif()
if(BUILD_MODULES) if(BUILD_MODULES)
add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${LIBS})
add_library(stl_extra MODULE src/stl_extra.cpp) add_library(stl_extra MODULE src/stl_extra.cpp)
target_link_libraries(stl_extra ${LIBS}) target_link_libraries(stl_extra ${LIBS})
@ -296,16 +283,13 @@ endif()
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai) file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
list(SORT UNIT_TESTS) list(SORT UNIT_TESTS)
file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/*.chai)
list(SORT PERFORMANCE_TESTS)
if (RUN_FUZZY_TESTS) if (RUN_FUZZY_TESTS)
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests") file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
execute_process( execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2016-06-29.tar.bz2 COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2015-07-16.tar.bz2
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
) )
@ -363,8 +347,8 @@ if(BUILD_TESTING)
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents}) string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
foreach(hit ${found_tests}) foreach(hit ${found_tests})
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit}) string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
add_test(compiled.${test_name} "${executable}" ${test_name}) add_test(${test_name} "${executable}" ${test_name})
set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}") set_tests_properties(${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
endforeach() endforeach()
endif() endif()
endif() endif()
@ -398,32 +382,12 @@ if(BUILD_TESTING)
) )
set(TESTS "")
foreach(filename ${UNIT_TESTS}) foreach(filename ${UNIT_TESTS})
message(STATUS "Adding unit test ${filename}") message(STATUS "Adding test ${filename}")
add_test(unit.${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename}) add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
list(APPEND TESTS unit.${filename})
endforeach() endforeach()
if (RUN_PERFORMANCE_TESTS) set_property(TEST ${UNIT_TESTS}
foreach(filename ${PERFORMANCE_TESTS})
message(STATUS "Adding performance test ${filename}")
add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $<TARGET_FILE:chai> ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename})
list(APPEND TESTS performance.${filename})
endforeach()
add_executable(profile_cpp_calls_2 performance_tests/profile_cpp_calls_2.cpp)
target_link_libraries(profile_cpp_calls_2 ${LIBS})
add_test(NAME performance.profile_cpp_calls_2 COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_cpp_calls_2 $<TARGET_FILE:profile_cpp_calls_2>)
add_executable(profile_fun_wrappers performance_tests/profile_fun_wrappers.cpp)
target_link_libraries(profile_fun_wrappers ${LIBS})
add_test(NAME performance.profile_fun_wrappers COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_fun_wrappers $<TARGET_FILE:profile_fun_wrappers>)
endif()
set_property(TEST ${TESTS}
PROPERTY ENVIRONMENT PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/" "CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
@ -431,12 +395,9 @@ if(BUILD_TESTING)
if(NOT UNIT_TEST_LIGHT) if(NOT UNIT_TEST_LIGHT)
add_executable(compiled_tests unittests/compiled_tests.cpp) add_executable(compiled_tests unittests/compiled_tests.cpp)
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(compiled_tests ${LIBS})
ADD_CATCH_TESTS(compiled_tests) ADD_CATCH_TESTS(compiled_tests)
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp)
target_link_libraries(static_chaiscript_test ${LIBS})
add_test(NAME Static_ChaiScript_Test COMMAND static_chaiscript_test)
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp) add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
target_link_libraries(boxed_cast_test ${LIBS}) target_link_libraries(boxed_cast_test ${LIBS})
@ -447,11 +408,11 @@ if(BUILD_TESTING)
add_test(NAME Type_Info_Test COMMAND type_info_test) add_test(NAME Type_Info_Test COMMAND type_info_test)
add_executable(c_linkage_test unittests/c_linkage_test.cpp) add_executable(c_linkage_test unittests/c_linkage_test.cpp)
target_link_libraries(c_linkage_test ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(c_linkage_test ${LIBS})
add_test(NAME C_Linkage_Test COMMAND c_linkage_test) add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
add_executable(integer_literal_test unittests/integer_literal_test.cpp) add_executable(integer_literal_test unittests/integer_literal_test.cpp)
target_link_libraries(integer_literal_test ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(integer_literal_test ${LIBS})
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test) add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
if(MULTITHREAD_SUPPORT_ENABLED) if(MULTITHREAD_SUPPORT_ENABLED)
@ -475,6 +436,9 @@ if(BUILD_TESTING)
target_link_libraries(multifile_test ${LIBS}) target_link_libraries(multifile_test ${LIBS})
add_test(NAME MultiFile_Test COMMAND multifile_test) add_test(NAME MultiFile_Test COMMAND multifile_test)
add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${LIBS})
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript) install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
endif() endif()
endif() endif()

View File

@ -1,28 +0,0 @@
# Introduction
This document outlines the principles that drive the development of ChaiScript. ChaiScript does not intent to be the perfect tool for *every* situation, but it does intend to be a good general purpose tool for *most* situations.
# Goals
1. Trivially easy to integrate with C++ projects
2. 0 external depenencies
3. "Perfect" integration with C++
* Direct mapping between ChaiScript objects and C++ objects
* Direct mapping between ChaiScript functions and C++ functions
* Direct mapping between ChaiScript exceptions and C++ exceptions
3. Never surprise the C++ developer
* Object lifetimes managed by the stack
* Familiar syntax to C++ developers
4. Perform "well enough" to not get in the way
# Alternatives
## Sol2
If you are looking for the fastest performing scripting language and don't mind Lua, you might want to consider [sol2](https://github.com/ThePhD/sol2).
## SWIG
If you are looking for the most flexible solution to be able to support multiple target languages, consider [SWIG](http://swig.org)

View File

@ -1,4 +1,4 @@
Copyright 2009-2016 Jason Turner Copyright 2009-2015 Jason Turner
Copyright 2009-2012 Jonathan Turner. Copyright 2009-2012 Jonathan Turner.
All Rights Reserved. All Rights Reserved.

View File

@ -1,22 +0,0 @@
version: 5.8.x.{build}
os: Visual Studio 2015
environment:
matrix:
- {}
build_script:
- cmd: >-
mkdir build
cd build
cmake c:\Projects\chaiscript -G "Visual Studio 14"
cmake --build . --config Debug
test_script:
- cmd: ctest -C Debug
notifications:
- provider: Webhook
url: https://webhooks.gitter.im/e/9ff725a985b5679d1d5d
on_build_success: true
on_build_failure: true
on_build_status_changed: false

View File

@ -27,13 +27,6 @@ chai.add(chaiscript::fun(&Class::method_name), "method_name");
chai.add(chaiscript::fun(&Class::member_name), "member_name"); chai.add(chaiscript::fun(&Class::member_name), "member_name");
``` ```
### Bound Member Functions
```
chai.add(chaiscript::fun(&Class::method_name, Class_instance_ptr), "method_name");
chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name");
```
### With Overloads ### With Overloads
#### Preferred #### Preferred
@ -91,63 +84,12 @@ chai.add(chaiscript::user_type<MyClass>(), "MyClass");
User defined type conversions are possible, defined in either script or in C++. User defined type conversions are possible, defined in either script or in C++.
### ChaiScript Defined Conversions
Function objects (including lambdas) can be used to add type conversions
from inside of ChaiScript:
```
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
```
### C++ Defined Conversions
Invoking a C++ type conversion possible with `static_cast`
```
chai.add(chaiscript::type_conversion<T, bool>());
```
Calling a user defined type conversion that takes a lambda
```
chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ }));
```
### Class Hierarchies
If you want objects to be convertable between base and derived classes, you must tell ChaiScritp about the relationship.
```
chai.add(chaiscript::base_class<Base, Derived>());
```
If you have multiple classes in your inheritance graph, you will probably want to tell ChaiScript about all relationships.
```
chai.add(chaiscript::base_class<Base, Derived>());
chai.add(chaiscript::base_class<Derived, MoreDerived>());
chai.add(chaiscript::base_class<Base, MoreDerived>());
```
### Helpers
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition: A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
``` ```
chai.add(chaiscript::vector_conversion<std::vector<int>>()); chai.add(chaiscript::vector_conversion<std::vector<int>>());
``` ```
A helper function also exists for strongly typed and ChaiScript `Map` function conversion definition:
```
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
```
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>` This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
## Adding Objects ## Adding Objects
@ -158,11 +100,9 @@ chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared
auto shareddouble = std::make_shared<double>(4.3); auto shareddouble = std::make_shared<double>(4.3);
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const, throws if object exists chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
``` ```
# Using STL # Using STL
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself. ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
@ -215,28 +155,6 @@ chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with an
static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
``` ```
### Conversion Caveats
Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you attempt to keep a reference to a `shared_ptr<>` you might invoke undefined behavior
```cpp
// ok this is supported, you can register it with chaiscript engine
void nullify_shared_ptr(std::shared_ptr<int> &t) {
t = nullptr
}
```
```cpp
int main()
{
// do some stuff and create a chaiscript instance
std::shared_ptr<int> &ptr = chai.eval<std::shared_ptr<int> &>(somevalue);
// DO NOT do this. Taking a non-const reference to a shared_ptr is not
// supported and causes undefined behavior in the chaiscript engine
}
```
## Sharing Values ## Sharing Values
``` ```
@ -303,51 +221,11 @@ var k = 5; // initialized to 5 (integer)
var l := k; // reference to k var l := k; // reference to k
auto &m = k; // reference to k auto &m = k; // reference to k
global g = 5; // creates a global variable. If global already exists, it is not re-added GLOBAL g = 5; // creates a global variable. If global already exists, it is not re-added
global g = 2; // global 'g' now equals 2 GLOBAL g = 2; // global 'g' now equals 2
global g2; GLOBAL g2;
if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hit more than once if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if GLOBAL decl hit more than once
GLOBAL g3; // all upper case version also accepted
```
## Looping
```
// c-style for loops
for (var i = 0; i < 100; ++i) { print(i); }
```
```
// while
while (some_condition()) { /* do something */ }
```
```
// ranged for
for (x : [1,2,3]) { print(i); }
```
Each of the loop styles can be broken using the `break` statement. For example:
```
while (some_condition()) {
/* do something */
if (another_condition()) { break; }
}
```
## Conditionals
```
if (expression) { }
```
```
// C++17-style init-if blocks
// Value of 'statement' is scoped for entire `if` block
if (statement; expression) { }
``` ```
## Built in Types ## Built in Types
@ -508,33 +386,9 @@ the contained function.
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins. If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
## Context
* `__LINE__` Current file line number
* `__FILE__` Full path of current file
* `__CLASS__` Name of current class
* `__FUNC__` Mame of current function
# Built In Functions # Built In Functions
## Disabling Built-Ins
When constructing a ChaiScript object, a vector of parameters can be passed in to disable or enable various built-in methods.
Current options:
```
enum class Options
{
Load_Modules,
No_Load_Modules,
External_Scripts,
No_External_Scripts
};
```
## Evaluation ## Evaluation
``` ```
@ -546,7 +400,4 @@ use("filename") // evals file exactly once and returns value of last statement
Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor
## JSON
* `from_json` converts a JSON string into its strongly typed (map, vector, int, double, string) representations
* `to_json` converts a ChaiScript object (either a `Object` or one of map, vector, int, double, string) tree into its JSON string representation

View File

@ -0,0 +1,103 @@
# Checks for C++11 features
# CXX11_FEATURE_LIST - a list containing all supported features
# HAS_CXX11_AUTO - auto keyword
# HAS_CXX11_NULLPTR - nullptr
# HAS_CXX11_LAMBDA - lambdas
# HAS_CXX11_STATIC_ASSERT - static_assert()
# HAS_CXX11_RVALUE_REFERENCES - rvalue references
# HAS_CXX11_DECLTYPE - decltype keyword
# HAS_CXX11_CSTDINT_H - cstdint header
# HAS_CXX11_LONG_LONG - long long signed & unsigned types
# HAS_CXX11_VARIADIC_TEMPLATES - variadic templates
# HAS_CXX11_CONSTEXPR - constexpr keyword
# HAS_CXX11_SIZEOF_MEMBER - sizeof() non-static members
# HAS_CXX11_FUNC - __func__ preprocessor constant
#
# Original script by Rolf Eike Beer
# Modifications by Andreas Weis
#
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)
SET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
IF(CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_CXX_FLAGS "-std=c++0x")
endif()
MACRO(CXX11_CHECK_FEATURE FEATURE_NAME FEATURE_NUMBER RESULT_VAR)
IF (NOT DEFINED ${RESULT_VAR})
SET(_bindir "${CMAKE_CURRENT_BINARY_DIR}/cxx11/cxx11_${FEATURE_NAME}")
IF (${FEATURE_NUMBER})
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME}-N${FEATURE_NUMBER})
SET(_LOG_NAME "\"${FEATURE_NAME}\" (N${FEATURE_NUMBER})")
ELSE (${FEATURE_NUMBER})
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME})
SET(_LOG_NAME "\"${FEATURE_NAME}\"")
ENDIF (${FEATURE_NUMBER})
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME}")
SET(_SRCFILE "${_SRCFILE_BASE}.cpp")
SET(_SRCFILE_FAIL "${_SRCFILE_BASE}_fail.cpp")
SET(_SRCFILE_FAIL_COMPILE "${_SRCFILE_BASE}_fail_compile.cpp")
IF (CROSS_COMPILING)
try_compile(${RESULT_VAR} "${_bindir}" "${_SRCFILE}")
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
try_compile(${RESULT_VAR} "${_bindir}_fail" "${_SRCFILE_FAIL}")
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
ELSE (CROSS_COMPILING)
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
"${_bindir}" "${_SRCFILE}")
IF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
SET(${RESULT_VAR} TRUE)
ELSE (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
SET(${RESULT_VAR} FALSE)
ENDIF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
"${_bindir}_fail" "${_SRCFILE_FAIL}")
IF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
SET(${RESULT_VAR} TRUE)
ELSE (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
SET(${RESULT_VAR} FALSE)
ENDIF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
ENDIF (CROSS_COMPILING)
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
try_compile(_TMP_RESULT "${_bindir}_fail_compile" "${_SRCFILE_FAIL_COMPILE}")
IF (_TMP_RESULT)
SET(${RESULT_VAR} FALSE)
ELSE (_TMP_RESULT)
SET(${RESULT_VAR} TRUE)
ENDIF (_TMP_RESULT)
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
IF (${RESULT_VAR})
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- works")
LIST(APPEND CXX11_FEATURE_LIST ${RESULT_VAR})
ELSE (${RESULT_VAR})
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- not supported")
ENDIF (${RESULT_VAR})
SET(${RESULT_VAR} ${${RESULT_VAR}} CACHE INTERNAL "C++11 support for ${_LOG_NAME}")
ENDIF (NOT DEFINED ${RESULT_VAR})
ENDMACRO(CXX11_CHECK_FEATURE)
CXX11_CHECK_FEATURE("auto" 2546 HAS_CXX11_AUTO)
CXX11_CHECK_FEATURE("nullptr" 2431 HAS_CXX11_NULLPTR)
CXX11_CHECK_FEATURE("lambda" 2927 HAS_CXX11_LAMBDA)
CXX11_CHECK_FEATURE("static_assert" 1720 HAS_CXX11_STATIC_ASSERT)
CXX11_CHECK_FEATURE("rvalue_references" 2118 HAS_CXX11_RVALUE_REFERENCES)
CXX11_CHECK_FEATURE("decltype" 2343 HAS_CXX11_DECLTYPE)
CXX11_CHECK_FEATURE("cstdint" "" HAS_CXX11_CSTDINT_H)
CXX11_CHECK_FEATURE("long_long" 1811 HAS_CXX11_LONG_LONG)
CXX11_CHECK_FEATURE("variadic_templates" 2555 HAS_CXX11_VARIADIC_TEMPLATES)
CXX11_CHECK_FEATURE("constexpr" 2235 HAS_CXX11_CONSTEXPR)
CXX11_CHECK_FEATURE("sizeof_member" 2253 HAS_CXX11_SIZEOF_MEMBER)
CXX11_CHECK_FEATURE("__func__" 2340 HAS_CXX11_FUNC)
SET(CXX11_FEATURE_LIST ${CXX11_FEATURE_LIST} CACHE STRING "C++11 feature support list")
MARK_AS_ADVANCED(FORCE CXX11_FEATURE_LIST)
SET(CMAKE_CXX_FLAGS ${CHECK_CXX11_OLD_CMAKE_CXX_FLAGS})
UNSET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS)

View File

@ -0,0 +1,8 @@
#include <cstring>
int main()
{
if (!__func__) { return 1; }
if(std::strlen(__func__) <= 0) { return 1; }
return 0;
}

View File

@ -0,0 +1,12 @@
int main()
{
auto i = 5;
auto f = 3.14159f;
auto d = 3.14159;
bool ret = (
(sizeof(f) < sizeof(d)) &&
(sizeof(i) == sizeof(int))
);
return ret ? 0 : 1;
}

View File

@ -0,0 +1,19 @@
constexpr int square(int x)
{
return x*x;
}
constexpr int the_answer()
{
return 42;
}
int main()
{
int test_arr[square(3)];
bool ret = (
(square(the_answer()) == 1764) &&
(sizeof(test_arr)/sizeof(test_arr[0]) == 9)
);
return ret ? 0 : 1;
}

View File

@ -0,0 +1,10 @@
#include <cstdint>
int main()
{
bool test =
(sizeof(int8_t) == 1) &&
(sizeof(int16_t) == 2) &&
(sizeof(int32_t) == 4) &&
(sizeof(int64_t) == 8);
return test ? 0 : 1;
}

View File

@ -0,0 +1,11 @@
bool check_size(int i)
{
return sizeof(int) == sizeof(decltype(i));
}
int main()
{
bool ret = check_size(42);
return ret ? 0 : 1;
}

View File

@ -0,0 +1,5 @@
int main()
{
int ret = 0;
return ([&ret]() -> int { return ret; })();
}

View File

@ -0,0 +1,7 @@
int main(void)
{
long long l;
unsigned long long ul;
return ((sizeof(l) >= 8) && (sizeof(ul) >= 8)) ? 0 : 1;
}

View File

@ -0,0 +1,5 @@
int main()
{
int* test = nullptr;
return test ? 1 : 0;
}

View File

@ -0,0 +1,5 @@
int main()
{
int i = nullptr;
return 1;
}

View File

@ -0,0 +1,15 @@
int foo(int& lvalue)
{
return 123;
}
int foo(int&& rvalue)
{
return 321;
}
int main()
{
int i = 42;
return ((foo(i) == 123) && (foo(42) == 321)) ? 0 : 1;
}

View File

@ -0,0 +1,14 @@
struct foo {
char bar;
int baz;
};
int main(void)
{
bool ret = (
(sizeof(foo::bar) == 1) &&
(sizeof(foo::baz) >= sizeof(foo::bar)) &&
(sizeof(foo) >= sizeof(foo::bar)+sizeof(foo::baz))
);
return ret ? 0 : 1;
}

View File

@ -0,0 +1,5 @@
int main()
{
static_assert(0 < 1, "your ordering of integers is screwed");
return 0;
}

View File

@ -0,0 +1,5 @@
int main()
{
static_assert(1 < 0, "this should fail");
return 0;
}

View File

@ -0,0 +1,23 @@
int Accumulate()
{
return 0;
}
template<typename T, typename... Ts>
int Accumulate(T v, Ts... vs)
{
return v + Accumulate(vs...);
}
template<int... Is>
int CountElements()
{
return sizeof...(Is);
}
int main()
{
int acc = Accumulate(1, 2, 3, 4, -5);
int count = CountElements<1,2,3,4,5>();
return ((acc == 5) && (count == 5)) ? 0 : 1;
}

View File

@ -1,11 +0,0 @@
#!/usr/bin/env ruby
require 'json'
`grep -rPIHn '\t' src/* include/* samples/*`.lines { |line|
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "tab_checker", :message => "Source Code Line Contains Tabs", :messagetype => "warning"}))
end
}

View File

@ -1,11 +0,0 @@
#!/usr/bin/env ruby
require 'json'
`grep -rPIHni 'todo' src/* include/* samples/*`.lines { |line|
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "todo_checker", :message => "todo: #{restofline.strip}", :messagetype => "info"}))
end
}

View File

@ -1,61 +0,0 @@
# My dict
for="for"
while="while"
def="def"
fun="fun"
if="if"
else="else"
and="&&"
or="||"
auto="auto"
var="var"
begin_block="{"
end_block="}"
empty_vec="[]"
string="string"
vector="Vector"
map="Map"
return="return"
break="break"
true="true"
false="false"
class="class"
attr="attr"
var="var"
global="global"
empty_lambda=" fun(){} "
empty_fun=" def empty_fun() {} "
continue="continue"
float=" 1.1f "
double=" 2.2 "
long_double=" 2.2ll "
unsigned=" 3u "
unsigned_long=" 4ul "
unsigned_long_long=" 4ull "
long_long=" 5ll "
attr="attr"
reference_del="auto &"
int8=" int8_t(1) "
int16=" int16_t(2) "
int32=" int32_t(3) "
int64=" int64_t(4) "
uint8=" uint8_t(1) "
uint16=" uint16_t(2) "
uint32=" uint32_t(3) "
uint64=" uint64_t(4) "
int8t="int8_t"
int16t="int16_t"
int32t="int32_t"
int64t="int64_t"
uint8t="uint8_t"
uint16t="uint16_t"
uint32t="uint32_t"
uint64t="uint64_t"

View File

@ -1,17 +0,0 @@
Command line used to find this crash:
../../Downloads/afl-1.80b/afl-fuzz -i- -o findings -x chaiscript.dict -- ../a.out unit_test.inc @@
If you can't reproduce a bug outside of afl-fuzz, be sure to set the same
memory limit. The limit used for this fuzzing session was 50.0 MB.
Need a tool to minimize test cases before investigating the crashes or sending
them to a vendor? Check out the afl-tmin that comes with the fuzzer!
Found any cool bugs in open-source tools using afl-fuzz? If yes, please drop
me a mail at <lcamtuf@coredump.cx> once the issues are fixed - I'd love to
add your finds to the gallery at:
http://lcamtuf.coredump.cx/afl/
Thanks :-)

View File

@ -1,5 +0,0 @@
def greet {
return("hello")
}
fun(){ "world" }

View File

@ -4,7 +4,7 @@ pushd ..
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2 wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2
tar -xvf cppcheck-1.66.tar.bz2 tar -xvf cppcheck-1.66.tar.bz2
cd cppcheck-1.66 cd cppcheck-1.66
make -j2 CXX=g++-4.8 make -j2
popd popd
../cppcheck-1.66/cppcheck --enable=all -I include --inline-suppr --suppress=missingIncludeSystem --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output ../cppcheck-1.66/cppcheck --enable=all -I include --inline-suppr --suppress=missingIncludeSystem --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output
sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output

View File

@ -0,0 +1,93 @@
# [PackageDev] target_format: plist, ext: tmLanguage
---
comment: 'ChaiScript Syntax: version 2.0'
fileTypes: [chai]
firstLineMatch: ^#!/usr/bin/env node
foldingStartMarker: ^.*\bdef\s*(\w+\s*)?\([^\)]*\)(\s*\{[^\}]*)?\s*$
foldingStopMarker: ^\s*\}
keyEquivalent: ^~J
name: ChaiScript
patterns:
- {comment: chaiscript shebang, match: ^#, name: comment.line.chai}
- {match: '\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?))\b', name: constant.numeric.chai}
- begin: ''''
beginCaptures:
'0': {name: punctuation.definition.string.begin.chai}
end: ''''
endCaptures:
'0': {name: punctuation.definition.string.end.chai}
name: string.quoted.single.chai
patterns:
- {match: '\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)', name: constant.character.escape.chai}
- begin: '"'
beginCaptures:
'0': {name: punctuation.definition.string.begin.chai}
end: '"'
endCaptures:
'0': {name: punctuation.definition.string.end.chai}
name: string.quoted.double.chai
patterns:
- {match: '\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)', name: constant.character.escape.chai}
- begin: /\*\*(?!/)
captures:
'0': {name: punctuation.definition.comment.chai}
end: \*/
name: comment.block.documentation.chai
- begin: /\*
captures:
'0': {name: punctuation.definition.comment.chai}
end: \*/
name: comment.block.chai
- captures:
'1': {name: punctuation.definition.comment.chai}
match: (//).*$\n?
name: comment.line.double-slash.chai
- captures:
'0': {name: punctuation.definition.comment.html.chai}
'2': {name: punctuation.definition.comment.html.chai}
match: (<!--|-->)
name: comment.block.html.chai
- {match: \b(boolean|byte|char|class|double|enum|float|fun|def|int|interface|long|short|var|auto|attr)\b,
name: storage.type.chai}
- {match: \b(break|case|catch|continue|default|do|else|finally|else if|for|goto|if|return|switch|throw|try|while)\b,
name: keyword.control.chai}
- {match: \b(delete|in|instanceof|new|typeof|with)\b, name: keyword.operator.chai}
- {match: \btrue\b, name: constant.language.boolean.true.chai}
- {match: \bfalse\b, name: constant.language.boolean.false.chai}
- {match: \bnull\b, name: constant.language.null.chai}
- {match: \b(Anchor|Applet|Area|Array|Boolean|Button|Checkbox|Date|document|event|FileUpload|Form|Frame|Function|Hidden|History|Image|JavaArray|JavaClass|JavaObject|JavaPackage|java|Layer|Link|Location|Math|MimeType|Number|navigator|netscape|Object|Option|Packages|Password|Plugin|Radio|RegExp|Reset|Select|String|Style|Submit|screen|sun|Text|Textarea|window|XMLHttpRequest)\b,
name: support.class.chai}
- {match: '\b(s(h(ift|ow(Mod(elessDialog|alDialog)|Help))|croll(X|By(Pages|Lines)?|Y|To)?|t(op|rike)|i(n|zeToContent|debar|gnText)|ort|u(p|b(str(ing)?)?)|pli(ce|t)|e(nd|t(Re(sizable|questHeader)|M(i(nutes|lliseconds)|onth)|Seconds|Ho(tKeys|urs)|Year|Cursor|Time(out)?|Interval|ZOptions|Date|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(ome|andleEvent)|navigate|c(har(CodeAt|At)|o(s|n(cat|textual|firm)|mpile)|eil|lear(Timeout|Interval)?|a(ptureEvents|ll)|reate(StyleSheet|Popup|EventObject))|t(o(GMTString|S(tring|ource)|U(TCString|pperCase)|Lo(caleString|werCase))|est|a(n|int(Enabled)?))|i(s(NaN|Finite)|ndexOf|talics)|d(isableExternalCapture|ump|etachEvent)|u(n(shift|taint|escape|watch)|pdateCommands)|j(oin|avaEnabled)|p(o(p|w)|ush|lugins.refresh|a(ddings|rse(Int|Float)?)|r(int|ompt|eference))|e(scape|nableExternalCapture|val|lementFromPoint|x(p|ec(Script|Command)?))|valueOf|UTC|queryCommand(State|Indeterm|Enabled|Value)|f(i(nd|le(ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(nt(size|color)|rward)|loor|romCharCode)|watch|l(ink|o(ad|g)|astIndexOf)|a(sin|nchor|cos|t(tachEvent|ob|an(2)?)|pply|lert|b(s|ort))|r(ou(nd|teEvents)|e(size(By|To)|calc|turnValue|place|verse|l(oad|ease(Capture|Events)))|andom)|g(o|et(ResponseHeader|M(i(nutes|lliseconds)|onth)|Se(conds|lection)|Hours|Year|Time(zoneOffset)?|Da(y|te)|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Da(y|te)|FullYear)|FullYear|A(ttention|llResponseHeaders)))|m(in|ove(B(y|elow)|To(Absolute)?|Above)|ergeAttributes|a(tch|rgins|x))|b(toa|ig|o(ld|rderWidths)|link|ack))\b(?=\()',
name: support.function.chai}
- {match: '\b(s(ub(stringData|mit)|plitText|e(t(NamedItem|Attribute(Node)?)|lect))|has(ChildNodes|Feature)|namedItem|c(l(ick|o(se|neNode))|reate(C(omment|DATASection|aption)|T(Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(ntityReference|lement)|Attribute))|tabIndex|i(nsert(Row|Before|Cell|Data)|tem)|open|delete(Row|C(ell|aption)|T(Head|Foot)|Data)|focus|write(ln)?|a(dd|ppend(Child|Data))|re(set|place(Child|Data)|move(NamedItem|Child|Attribute(Node)?)?)|get(NamedItem|Element(sBy(Name|TagName)|ById)|Attribute(Node)?)|blur)\b(?=\()',
name: support.function.dom.chai}
- {match: '(?<=\.)(s(ystemLanguage|cr(ipts|ollbars|een(X|Y|Top|Left))|t(yle(Sheets)?|atus(Text|bar)?)|ibling(Below|Above)|ource|uffixes|e(curity(Policy)?|l(ection|f)))|h(istory|ost(name)?|as(h|Focus))|y|X(MLDocument|SLDocument)|n(ext|ame(space(s|URI)|Prop))|M(IN_VALUE|AX_VALUE)|c(haracterSet|o(n(structor|trollers)|okieEnabled|lorDepth|mp(onents|lete))|urrent|puClass|l(i(p(boardData)?|entInformation)|osed|asses)|alle(e|r)|rypto)|t(o(olbar|p)|ext(Transform|Indent|Decoration|Align)|ags)|SQRT(1_2|2)|i(n(ner(Height|Width)|put)|ds|gnoreCase)|zIndex|o(scpu|n(readystatechange|Line)|uter(Height|Width)|p(sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(i(splay|alog(Height|Top|Width|Left|Arguments)|rectories)|e(scription|fault(Status|Ch(ecked|arset)|View)))|u(ser(Profile|Language|Agent)|n(iqueID|defined)|pdateInterval)|_content|p(ixelDepth|ort|ersonalbar|kcs11|l(ugins|atform)|a(thname|dding(Right|Bottom|Top|Left)|rent(Window|Layer)?|ge(X(Offset)?|Y(Offset)?))|r(o(to(col|type)|duct(Sub)?|mpter)|e(vious|fix)))|e(n(coding|abledPlugin)|x(ternal|pando)|mbeds)|v(isibility|endor(Sub)?|Linkcolor)|URLUnencoded|P(I|OSITIVE_INFINITY)|f(ilename|o(nt(Size|Family|Weight)|rmName)|rame(s|Element)|gColor)|E|whiteSpace|l(i(stStyleType|n(eHeight|kColor))|o(ca(tion(bar)?|lName)|wsrc)|e(ngth|ft(Context)?)|a(st(M(odified|atch)|Index|Paren)|yer(s|X)|nguage))|a(pp(MinorVersion|Name|Co(deName|re)|Version)|vail(Height|Top|Width|Left)|ll|r(ity|guments)|Linkcolor|bove)|r(ight(Context)?|e(sponse(XML|Text)|adyState))|global|x|m(imeTypes|ultiline|enubar|argin(Right|Bottom|Top|Left))|L(N(10|2)|OG(10E|2E))|b(o(ttom|rder(Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(Color|Image)))\b',
name: support.constant.chai}
- {match: '(?<=\.)(s(hape|ystemId|c(heme|ope|rolling)|ta(ndby|rt)|ize|ummary|pecified|e(ctionRowIndex|lected(Index)?)|rc)|h(space|t(tpEquiv|mlFor)|e(ight|aders)|ref(lang)?)|n(o(Resize|tation(s|Name)|Shade|Href|de(Name|Type|Value)|Wrap)|extSibling|ame)|c(h(ildNodes|Off|ecked|arset)?|ite|o(ntent|o(kie|rds)|de(Base|Type)?|l(s|Span|or)|mpact)|ell(s|Spacing|Padding)|l(ear|assName)|aption)|t(ype|Bodies|itle|Head|ext|a(rget|gName)|Foot)|i(sMap|ndex|d|m(plementation|ages))|o(ptions|wnerDocument|bject)|d(i(sabled|r)|o(c(type|umentElement)|main)|e(clare|f(er|ault(Selected|Checked|Value)))|at(eTime|a))|useMap|p(ublicId|arentNode|r(o(file|mpt)|eviousSibling))|e(n(ctype|tities)|vent|lements)|v(space|ersion|alue(Type)?|Link|Align)|URL|f(irstChild|orm(s)?|ace|rame(Border)?)|width|l(ink(s)?|o(ngDesc|wSrc)|a(stChild|ng|bel))|a(nchors|c(ce(ssKey|pt(Charset)?)|tion)|ttributes|pplets|l(t|ign)|r(chive|eas)|xis|Link|bbr)|r(ow(s|Span|Index)|ules|e(v|ferrer|l|adOnly))|m(ultiple|e(thod|dia)|a(rgin(Height|Width)|xLength))|b(o(dy|rder)|ackground|gColor))\b',
name: support.constant.dom.chai}
- {match: \b(ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|NOTATION_NODE|INDEX_SIZE_ERR|DOMSTRING_SIZE_ERR|HIERARCHY_REQUEST_ERR|WRONG_DOCUMENT_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR|NOT_SUPPORTED_ERR|INUSE_ATTRIBUTE_ERR)\b,
name: support.constant.dom.chai}
- {match: '\bon(R(ow(s(inserted|delete)|e(nter|xit))|e(s(ize(start|end)?|et)|adystatechange))|Mouse(o(ut|ver)|down|up|move)|B(efore(cut|deactivate|u(nload|pdate)|p(aste|rint)|editfocus|activate)|lur)|S(croll|top|ubmit|elect(start|ionchange)?)|H(over|elp)|C(hange|ont(extmenu|rolselect)|ut|ellchange|l(ick|ose))|D(eactivate|ata(setc(hanged|omplete)|available)|r(op|ag(start|over|drop|en(ter|d)|leave)?)|blclick)|Unload|P(aste|ropertychange)|Error(update)?|Key(down|up|press)|Focus|Load|A(ctivate|fter(update|print)|bort))\b',
name: support.function.event-handler.chai}
- {match: '!|\$|%|&|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\b(in|instanceof|new|delete|typeof|void)\b',
name: keyword.operator.chai}
- {match: \b(Infinity|NaN|undefined)\b, name: constant.language.chai}
- begin: (?<=[=(:]|^|return|&&|\|\||!)\s*(/)(?![/*+{}?])
beginCaptures:
'1': {name: punctuation.definition.string.begin.chai}
end: (/)[igm]*
endCaptures:
'1': {name: punctuation.definition.string.end.chai}
name: string.regexp.chai
patterns:
- {match: \\., name: constant.character.escape.chai}
- {match: \;, name: punctuation.terminator.statement.chai}
- {match: ',[ |\t]*', name: meta.delimiter.object.comma.chai}
- {match: \., name: meta.delimiter.method.period.chai}
- {match: '\{|\}', name: meta.brace.curly.chai}
- {match: \(|\), name: meta.brace.round.chai}
- {match: '\[|\]', name: meta.brace.square.chai}
scopeName: source.chai
uuid: 93E017CC-6F27-11D9-90EB-000D93589AF6
...

View File

@ -0,0 +1,333 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>comment</key>
<string>ChaiScript Syntax: version 2.0</string>
<key>fileTypes</key>
<array>
<string>chai</string>
</array>
<key>firstLineMatch</key>
<string>^#!/usr/bin/env node</string>
<key>foldingStartMarker</key>
<string>^.*\bdef\s*(\w+\s*)?\([^\)]*\)(\s*\{[^\}]*)?\s*$</string>
<key>foldingStopMarker</key>
<string>^\s*\}</string>
<key>keyEquivalent</key>
<string>^~J</string>
<key>name</key>
<string>ChaiScript</string>
<key>patterns</key>
<array>
<dict>
<key>comment</key>
<string>chaiscript shebang</string>
<key>match</key>
<string>^#</string>
<key>name</key>
<string>comment.line.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?))\b</string>
<key>name</key>
<string>constant.numeric.chai</string>
</dict>
<dict>
<key>begin</key>
<string>'</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.chai</string>
</dict>
</dict>
<key>end</key>
<string>'</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.chai</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.single.chai</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.chai</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>"</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.chai</string>
</dict>
</dict>
<key>end</key>
<string>"</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.chai</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.double.chai</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.chai</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>/\*\*(?!/)</string>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.chai</string>
</dict>
</dict>
<key>end</key>
<string>\*/</string>
<key>name</key>
<string>comment.block.documentation.chai</string>
</dict>
<dict>
<key>begin</key>
<string>/\*</string>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.chai</string>
</dict>
</dict>
<key>end</key>
<string>\*/</string>
<key>name</key>
<string>comment.block.chai</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.chai</string>
</dict>
</dict>
<key>match</key>
<string>(//).*$\n?</string>
<key>name</key>
<string>comment.line.double-slash.chai</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.html.chai</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.html.chai</string>
</dict>
</dict>
<key>match</key>
<string>(&lt;!--|--&gt;)</string>
<key>name</key>
<string>comment.block.html.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(boolean|byte|char|class|double|enum|float|fun|def|int|interface|long|short|var|auto|attr)\b</string>
<key>name</key>
<string>storage.type.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(break|case|catch|continue|default|do|else|finally|else if|for|goto|if|return|switch|throw|try|while)\b</string>
<key>name</key>
<string>keyword.control.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(delete|in|instanceof|new|typeof|with)\b</string>
<key>name</key>
<string>keyword.operator.chai</string>
</dict>
<dict>
<key>match</key>
<string>\btrue\b</string>
<key>name</key>
<string>constant.language.boolean.true.chai</string>
</dict>
<dict>
<key>match</key>
<string>\bfalse\b</string>
<key>name</key>
<string>constant.language.boolean.false.chai</string>
</dict>
<dict>
<key>match</key>
<string>\bnull\b</string>
<key>name</key>
<string>constant.language.null.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(Anchor|Applet|Area|Array|Boolean|Button|Checkbox|Date|document|event|FileUpload|Form|Frame|Function|Hidden|History|Image|JavaArray|JavaClass|JavaObject|JavaPackage|java|Layer|Link|Location|Math|MimeType|Number|navigator|netscape|Object|Option|Packages|Password|Plugin|Radio|RegExp|Reset|Select|String|Style|Submit|screen|sun|Text|Textarea|window|XMLHttpRequest)\b</string>
<key>name</key>
<string>support.class.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(s(h(ift|ow(Mod(elessDialog|alDialog)|Help))|croll(X|By(Pages|Lines)?|Y|To)?|t(op|rike)|i(n|zeToContent|debar|gnText)|ort|u(p|b(str(ing)?)?)|pli(ce|t)|e(nd|t(Re(sizable|questHeader)|M(i(nutes|lliseconds)|onth)|Seconds|Ho(tKeys|urs)|Year|Cursor|Time(out)?|Interval|ZOptions|Date|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(ome|andleEvent)|navigate|c(har(CodeAt|At)|o(s|n(cat|textual|firm)|mpile)|eil|lear(Timeout|Interval)?|a(ptureEvents|ll)|reate(StyleSheet|Popup|EventObject))|t(o(GMTString|S(tring|ource)|U(TCString|pperCase)|Lo(caleString|werCase))|est|a(n|int(Enabled)?))|i(s(NaN|Finite)|ndexOf|talics)|d(isableExternalCapture|ump|etachEvent)|u(n(shift|taint|escape|watch)|pdateCommands)|j(oin|avaEnabled)|p(o(p|w)|ush|lugins.refresh|a(ddings|rse(Int|Float)?)|r(int|ompt|eference))|e(scape|nableExternalCapture|val|lementFromPoint|x(p|ec(Script|Command)?))|valueOf|UTC|queryCommand(State|Indeterm|Enabled|Value)|f(i(nd|le(ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(nt(size|color)|rward)|loor|romCharCode)|watch|l(ink|o(ad|g)|astIndexOf)|a(sin|nchor|cos|t(tachEvent|ob|an(2)?)|pply|lert|b(s|ort))|r(ou(nd|teEvents)|e(size(By|To)|calc|turnValue|place|verse|l(oad|ease(Capture|Events)))|andom)|g(o|et(ResponseHeader|M(i(nutes|lliseconds)|onth)|Se(conds|lection)|Hours|Year|Time(zoneOffset)?|Da(y|te)|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Da(y|te)|FullYear)|FullYear|A(ttention|llResponseHeaders)))|m(in|ove(B(y|elow)|To(Absolute)?|Above)|ergeAttributes|a(tch|rgins|x))|b(toa|ig|o(ld|rderWidths)|link|ack))\b(?=\()</string>
<key>name</key>
<string>support.function.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(s(ub(stringData|mit)|plitText|e(t(NamedItem|Attribute(Node)?)|lect))|has(ChildNodes|Feature)|namedItem|c(l(ick|o(se|neNode))|reate(C(omment|DATASection|aption)|T(Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(ntityReference|lement)|Attribute))|tabIndex|i(nsert(Row|Before|Cell|Data)|tem)|open|delete(Row|C(ell|aption)|T(Head|Foot)|Data)|focus|write(ln)?|a(dd|ppend(Child|Data))|re(set|place(Child|Data)|move(NamedItem|Child|Attribute(Node)?)?)|get(NamedItem|Element(sBy(Name|TagName)|ById)|Attribute(Node)?)|blur)\b(?=\()</string>
<key>name</key>
<string>support.function.dom.chai</string>
</dict>
<dict>
<key>match</key>
<string>(?&lt;=\.)(s(ystemLanguage|cr(ipts|ollbars|een(X|Y|Top|Left))|t(yle(Sheets)?|atus(Text|bar)?)|ibling(Below|Above)|ource|uffixes|e(curity(Policy)?|l(ection|f)))|h(istory|ost(name)?|as(h|Focus))|y|X(MLDocument|SLDocument)|n(ext|ame(space(s|URI)|Prop))|M(IN_VALUE|AX_VALUE)|c(haracterSet|o(n(structor|trollers)|okieEnabled|lorDepth|mp(onents|lete))|urrent|puClass|l(i(p(boardData)?|entInformation)|osed|asses)|alle(e|r)|rypto)|t(o(olbar|p)|ext(Transform|Indent|Decoration|Align)|ags)|SQRT(1_2|2)|i(n(ner(Height|Width)|put)|ds|gnoreCase)|zIndex|o(scpu|n(readystatechange|Line)|uter(Height|Width)|p(sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(i(splay|alog(Height|Top|Width|Left|Arguments)|rectories)|e(scription|fault(Status|Ch(ecked|arset)|View)))|u(ser(Profile|Language|Agent)|n(iqueID|defined)|pdateInterval)|_content|p(ixelDepth|ort|ersonalbar|kcs11|l(ugins|atform)|a(thname|dding(Right|Bottom|Top|Left)|rent(Window|Layer)?|ge(X(Offset)?|Y(Offset)?))|r(o(to(col|type)|duct(Sub)?|mpter)|e(vious|fix)))|e(n(coding|abledPlugin)|x(ternal|pando)|mbeds)|v(isibility|endor(Sub)?|Linkcolor)|URLUnencoded|P(I|OSITIVE_INFINITY)|f(ilename|o(nt(Size|Family|Weight)|rmName)|rame(s|Element)|gColor)|E|whiteSpace|l(i(stStyleType|n(eHeight|kColor))|o(ca(tion(bar)?|lName)|wsrc)|e(ngth|ft(Context)?)|a(st(M(odified|atch)|Index|Paren)|yer(s|X)|nguage))|a(pp(MinorVersion|Name|Co(deName|re)|Version)|vail(Height|Top|Width|Left)|ll|r(ity|guments)|Linkcolor|bove)|r(ight(Context)?|e(sponse(XML|Text)|adyState))|global|x|m(imeTypes|ultiline|enubar|argin(Right|Bottom|Top|Left))|L(N(10|2)|OG(10E|2E))|b(o(ttom|rder(Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(Color|Image)))\b</string>
<key>name</key>
<string>support.constant.chai</string>
</dict>
<dict>
<key>match</key>
<string>(?&lt;=\.)(s(hape|ystemId|c(heme|ope|rolling)|ta(ndby|rt)|ize|ummary|pecified|e(ctionRowIndex|lected(Index)?)|rc)|h(space|t(tpEquiv|mlFor)|e(ight|aders)|ref(lang)?)|n(o(Resize|tation(s|Name)|Shade|Href|de(Name|Type|Value)|Wrap)|extSibling|ame)|c(h(ildNodes|Off|ecked|arset)?|ite|o(ntent|o(kie|rds)|de(Base|Type)?|l(s|Span|or)|mpact)|ell(s|Spacing|Padding)|l(ear|assName)|aption)|t(ype|Bodies|itle|Head|ext|a(rget|gName)|Foot)|i(sMap|ndex|d|m(plementation|ages))|o(ptions|wnerDocument|bject)|d(i(sabled|r)|o(c(type|umentElement)|main)|e(clare|f(er|ault(Selected|Checked|Value)))|at(eTime|a))|useMap|p(ublicId|arentNode|r(o(file|mpt)|eviousSibling))|e(n(ctype|tities)|vent|lements)|v(space|ersion|alue(Type)?|Link|Align)|URL|f(irstChild|orm(s)?|ace|rame(Border)?)|width|l(ink(s)?|o(ngDesc|wSrc)|a(stChild|ng|bel))|a(nchors|c(ce(ssKey|pt(Charset)?)|tion)|ttributes|pplets|l(t|ign)|r(chive|eas)|xis|Link|bbr)|r(ow(s|Span|Index)|ules|e(v|ferrer|l|adOnly))|m(ultiple|e(thod|dia)|a(rgin(Height|Width)|xLength))|b(o(dy|rder)|ackground|gColor))\b</string>
<key>name</key>
<string>support.constant.dom.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|NOTATION_NODE|INDEX_SIZE_ERR|DOMSTRING_SIZE_ERR|HIERARCHY_REQUEST_ERR|WRONG_DOCUMENT_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR|NOT_SUPPORTED_ERR|INUSE_ATTRIBUTE_ERR)\b</string>
<key>name</key>
<string>support.constant.dom.chai</string>
</dict>
<dict>
<key>match</key>
<string>\bon(R(ow(s(inserted|delete)|e(nter|xit))|e(s(ize(start|end)?|et)|adystatechange))|Mouse(o(ut|ver)|down|up|move)|B(efore(cut|deactivate|u(nload|pdate)|p(aste|rint)|editfocus|activate)|lur)|S(croll|top|ubmit|elect(start|ionchange)?)|H(over|elp)|C(hange|ont(extmenu|rolselect)|ut|ellchange|l(ick|ose))|D(eactivate|ata(setc(hanged|omplete)|available)|r(op|ag(start|over|drop|en(ter|d)|leave)?)|blclick)|Unload|P(aste|ropertychange)|Error(update)?|Key(down|up|press)|Focus|Load|A(ctivate|fter(update|print)|bort))\b</string>
<key>name</key>
<string>support.function.event-handler.chai</string>
</dict>
<dict>
<key>match</key>
<string>!|\$|%|&amp;|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\|\||\?\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\b(in|instanceof|new|delete|typeof|void)\b</string>
<key>name</key>
<string>keyword.operator.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(Infinity|NaN|undefined)\b</string>
<key>name</key>
<string>constant.language.chai</string>
</dict>
<dict>
<key>begin</key>
<string>(?&lt;=[=(:]|^|return|&amp;&amp;|\|\||!)\s*(/)(?![/*+{}?])</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.chai</string>
</dict>
</dict>
<key>end</key>
<string>(/)[igm]*</string>
<key>endCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.chai</string>
</dict>
</dict>
<key>name</key>
<string>string.regexp.chai</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\.</string>
<key>name</key>
<string>constant.character.escape.chai</string>
</dict>
</array>
</dict>
<dict>
<key>match</key>
<string>\;</string>
<key>name</key>
<string>punctuation.terminator.statement.chai</string>
</dict>
<dict>
<key>match</key>
<string>,[ |\t]*</string>
<key>name</key>
<string>meta.delimiter.object.comma.chai</string>
</dict>
<dict>
<key>match</key>
<string>\.</string>
<key>name</key>
<string>meta.delimiter.method.period.chai</string>
</dict>
<dict>
<key>match</key>
<string>\{|\}</string>
<key>name</key>
<string>meta.brace.curly.chai</string>
</dict>
<dict>
<key>match</key>
<string>\(|\)</string>
<key>name</key>
<string>meta.brace.round.chai</string>
</dict>
<dict>
<key>match</key>
<string>\[|\]</string>
<key>name</key>
<string>meta.brace.square.chai</string>
</dict>
</array>
<key>scopeName</key>
<string>source.chai</string>
<key>uuid</key>
<string>93E017CC-6F27-11D9-90EB-000D93589AF6</string>
</dict>
</plist>

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HPP_ #ifndef CHAISCRIPT_HPP_
#define CHAISCRIPT_HPP_ #define CHAISCRIPT_HPP_
@ -69,7 +65,7 @@
/// int main() /// int main()
/// { /// {
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::fun(&function), "function"); /// chai.add(&function, "function");
/// ///
/// double d = chai.eval<double>("function(3, 4.75);"); /// double d = chai.eval<double>("function(3, 4.75);");
/// } /// }
@ -699,10 +695,11 @@
/// Begins a function or method definition /// Begins a function or method definition
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
/// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block /// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block /// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// annotation: meta-annotation on function, currently used as documentation. Optional.
/// identifier: name of function. Required. /// identifier: name of function. Required.
/// args: comma-delimited list of parameter names with optional type specifiers. Optional. /// args: comma-delimited list of parameter names with optional type specifiers. Optional.
/// guards: guarding statement that act as a prerequisite for the function. Optional. /// guards: guarding statement that act as a prerequisite for the function. Optional.
@ -820,26 +817,16 @@
/// @namespace chaiscript::detail /// @namespace chaiscript::detail
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported. /// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
#include "chaiscript_basic.hpp" #include "chaiscript_defines.hpp"
#include "language/chaiscript_parser.hpp"
#include "chaiscript_stdlib.hpp" #include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
namespace chaiscript
{
class ChaiScript : public ChaiScript_Basic
{
public:
ChaiScript(std::vector<std::string> t_modulepaths = {},
std::vector<std::string> t_usepaths = {},
const std::vector<Options> &t_opts = {})
: ChaiScript_Basic(
chaiscript::Std_Lib::library(),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
t_modulepaths, t_usepaths, t_opts)
{
}
};
}
#endif /* CHAISCRIPT_HPP_ */ #endif /* CHAISCRIPT_HPP_ */

View File

@ -1,39 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BASIC_HPP_
#define CHAISCRIPT_BASIC_HPP_
#include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
// This file includes all of the basic requirements for ChaiScript,
// to use, you might do something like:
//
/*
#include "chaiscript_stdlib.hpp"
#include "language/chaiscript_parser.hpp"
ChaiScript_Basic chai(
chaiscript::Std_Lib::library(),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>());
*/
// If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp
#endif /* CHAISCRIPT_BASIC_HPP_ */

View File

@ -1,23 +1,22 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_ #ifndef CHAISCRIPT_DEFINES_HPP_
#define CHAISCRIPT_DEFINES_HPP_ #define CHAISCRIPT_DEFINES_HPP_
#ifdef _MSC_VER #ifdef _MSC_VER
#define CHAISCRIPT_STRINGIZE(x) "" #x
#define CHAISCRIPT_STRINGIZE_EXPANDED(x) CHAISCRIPT_STRINGIZE(x)
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE_EXPANDED(_MSC_FULL_VER)
#define CHAISCRIPT_MSVC _MSC_VER #define CHAISCRIPT_MSVC _MSC_VER
#define CHAISCRIPT_HAS_DECLSPEC #define CHAISCRIPT_HAS_DECLSPEC
#if _MSC_VER <= 1800
#define CHAISCRIPT_MSVC_12
#endif
#endif
static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required"); #ifndef CHAISCRIPT_MSVC_12
#define CHAISCRIPT_HAS_MAGIC_STATICS
#else
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
#endif #endif
#include <vector> #include <vector>
@ -30,29 +29,27 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_WINDOWS #define CHAISCRIPT_WINDOWS
#endif #endif
#if defined(_WIN32) #if ( ( (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) ) && !defined(WIN32)) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP))
#if defined(__llvm__) /// Currently only g++>=4.8 supports this natively
#define CHAISCRIPT_COMPILER_NAME "clang(windows)" /// MinGW pretends to, but causes a crash on exit when thread_local objects are destructed
#elif defined(__GNUC__) /// \todo Make this support other compilers when possible
#define CHAISCRIPT_COMPILER_NAME "gcc(mingw)" #define CHAISCRIPT_HAS_THREAD_LOCAL
#else
#define CHAISCRIPT_COMPILER_NAME "msvc"
#endif
#else
#if defined(__llvm__)
#define CHAISCRIPT_COMPILER_NAME "clang"
#elif defined(__GNUC__)
#define CHAISCRIPT_COMPILER_NAME "gcc"
#else
#define CHAISCRIPT_COMPILER_NAME "unknown"
#endif
#endif #endif
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 6)
#define CHAISCRIPT_GCC_4_6
#endif
#if defined(__llvm__) #if defined(__llvm__)
#define CHAISCRIPT_CLANG #define CHAISCRIPT_CLANG
#endif #endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_CLANG)
#define CHAISCRIPT_OVERRIDE override
#else
#define CHAISCRIPT_OVERRIDE
#endif
#ifdef CHAISCRIPT_HAS_DECLSPEC #ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport) #define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
@ -60,28 +57,20 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_MODULE_EXPORT extern "C" #define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif #endif
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG) #ifdef CHAISCRIPT_MSVC_12
#define CHAISCRIPT_UTF16_UTF32 #define CHAISCRIPT_NOEXCEPT throw()
#endif #define CHAISCRIPT_CONSTEXPR
#ifdef _DEBUG
#define CHAISCRIPT_DEBUG true
#else #else
#define CHAISCRIPT_DEBUG false #define CHAISCRIPT_NOEXCEPT noexcept
#define CHAISCRIPT_CONSTEXPR constexpr
#endif #endif
#include <memory> #include <memory>
#include <string>
#include <cmath>
namespace chaiscript { namespace chaiscript {
static const int version_major = 6; static const int version_major = 5;
static const int version_minor = 0; static const int version_minor = 7;
static const int version_patch = 0; static const int version_patch = 2;
static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
static const bool debug_build = CHAISCRIPT_DEBUG;
template<typename B, typename D, typename ...Arg> template<typename B, typename D, typename ...Arg>
inline std::shared_ptr<B> make_shared(Arg && ... arg) inline std::shared_ptr<B> make_shared(Arg && ... arg)
@ -93,135 +82,6 @@ namespace chaiscript {
#endif #endif
} }
struct Build_Info {
static int version_major()
{
return chaiscript::version_major;
}
static int version_minor()
{
return chaiscript::version_minor;
}
static int version_patch()
{
return chaiscript::version_patch;
}
static std::string version()
{
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
}
static std::string compiler_id()
{
return compiler_name() + '-' + compiler_version();
}
static std::string build_id()
{
return compiler_id() + (debug_build()?"-Debug":"-Release");
}
static std::string compiler_version()
{
return chaiscript::compiler_version;
}
static std::string compiler_name()
{
return chaiscript::compiler_name;
}
static bool debug_build()
{
return chaiscript::debug_build;
}
};
template<typename T>
auto parse_num(const char *t_str) -> typename std::enable_if<std::is_integral<T>::value, T>::type
{
T t = 0;
for (char c = *t_str; (c = *t_str) != 0; ++t_str) {
if (c < '0' || c > '9') {
return t;
}
t *= 10;
t += c - '0';
}
return t;
}
template<typename T>
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
{
T t = 0;
T base = 0;
T decimal_place = 0;
bool exponent = false;
bool neg_exponent = false;
const auto final_value = [](const T val, const T baseval, const bool hasexp, const bool negexp) -> T {
if (!hasexp) {
return val;
} else {
return baseval * std::pow(T(10), val*T(negexp?-1:1));
}
};
for(; *t_str != '\0'; ++t_str) {
char c = *t_str;
if (c == '.') {
decimal_place = 10;
} else if (c == 'e' || c == 'E') {
exponent = true;
decimal_place = 0;
base = t;
t = 0;
} else if (c == '-' && exponent) {
neg_exponent = true;
} else if (c == '+' && exponent) {
neg_exponent = false;
} else if (c < '0' || c > '9') {
return final_value(t, base, exponent, neg_exponent);
} else if (decimal_place < T(10)) {
t *= T(10);
t += T(c - '0');
} else {
t += (T(c - '0') / (T(decimal_place)));
decimal_place *= 10;
}
}
return final_value(t, base, exponent, neg_exponent);
}
template<typename T>
T parse_num(const std::string &t_str)
{
return parse_num<T>(t_str.c_str());
}
enum class Options
{
No_Load_Modules,
Load_Modules,
No_External_Scripts,
External_Scripts
};
static inline std::vector<Options> default_options()
{
#ifdef CHAISCRIPT_NO_DYNLOAD
return {Options::No_Load_Modules, Options::External_Scripts};
#else
return {Options::Load_Modules, Options::External_Scripts};
#endif
}
} }
#endif #endif

View File

@ -14,17 +14,11 @@
#include <vector> #include <vector>
#include "chaiscript_defines.hpp" #include "chaiscript_defines.hpp"
#include "language/chaiscript_common.hpp" #include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
//#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/operators.hpp"
#include "dispatchkit/bootstrap.hpp" #include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/bootstrap_stl.hpp"
//#include "dispatchkit/boxed_value.hpp" #include "dispatchkit/boxed_value.hpp"
#include "language/chaiscript_prelude.hpp" #include "language/chaiscript_prelude.chai"
#include "dispatchkit/register_function.hpp"
#include "utility/json_wrap.hpp" #include "utility/json_wrap.hpp"
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
@ -44,20 +38,21 @@ namespace chaiscript
static ModulePtr library() static ModulePtr library()
{ {
auto lib = std::make_shared<Module>(); using namespace bootstrap;
bootstrap::Bootstrap::bootstrap(*lib);
bootstrap::standard_library::vector_type<std::vector<Boxed_Value> >("Vector", *lib); ModulePtr lib = Bootstrap::bootstrap();
bootstrap::standard_library::string_type<std::string>("string", *lib);
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value> >("Map", *lib); lib->add(standard_library::vector_type<std::vector<Boxed_Value> >("Vector"));
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair", *lib); lib->add(standard_library::string_type<std::string>("string"));
lib->add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
lib->add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib); lib->add(standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future"));
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async"); lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
#endif #endif
json_wrap::library(*lib); lib->add(json_wrap::library());
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ ); lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_THREADING_HPP_ #ifndef CHAISCRIPT_THREADING_HPP_
#define CHAISCRIPT_THREADING_HPP_ #define CHAISCRIPT_THREADING_HPP_
@ -46,92 +42,147 @@ namespace chaiscript
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
template<typename T> template<typename T>
using unique_lock = std::unique_lock<T>; class unique_lock : public std::unique_lock<T>
{
public:
unique_lock(T &t) : std::unique_lock<T>(t) {}
};
template<typename T> template<typename T>
using shared_lock = std::unique_lock<T>; class shared_lock : public std::unique_lock<T>
{
public:
shared_lock(T &t) : std::unique_lock<T>(t) {}
void unlock() {}
};
template<typename T> template<typename T>
using lock_guard = std::lock_guard<T>; class lock_guard : public std::lock_guard<T>
{
public:
lock_guard(T &t) : std::lock_guard<T>(t) {}
};
class shared_mutex : public std::mutex { };
using shared_mutex = std::mutex;
using std::mutex; using std::mutex;
using std::recursive_mutex; using std::recursive_mutex;
#ifdef CHAISCRIPT_HAS_THREAD_LOCAL
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If /// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from. /// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
template<typename T> template<typename T>
class Thread_Storage class Thread_Storage
{ {
public: public:
Thread_Storage() = default;
Thread_Storage(const Thread_Storage &) = delete; Thread_Storage(void *t_key)
Thread_Storage(Thread_Storage &&) = delete; : m_key(t_key)
Thread_Storage &operator=(const Thread_Storage &) = delete; {
Thread_Storage &operator=(Thread_Storage &&) = delete; }
~Thread_Storage() ~Thread_Storage()
{ {
if (!destroyed) { t().erase(m_key);
t().erase(this);
}
} }
inline const T *operator->() const inline const T *operator->() const
{ {
return &(t()[const_cast<Thread_Storage *>(this)]); return &(t()[m_key]);
} }
inline const T &operator*() const inline const T &operator*() const
{ {
return t()[const_cast<Thread_Storage *>(this)]; return t()[m_key];
} }
inline T *operator->() inline T *operator->()
{ {
return &(t()[this]); return &(t()[m_key]);
} }
inline T &operator*() inline T &operator*()
{ {
return t()[this]; return t()[m_key];
} }
void *m_key;
private: private:
struct Map_Holder { static std::unordered_map<void*, T> &t()
std::unordered_map<Thread_Storage<T> *, T> map; {
thread_local static std::unordered_map<void *, T> my_t;
Map_Holder() = default; return my_t;
Map_Holder(const Map_Holder &) = delete; }
Map_Holder(Map_Holder &&) = delete; };
Map_Holder& operator=(Map_Holder &&) = delete;
Map_Holder& operator=(const Map_Holder &&) = delete; #else
~Map_Holder() {
// here is the theory: /// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
// * If the Map_Holder is destroyed before the Thread_Storage, a flag will get set /// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
// * If destroyed after the Thread_Storage, the * will have been removed from `map` and nothing will happen ///
for(auto &elem : map) { elem.first->destroyed = true; } /// This version is used if the compiler does not support thread_local
} template<typename T>
}; class Thread_Storage
{
static std::unordered_map<Thread_Storage<T> *, T> &t() public:
Thread_Storage(void *)
{ {
thread_local Map_Holder my_map;
return my_map.map;
} }
bool destroyed{false}; inline const T *operator->() const
{
return get_tls().get();
}
inline const T &operator*() const
{
return *get_tls();
}
inline T *operator->()
{
return get_tls().get();
}
inline T &operator*()
{
return *get_tls();
}
private:
/// \todo this leaks thread instances. It needs to be culled from time to time
std::shared_ptr<T> get_tls() const
{
unique_lock<mutex> lock(m_mutex);
auto itr = m_instances.find(std::this_thread::get_id());
if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(std::make_shared<T>());
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
return new_instance;
}
mutable mutex m_mutex;
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
}; };
#endif // threading enabled but no tls
#else // threading disabled #else // threading disabled
template<typename T> template<typename T>
class unique_lock class unique_lock
{ {
public: public:
explicit unique_lock(T &) {} unique_lock(T &) {}
void lock() {} void lock() {}
void unlock() {} void unlock() {}
}; };
@ -140,7 +191,7 @@ namespace chaiscript
class shared_lock class shared_lock
{ {
public: public:
explicit shared_lock(T &) {} shared_lock(T &) {}
void lock() {} void lock() {}
void unlock() {} void unlock() {}
}; };
@ -149,7 +200,7 @@ namespace chaiscript
class lock_guard class lock_guard
{ {
public: public:
explicit lock_guard(T &) {} lock_guard(T &) {}
}; };
class shared_mutex { }; class shared_mutex { };
@ -161,7 +212,7 @@ namespace chaiscript
class Thread_Storage class Thread_Storage
{ {
public: public:
explicit Thread_Storage(void *) Thread_Storage(void *)
{ {
} }

View File

@ -21,20 +21,23 @@ namespace chaiscript {
class bad_any_cast : public std::bad_cast class bad_any_cast : public std::bad_cast
{ {
public: public:
bad_any_cast() = default; bad_any_cast() CHAISCRIPT_NOEXCEPT
: m_what("bad any cast")
{
}
bad_any_cast(const bad_any_cast &) = default; bad_any_cast(const bad_any_cast &) = default;
~bad_any_cast() noexcept override = default; virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occurred /// \brief Description of what error occurred
const char * what() const noexcept override virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{ {
return m_what.c_str(); return m_what.c_str();
} }
private: private:
std::string m_what = "bad any cast"; std::string m_what;
}; };
} }
@ -43,17 +46,16 @@ namespace chaiscript {
private: private:
struct Data struct Data
{ {
explicit Data(const std::type_info &t_type) Data(const std::type_info &t_type)
: m_type(t_type) : m_type(t_type)
{ {
} }
Data &operator=(const Data &) = delete; Data &operator=(const Data &) = delete;
virtual ~Data() = default; virtual ~Data() {}
virtual void *data() = 0; virtual void *data() = 0;
const std::type_info &type() const const std::type_info &type() const
{ {
return m_type; return m_type;
@ -72,12 +74,14 @@ namespace chaiscript {
{ {
} }
void *data() override virtual ~Data_Impl() {}
virtual void *data() CHAISCRIPT_OVERRIDE
{ {
return &m_data; return &m_data;
} }
std::unique_ptr<Data> clone() const override std::unique_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
{ {
return std::unique_ptr<Data>(new Data_Impl<T>(m_data)); return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
} }
@ -92,8 +96,6 @@ namespace chaiscript {
public: public:
// construct/copy/destruct // construct/copy/destruct
Any() = default; Any() = default;
Any(Any &&) = default;
Any &operator=(Any &&t_any) = default;
Any(const Any &t_any) Any(const Any &t_any)
{ {
@ -105,6 +107,10 @@ namespace chaiscript {
} }
} }
#if !defined(_MSC_VER) || _MSC_VER != 1800
Any(Any &&) = default;
Any &operator=(Any &&t_any) = default;
#endif
template<typename ValueType, template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type> typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
@ -133,6 +139,10 @@ namespace chaiscript {
} }
~Any()
{
}
// modifiers // modifiers
Any & swap(Any &t_other) Any & swap(Any &t_other)
{ {
@ -148,7 +158,8 @@ namespace chaiscript {
const std::type_info & type() const const std::type_info & type() const
{ {
if (m_data) { if (m_data)
{
return m_data->type(); return m_data->type();
} else { } else {
return typeid(void); return typeid(void);

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_ #define CHAISCRIPT_BAD_BOXED_CAST_HPP_
@ -34,32 +30,32 @@ namespace chaiscript
{ {
public: public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
std::string t_what) noexcept std::string t_what) CHAISCRIPT_NOEXCEPT
: from(t_from), to(&t_to), m_what(std::move(t_what)) : from(std::move(t_from)), to(&t_to), m_what(std::move(t_what))
{ {
} }
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name()) : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
{ {
} }
explicit bad_boxed_cast(std::string t_what) noexcept bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT
: m_what(std::move(t_what)) : to(nullptr), m_what(std::move(t_what))
{ {
} }
bad_boxed_cast(const bad_boxed_cast &) = default; bad_boxed_cast(const bad_boxed_cast &) = default;
~bad_boxed_cast() noexcept override = default; virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occurred /// \brief Description of what error occurred
const char * what() const noexcept override virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{ {
return m_what.c_str(); return m_what.c_str();
} }
Type_Info from; ///< Type_Info contained in the Boxed_Value Type_Info from; ///< Type_Info contained in the Boxed_Value
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type const std::type_info *to; ///< std::type_info of the desired (but failed) result type
private: private:
std::string m_what; std::string m_what;

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BIND_FIRST_HPP_ #ifndef CHAISCRIPT_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_ #define CHAISCRIPT_BIND_FIRST_HPP_
@ -31,52 +27,45 @@ namespace chaiscript
} }
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(Ret (*f)(P1, Param...), O&& o) std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
{ {
return [f, o](Param...param) -> Ret { return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return f(std::forward<O>(o), std::forward<Param>(param)...); return f(std::forward<O>(o), std::forward<Param>(param)...);
}; }
);
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(Ret (Class::*f)(Param...), O&& o) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
{ {
return [f, o](Param...param) -> Ret { return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...); return (get_pointer(o)->*f)(std::forward<Param>(param)...);
}; }
);
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(Ret (Class::*f)(Param...) const, O&& o) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
{ {
return [f, o](Param...param) -> Ret { return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...); return (get_pointer(o)->*f)(std::forward<Param>(param)...);
}; }
);
} }
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o) std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
{ {
return [f, o](Param...param) -> Ret { return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return f(o, std::forward<Param>(param)...); return f(o, std::forward<Param>(param)...);
}; });
} }
template<typename F, typename O, typename Ret, typename Class, typename P1, typename ... Param>
auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const)
{
return [fo, o, f](Param ...param) -> Ret {
return (fo.*f)(o, std::forward<Param>(param)...);
};
}
template<typename F, typename O>
auto bind_first(const F &f, O&& o)
{
return bind_first(f, std::forward<O>(o), &F::operator());
}
} }
} }

View File

@ -1,31 +1,63 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_ #ifndef CHAISCRIPT_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_ #define CHAISCRIPT_BOOTSTRAP_HPP_
#include "../utility/utility.hpp" #include <cstdint>
#include <exception>
#include <functional>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>
#include <iterator>
#include "bad_boxed_cast.hpp"
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "dispatchkit.hpp"
#include "type_conversions.hpp"
#include "dynamic_object.hpp"
#include "operators.hpp"
#include "proxy_constructors.hpp"
#include "proxy_functions.hpp"
#include "proxy_functions_detail.hpp"
#include "register_function.hpp" #include "register_function.hpp"
#include "type_info.hpp"
#include "../utility/utility.hpp"
#include "../language/chaiscript_common.hpp"
namespace chaiscript namespace chaiscript
{ {
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types /// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
namespace bootstrap namespace bootstrap
{ {
namespace detail
{
/// \brief Constructs a new POD value object from a Boxed_Number
/// \param[in] v Boxed_Number to copy into the new object
/// \returns The newly created object.
template<typename P1>
std::shared_ptr<P1> construct_pod(const Boxed_Number &v)
{
return std::make_shared<P1>(v.get_as<P1>());
}
}
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type > template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
void array(const std::string &type, Module& m) ModulePtr array(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
typedef typename std::remove_extent<T>::type ReturnType; typedef typename std::remove_extent<T>::type ReturnType;
const auto extent = std::extent<T>::value; const auto extent = std::extent<T>::value;
m.add(user_type<T>(), type); m->add(user_type<T>(), type);
m.add(fun( m->add(fun(
[extent](T& t, size_t index)->ReturnType &{ [extent](T& t, size_t index)->ReturnType &{
if (extent > 0 && index >= extent) { if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
@ -36,7 +68,7 @@ namespace chaiscript
), "[]" ), "[]"
); );
m.add(fun( m->add(fun(
[extent](const T &t, size_t index)->const ReturnType &{ [extent](const T &t, size_t index)->const ReturnType &{
if (extent > 0 && index >= extent) { if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
@ -47,29 +79,33 @@ namespace chaiscript
), "[]" ), "[]"
); );
m.add(fun( m->add(fun(
[extent](const T &) { [extent](const T &) {
return extent; return extent;
}), "size"); }), "size");
return m;
} }
/// \brief Adds a copy constructor for the given type to the given Model /// \brief Adds a copy constructor for the given type to the given Model
/// \param[in] type The name of the type. The copy constructor will be named "type". /// \param[in] type The name of the type. The copy constructor will be named "type".
/// \param[in,out] m The Module to add the copy constructor to /// \param[in,out] m The Module to add the copy constructor to
/// \tparam T The type to add a copy constructor for /// \tparam T The type to add a copy constructor for
/// \returns The passed in Module /// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
template<typename T> template<typename T>
void copy_constructor(const std::string &type, Module& m) ModulePtr copy_constructor(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(constructor<T (const T &)>(), type); m->add(constructor<T (const T &)>(), type);
return m;
} }
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users. /// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
/// \tparam T Type to create comparison operators for /// \tparam T Type to create comparison operators for
/// \param[in,out] m module to add comparison operators to /// \param[in,out] m module to add comparison operators to
/// \returns the passed in Module. /// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
template<typename T> template<typename T>
void opers_comparison(Module& m) ModulePtr opers_comparison(ModulePtr m = std::make_shared<Module>())
{ {
operators::equal<T>(m); operators::equal<T>(m);
operators::greater_than<T>(m); operators::greater_than<T>(m);
@ -77,6 +113,7 @@ namespace chaiscript
operators::less_than<T>(m); operators::less_than<T>(m);
operators::less_than_equal<T>(m); operators::less_than_equal<T>(m);
operators::not_equal<T>(m); operators::not_equal<T>(m);
return m;
} }
@ -85,14 +122,15 @@ namespace chaiscript
/// \param[in] type The name of the type to add the constructors for. /// \param[in] type The name of the type to add the constructors for.
/// \param[in,out] m The Module to add the basic constructors to /// \param[in,out] m The Module to add the basic constructors to
/// \tparam T Type to generate basic constructors for /// \tparam T Type to generate basic constructors for
/// \returns The passed in Module /// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
/// \sa copy_constructor /// \sa copy_constructor
/// \sa constructor /// \sa constructor
template<typename T> template<typename T>
void basic_constructors(const std::string &type, Module& m) ModulePtr basic_constructors(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(constructor<T ()>(), type); m->add(constructor<T ()>(), type);
copy_constructor<T>(type, m); copy_constructor<T>(type, m);
return m;
} }
/// \brief Adds a constructor for a POD type /// \brief Adds a constructor for a POD type
@ -100,12 +138,22 @@ namespace chaiscript
/// \param[in] type The name of the type /// \param[in] type The name of the type
/// \param[in,out] m The Module to add the constructor to /// \param[in,out] m The Module to add the constructor to
template<typename T> template<typename T>
void construct_pod(const std::string &type, Module& m) ModulePtr construct_pod(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(fun([](const Boxed_Number &bn){ return bn.get_as<T>(); }), type); m->add(fun(&detail::construct_pod<T>), type);
return m;
} }
/// to_string function for internal use. Uses ostream operator<<
template<typename Input>
std::string to_string(Input i)
{
std::stringstream ss;
ss << i;
return ss.str();
}
/// Internal function for converting from a string to a value /// Internal function for converting from a string to a value
/// uses ostream operator >> to perform the conversion /// uses ostream operator >> to perform the conversion
template<typename Input> template<typename Input>
@ -137,13 +185,14 @@ namespace chaiscript
/// Add all common functions for a POD type. All operators, and /// Add all common functions for a POD type. All operators, and
/// common conversions /// common conversions
template<typename T> template<typename T>
void bootstrap_pod_type(const std::string &name, Module& m) ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = std::make_shared<Module>())
{ {
m.add(user_type<T>(), name); m->add(user_type<T>(), name);
m.add(constructor<T()>(), name); m->add(constructor<T()>(), name);
construct_pod<T>(name, m); construct_pod<T>(name, m);
m.add(fun(&parse_string<T>), "to_" + name); m->add(fun(&parse_string<T>), "to_" + name);
return m;
} }
@ -153,14 +202,15 @@ namespace chaiscript
/// for handling of Proxy_Function object (that is, /// for handling of Proxy_Function object (that is,
/// function variables. /// function variables.
template<typename Type> template<typename Type>
auto shared_ptr_clone(const std::shared_ptr<Type> &p) std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
{ {
return p; return p;
} }
/// Specific version of shared_ptr_clone just for Proxy_Functions /// Specific version of shared_ptr_clone just for Proxy_Functions
template<typename Type> template<typename Type>
std::shared_ptr<typename std::remove_const<Type>::type> shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p) std::shared_ptr<typename std::remove_const<Type>::type>
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
{ {
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p); return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
} }
@ -211,41 +261,43 @@ namespace chaiscript
/// Add all arithmetic operators for PODs /// Add all arithmetic operators for PODs
static void opers_arithmetic_pod(Module& m) static void opers_arithmetic_pod(ModulePtr m = std::make_shared<Module>())
{ {
m.add(fun(&Boxed_Number::equals), "=="); m->add(fun(&Boxed_Number::equals), "==");
m.add(fun(&Boxed_Number::less_than), "<"); m->add(fun(&Boxed_Number::less_than), "<");
m.add(fun(&Boxed_Number::greater_than), ">"); m->add(fun(&Boxed_Number::greater_than), ">");
m.add(fun(&Boxed_Number::greater_than_equal), ">="); m->add(fun(&Boxed_Number::greater_than_equal), ">=");
m.add(fun(&Boxed_Number::less_than_equal), "<="); m->add(fun(&Boxed_Number::less_than_equal), "<=");
m.add(fun(&Boxed_Number::not_equal), "!="); m->add(fun(&Boxed_Number::not_equal), "!=");
m->add(fun(&Boxed_Number::pre_decrement), "--");
m->add(fun(&Boxed_Number::pre_increment), "++");
m->add(fun(&Boxed_Number::sum), "+");
m->add(fun(&Boxed_Number::unary_plus), "+");
m->add(fun(&Boxed_Number::unary_minus), "-");
m->add(fun(&Boxed_Number::difference), "-");
m->add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m->add(fun(&Boxed_Number::assign), "=");
m->add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m->add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m->add(fun(&Boxed_Number::assign_remainder), "%=");
m->add(fun(&Boxed_Number::assign_shift_left), "<<=");
m->add(fun(&Boxed_Number::assign_shift_right), ">>=");
m->add(fun(&Boxed_Number::bitwise_and), "&");
m->add(fun(&Boxed_Number::bitwise_complement), "~");
m->add(fun(&Boxed_Number::bitwise_xor), "^");
m->add(fun(&Boxed_Number::bitwise_or), "|");
m->add(fun(&Boxed_Number::assign_product), "*=");
m->add(fun(&Boxed_Number::assign_quotient), "/=");
m->add(fun(&Boxed_Number::assign_sum), "+=");
m->add(fun(&Boxed_Number::assign_difference), "-=");
m->add(fun(&Boxed_Number::quotient), "/");
m->add(fun(&Boxed_Number::shift_left), "<<");
m->add(fun(&Boxed_Number::product), "*");
m->add(fun(&Boxed_Number::remainder), "%");
m->add(fun(&Boxed_Number::shift_right), ">>");
m.add(fun(&Boxed_Number::pre_decrement), "--");
m.add(fun(&Boxed_Number::pre_increment), "++");
m.add(fun(&Boxed_Number::sum), "+");
m.add(fun(&Boxed_Number::unary_plus), "+");
m.add(fun(&Boxed_Number::unary_minus), "-");
m.add(fun(&Boxed_Number::difference), "-");
m.add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m.add(fun(&Boxed_Number::assign), "=");
m.add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m.add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m.add(fun(&Boxed_Number::assign_remainder), "%=");
m.add(fun(&Boxed_Number::assign_shift_left), "<<=");
m.add(fun(&Boxed_Number::assign_shift_right), ">>=");
m.add(fun(&Boxed_Number::bitwise_and), "&");
m.add(fun(&Boxed_Number::bitwise_complement), "~");
m.add(fun(&Boxed_Number::bitwise_xor), "^");
m.add(fun(&Boxed_Number::bitwise_or), "|");
m.add(fun(&Boxed_Number::assign_product), "*=");
m.add(fun(&Boxed_Number::assign_quotient), "/=");
m.add(fun(&Boxed_Number::assign_sum), "+=");
m.add(fun(&Boxed_Number::assign_difference), "-=");
m.add(fun(&Boxed_Number::quotient), "/");
m.add(fun(&Boxed_Number::shift_left), "<<");
m.add(fun(&Boxed_Number::product), "*");
m.add(fun(&Boxed_Number::remainder), "%");
m.add(fun(&Boxed_Number::shift_right), ">>");
} }
/// Create a bound function object. The first param is the function to bind /// Create a bound function object. The first param is the function to bind
@ -285,6 +337,26 @@ namespace chaiscript
} }
} }
static void throw_exception(const Boxed_Value &bv) {
throw bv;
}
static std::string what(const std::exception &e)
{
return e.what();
}
/// Boolean specialization of internal to_string function
static std::string bool_to_string(bool b)
{
if (b)
{
return "true";
} else {
return "false";
}
}
template<typename FunctionType> template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
const dispatch::Proxy_Function_Base *b) const dispatch::Proxy_Function_Base *b)
@ -320,7 +392,7 @@ namespace chaiscript
} }
template<typename Function> template<typename Function>
static auto return_boxed_value_vector(const Function &f) static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
{ {
return [f](const dispatch::Proxy_Function_Base *b) { return [f](const dispatch::Proxy_Function_Base *b) {
return do_return_boxed_value_vector(f, b); return do_return_boxed_value_vector(f, b);
@ -331,123 +403,94 @@ namespace chaiscript
public: public:
/// \brief perform all common bootstrap functions for std::string, void and POD types /// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to /// \param[in,out] m Module to add bootstrapped functions to
/// \returns passed in Module /// \returns passed in ModulePtr, or newly created one if default argument is used
static void bootstrap(Module& m) static ModulePtr bootstrap(ModulePtr m = std::make_shared<Module>())
{ {
m.add(user_type<void>(), "void"); m->add(user_type<void>(), "void");
m.add(user_type<bool>(), "bool"); m->add(user_type<bool>(), "bool");
m.add(user_type<Boxed_Value>(), "Object"); m->add(user_type<Boxed_Value>(), "Object");
m.add(user_type<Boxed_Number>(), "Number"); m->add(user_type<Boxed_Number>(), "Number");
m.add(user_type<Proxy_Function>(), "Function"); m->add(user_type<Proxy_Function>(), "Function");
m.add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function"); m->add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
m.add(user_type<std::exception>(), "exception"); m->add(user_type<std::exception>(), "exception");
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity"); m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "=="); m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types"); m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
m.add(fun([](const std::exception &e){ return std::string(e.what()); }), "what");
m.add(user_type<std::out_of_range>(), "out_of_range"); m->add(user_type<std::out_of_range>(), "out_of_range");
m.add(user_type<std::logic_error>(), "logic_error"); m->add(user_type<std::logic_error>(), "logic_error");
m.add(chaiscript::base_class<std::exception, std::logic_error>()); m->add(chaiscript::base_class<std::exception, std::logic_error>());
m.add(chaiscript::base_class<std::logic_error, std::out_of_range>()); m->add(chaiscript::base_class<std::logic_error, std::out_of_range>());
m.add(chaiscript::base_class<std::exception, std::out_of_range>()); m->add(chaiscript::base_class<std::exception, std::out_of_range>());
m.add(user_type<std::runtime_error>(), "runtime_error"); m->add(user_type<std::runtime_error>(), "runtime_error");
m.add(chaiscript::base_class<std::exception, std::runtime_error>()); m->add(chaiscript::base_class<std::exception, std::runtime_error>());
m.add(constructor<std::runtime_error (const std::string &)>(), "runtime_error"); m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object"); m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object"); m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object"); m->add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object");
m.add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name"); m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
m.add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs"); m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
m.add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit"); m->add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit"); m->add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr"); m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr"); m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)), "method_missing"); m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::method_missing)), "method_missing"); m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]"); m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]"); m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
m.eval(R"chaiscript( m->eval(R""(
def Dynamic_Object::clone() { def Dynamic_Object::clone() {
auto &new_o = Dynamic_Object(this.get_type_name()); auto &new_o = Dynamic_Object(this.get_type_name());
for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } ); for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
new_o; new_o;
} }
)"");
def `=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name() m->add(fun(&has_guard), "has_guard");
{ m->add(fun(&get_guard), "get_guard");
for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } );
}
def `!=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name() m->add(fun(&Boxed_Value::is_undef), "is_var_undef");
{ m->add(fun(&Boxed_Value::is_null), "is_var_null");
var rhs_attrs := rhs.get_attrs(); m->add(fun(&Boxed_Value::is_const), "is_var_const");
var lhs_attrs := lhs.get_attrs(); m->add(fun(&Boxed_Value::is_ref), "is_var_reference");
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
m->add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
m->add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
m->add(fun(&Boxed_Value::is_type), "is_type");
m->add(fun(&Boxed_Value::get_attr), "get_var_attr");
m->add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
m->add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
if (rhs_attrs.size() != lhs_attrs.size()) { m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
true; m->add(user_type<Type_Info>(), "Type_Info");
} else { m->add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
return any_of(rhs_attrs, fun[lhs](x) { !lhs.has_attr(x.first) || lhs.get_attr(x.first) != x.second; } );
}
}
def `==`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
{
var rhs_attrs := rhs.get_attrs();
var lhs_attrs := lhs.get_attrs();
if (rhs_attrs.size() != lhs_attrs.size()) {
false;
} else {
return all_of(rhs_attrs, fun[lhs](x) { lhs.has_attr(x.first) && lhs.get_attr(x.first) == x.second; } );
}
}
)chaiscript");
m.add(fun(&has_guard), "has_guard");
m.add(fun(&get_guard), "get_guard");
m.add(fun(&Boxed_Value::is_undef), "is_var_undef");
m.add(fun(&Boxed_Value::is_null), "is_var_null");
m.add(fun(&Boxed_Value::is_const), "is_var_const");
m.add(fun(&Boxed_Value::is_ref), "is_var_reference");
m.add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
m.add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
m.add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
m.add(fun(&Boxed_Value::is_type), "is_type");
m.add(fun(&Boxed_Value::get_attr), "get_var_attr");
m.add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
m.add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
m.add(fun(&Boxed_Value::get_type_info), "get_type_info");
m.add(user_type<Type_Info>(), "Type_Info");
m.add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
operators::equal<Type_Info>(m); operators::equal<Type_Info>(m);
m.add(fun(&Type_Info::is_const), "is_type_const"); m->add(fun(&Type_Info::is_const), "is_type_const");
m.add(fun(&Type_Info::is_reference), "is_type_reference"); m->add(fun(&Type_Info::is_reference), "is_type_reference");
m.add(fun(&Type_Info::is_void), "is_type_void"); m->add(fun(&Type_Info::is_void), "is_type_void");
m.add(fun(&Type_Info::is_undef), "is_type_undef"); m->add(fun(&Type_Info::is_undef), "is_type_undef");
m.add(fun(&Type_Info::is_pointer), "is_type_pointer"); m->add(fun(&Type_Info::is_pointer), "is_type_pointer");
m.add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic"); m->add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
m.add(fun(&Type_Info::name), "cpp_name"); m->add(fun(&Type_Info::name), "cpp_name");
m.add(fun(&Type_Info::bare_name), "cpp_bare_name"); m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
m.add(fun(&Type_Info::bare_equal), "bare_equal"); m->add(fun(&Type_Info::bare_equal), "bare_equal");
basic_constructors<bool>("bool", m); basic_constructors<bool>("bool", m);
@ -455,14 +498,14 @@ namespace chaiscript
operators::equal<bool>(m); operators::equal<bool>(m);
operators::not_equal<bool>(m); operators::not_equal<bool>(m);
m.add(fun([](const std::string &s) { return s; }), "to_string"); m->add(fun([](const std::string &s) -> std::string { return s; }), "to_string");
m.add(fun([](const bool b) { return std::string(b?"true":"false"); }), "to_string"); m->add(fun(&Bootstrap::bool_to_string), "to_string");
m.add(fun(&unknown_assign), "="); m->add(fun(&unknown_assign), "=");
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw"); m->add(fun(&throw_exception), "throw");
m->add(fun(&what), "what");
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
m.add(fun(&Boxed_Number::to_string), "to_string");
m->add(fun(&to_string<char>), "to_string");
m->add(fun(&Boxed_Number::to_string), "to_string");
bootstrap_pod_type<double>("double", m); bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m); bootstrap_pod_type<long double>("long_double", m);
@ -487,71 +530,58 @@ namespace chaiscript
bootstrap_pod_type<std::uint32_t>("uint32_t", m); bootstrap_pod_type<std::uint32_t>("uint32_t", m);
bootstrap_pod_type<std::uint64_t>("uint64_t", m); bootstrap_pod_type<std::uint64_t>("uint64_t", m);
operators::logical_compliment<bool>(m); operators::logical_compliment<bool>(m);
opers_arithmetic_pod(m); opers_arithmetic_pod(m);
m.add(fun(&Build_Info::version_major), "version_major"); m->add(fun(&print), "print_string");
m.add(fun(&Build_Info::version_minor), "version_minor"); m->add(fun(&println), "println_string");
m.add(fun(&Build_Info::version_patch), "version_patch");
m.add(fun(&Build_Info::version), "version");
m.add(fun(&Build_Info::compiler_version), "compiler_version");
m.add(fun(&Build_Info::compiler_name), "compiler_name");
m.add(fun(&Build_Info::compiler_id), "compiler_id");
m.add(fun(&Build_Info::debug_build), "debug_build");
m->add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
m.add(fun(&print), "print_string"); m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m.add(fun(&println), "println_string"); m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind"); m->add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
m->add(fun(
m.add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m.add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
m.add(fun(
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) { [](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
t_lhs.assign(t_rhs); t_lhs.assign(t_rhs);
} }
), "=" ), "="
); );
m.add(fun(&Boxed_Value::type_match), "type_match"); m->add(fun(&Boxed_Value::type_match), "type_match");
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>()); m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error"); m->add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>()); m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m); // chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m, chaiscript::utility::add_class<chaiscript::exception::eval_error>(*m,
"eval_error", "eval_error",
{ }, { },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"}, { {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"}, {fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
{fun([](const chaiscript::exception::eval_error &t_eval_error) { {fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval; std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(), std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
std::back_inserter(retval), std::back_inserter(retval),
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>); &chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
return retval; return retval;
}), "call_stack"} } })), "call_stack"} }
); );
chaiscript::utility::add_class<chaiscript::File_Position>(m, chaiscript::utility::add_class<chaiscript::File_Position>(*m,
"File_Position", "File_Position",
{ constructor<File_Position()>(), { constructor<File_Position()>(),
constructor<File_Position(int, int)>() }, constructor<File_Position(int, int)>() },
@ -560,7 +590,7 @@ namespace chaiscript
); );
chaiscript::utility::add_class<AST_Node>(m, chaiscript::utility::add_class<AST_Node>(*m,
"AST_Node", "AST_Node",
{ }, { },
{ {fun(&AST_Node::text), "text"}, { {fun(&AST_Node::text), "text"},
@ -569,17 +599,28 @@ namespace chaiscript
{fun(&AST_Node::start), "start"}, {fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"}, {fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"}, {fun(&AST_Node::to_string), "to_string"},
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> { {fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval; std::vector<Boxed_Value> retval;
const auto children = t_node.get_children(); std::transform(t_node.children.begin(), t_node.children.end(),
std::transform(children.begin(), children.end(),
std::back_inserter(retval), std::back_inserter(retval),
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>); &chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
return retval; return retval;
}), "children"} })), "children"},
{fun(&AST_Node::replace_child), "replace_child"}
} }
); );
chaiscript::utility::add_class<parser::ChaiScript_Parser>(*m,
"ChaiScript_Parser",
{ constructor<parser::ChaiScript_Parser ()>() },
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
);
return m;
} }
}; };
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/// \file /// \file
/// This file contains utility functions for registration of STL container /// This file contains utility functions for registration of STL container
/// classes. The methodology used is based on the SGI STL concepts. /// classes. The methodology used is based on the SGI STL concepts.
@ -41,10 +37,11 @@ namespace chaiscript
/// Bidir_Range, based on the D concept of ranges. /// Bidir_Range, based on the D concept of ranges.
/// \todo Update the Range code to base its capabilities on /// \todo Update the Range code to base its capabilities on
/// the user_typetraits of the iterator passed in /// the user_typetraits of the iterator passed in
template<typename Container, typename IterType> template<typename Container>
struct Bidir_Range struct Bidir_Range
{ {
typedef Container container_type; typedef Container container_type;
typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
Bidir_Range(Container &c) Bidir_Range(Container &c)
: m_begin(c.begin()), m_end(c.end()) : m_begin(c.begin()), m_end(c.end())
@ -74,28 +71,86 @@ namespace chaiscript
--m_end; --m_end;
} }
decltype(auto) front() const reference_type front() const
{ {
if (empty()) if (empty())
{ {
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
return (*m_begin); return *m_begin;
} }
decltype(auto) back() const reference_type back() const
{ {
if (empty()) if (empty())
{ {
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
auto pos = m_end; typename Container::iterator pos = m_end;
--pos; --pos;
return (*(pos)); return *(pos);
} }
IterType m_begin; typename Container::iterator m_begin;
IterType m_end; typename Container::iterator m_end;
};
template<typename Container>
struct Const_Bidir_Range
{
typedef const Container container_type;
typedef typename std::iterator_traits<typename Container::const_iterator>::reference const_reference_type;
Const_Bidir_Range(const Container &c)
: m_begin(c.begin()), m_end(c.end())
{
}
bool empty() const
{
return m_begin == m_end;
}
void pop_front()
{
if (empty())
{
throw std::range_error("Range empty");
}
++m_begin;
}
void pop_back()
{
if (empty())
{
throw std::range_error("Range empty");
}
--m_end;
}
const_reference_type front() const
{
if (empty())
{
throw std::range_error("Range empty");
}
return *m_begin;
}
const_reference_type back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
typename Container::const_iterator pos = m_end;
--pos;
return *(pos);
}
typename Container::const_iterator m_begin;
typename Container::const_iterator m_end;
}; };
namespace detail { namespace detail {
@ -122,19 +177,21 @@ namespace chaiscript
/// Add Bidir_Range support for the given ContainerType /// Add Bidir_Range support for the given ContainerType
template<typename Bidir_Type> template<typename Bidir_Type>
void input_range_type_impl(const std::string &type, Module& m) ModulePtr input_range_type_impl(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(user_type<Bidir_Type>(), type + "_Range"); m->add(user_type<Bidir_Type>(), type + "_Range");
copy_constructor<Bidir_Type>(type + "_Range", m); copy_constructor<Bidir_Type>(type + "_Range", m);
m.add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal"); m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal");
m.add(fun(&Bidir_Type::empty), "empty"); m->add(fun(&Bidir_Type::empty), "empty");
m.add(fun(&Bidir_Type::pop_front), "pop_front"); m->add(fun(&Bidir_Type::pop_front), "pop_front");
m.add(fun(&Bidir_Type::front), "front"); m->add(fun(&Bidir_Type::front), "front");
m.add(fun(&Bidir_Type::pop_back), "pop_back"); m->add(fun(&Bidir_Type::pop_back), "pop_back");
m.add(fun(&Bidir_Type::back), "back"); m->add(fun(&Bidir_Type::back), "back");
return m;
} }
@ -173,16 +230,10 @@ namespace chaiscript
} }
template<typename ContainerType> template<typename ContainerType>
void input_range_type(const std::string &type, Module& m) ModulePtr input_range_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator> >(type,m); detail::input_range_type_impl<Bidir_Range<ContainerType> >(type,m);
detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator> >("Const_" + type,m); detail::input_range_type_impl<Const_Bidir_Range<ContainerType> >("Const_" + type, m);
}
template<typename ContainerType>
ModulePtr input_range_type(const std::string &type)
{
auto m = std::make_shared<Module>();
input_range_type<ContainerType>(type, *m);
return m; return m;
} }
@ -190,83 +241,33 @@ namespace chaiscript
/// Add random_access_container concept to the given ContainerType /// Add random_access_container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/RandomAccessContainer.html /// http://www.sgi.com/tech/stl/RandomAccessContainer.html
template<typename ContainerType> template<typename ContainerType>
void random_access_container_type(const std::string &/*type*/, Module& m) ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
{ {
//In the interest of runtime safety for the m, we prefer the at() method for [] access, //In the interest of runtime safety for the m, we prefer the at() method for [] access,
//to throw an exception in an out of bounds condition. //to throw an exception in an out of bounds condition.
m.add( m->add(
fun( fun(
[](ContainerType &c, int index) -> typename ContainerType::reference { [](ContainerType &c, int index) -> typename ContainerType::reference {
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions return c.at(index);
/// during dispatch. reevaluate
return c.at(static_cast<typename ContainerType::size_type>(index));
}), "[]"); }), "[]");
m.add( m->add(
fun( fun(
[](const ContainerType &c, int index) -> typename ContainerType::const_reference { [](const ContainerType &c, int index) -> typename ContainerType::const_reference {
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions return c.at(index);
/// during dispatch. reevaluate
return c.at(static_cast<typename ContainerType::size_type>(index));
}), "[]"); }), "[]");
}
template<typename ContainerType>
ModulePtr random_access_container_type(const std::string &type)
{
auto m = std::make_shared<Module>();
random_access_container_type<ContainerType>(type, *m);
return m; return m;
} }
/// Add assignable concept to the given ContainerType /// Add assignable concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Assignable.html /// http://www.sgi.com/tech/stl/Assignable.html
template<typename ContainerType> template<typename ContainerType>
void assignable_type(const std::string &type, Module& m) ModulePtr assignable_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
copy_constructor<ContainerType>(type, m); copy_constructor<ContainerType>(type, m);
operators::assign<ContainerType>(m); operators::assign<ContainerType>(m);
}
template<typename ContainerType>
ModulePtr assignable_type(const std::string &type)
{
auto m = std::make_shared<Module>();
assignable_type<ContainerType>(type, *m);
return m;
}
/// Add container resize concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/
template<typename ContainerType>
void resizable_type(const std::string &/*type*/, Module& m)
{
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type& val) { return a->resize(n, val); } ), "resize");
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); } ), "resize");
}
template<typename ContainerType>
ModulePtr resizable_type(const std::string &type)
{
auto m = std::make_shared<Module>();
resizable_type<ContainerType>(type, *m);
return m;
}
/// Add container reserve concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/
template<typename ContainerType>
void reservable_type(const std::string &/*type*/, Module& m)
{
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); } ), "reserve");
m.add(fun([](const ContainerType *a) { return a->capacity(); } ), "capacity");
}
template<typename ContainerType>
ModulePtr reservable_type(const std::string &type)
{
auto m = std::make_shared<Module>();
reservable_type<ContainerType>(type, *m);
return m; return m;
} }
@ -274,17 +275,11 @@ namespace chaiscript
/// Add container concept to the given ContainerType /// Add container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Container.html /// http://www.sgi.com/tech/stl/Container.html
template<typename ContainerType> template<typename ContainerType>
void container_type(const std::string &/*type*/, Module& m) ModulePtr container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
{ {
m.add(fun([](const ContainerType *a) { return a->size(); } ), "size"); m->add(fun([](const ContainerType *a) { return a->size(); } ), "size");
m.add(fun([](const ContainerType *a) { return a->empty(); } ), "empty"); m->add(fun([](const ContainerType *a) { return a->empty(); } ), "empty");
m.add(fun([](ContainerType *a) { a->clear(); } ), "clear"); m->add(fun([](ContainerType *a) { a->clear(); } ), "clear");
}
template <typename ContainerType>
ModulePtr container_type(const std::string& type)
{
auto m = std::make_shared<Module>();
container_type<ContainerType>(type, *m);
return m; return m;
} }
@ -292,26 +287,21 @@ namespace chaiscript
/// Add default constructable concept to the given Type /// Add default constructable concept to the given Type
/// http://www.sgi.com/tech/stl/DefaultConstructible.html /// http://www.sgi.com/tech/stl/DefaultConstructible.html
template<typename Type> template<typename Type>
void default_constructible_type(const std::string &type, Module& m) ModulePtr default_constructible_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(constructor<Type ()>(), type); m->add(constructor<Type ()>(), type);
}
template <typename Type>
ModulePtr default_constructible_type(const std::string& type)
{
auto m = std::make_shared<Module>();
default_constructible_type<Type>(type, *m);
return m; return m;
} }
/// Add sequence concept to the given ContainerType /// Add sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Sequence.html /// http://www.sgi.com/tech/stl/Sequence.html
template<typename ContainerType> template<typename ContainerType>
void sequence_type(const std::string &/*type*/, Module& m) ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
{ {
m.add(fun(&detail::insert_at<ContainerType>), m->add(fun(&detail::insert_at<ContainerType>),
[]()->std::string{ []()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
return "insert_ref_at"; return "insert_ref_at";
@ -320,31 +310,27 @@ namespace chaiscript
} }
}()); }());
m.add(fun(&detail::erase_at<ContainerType>), "erase_at"); m->add(fun(&detail::erase_at<ContainerType>), "erase_at");
}
template <typename ContainerType>
ModulePtr sequence_type(const std::string &type)
{
auto m = std::make_shared<Module>();
sequence_type<ContainerType>(type, *m);
return m; return m;
} }
/// Add back insertion sequence concept to the given ContainerType /// Add back insertion sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html /// http://www.sgi.com/tech/stl/BackInsertionSequence.html
template<typename ContainerType> template<typename ContainerType>
void back_insertion_sequence_type(const std::string &type, Module& m) ModulePtr back_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
typedef typename ContainerType::reference (ContainerType::*backptr)(); typedef typename ContainerType::reference (ContainerType::*backptr)();
m.add(fun(static_cast<backptr>(&ContainerType::back)), "back"); m->add(fun(static_cast<backptr>(&ContainerType::back)), "back");
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &); typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
m.add(fun(static_cast<push_back>(&ContainerType::push_back)), m->add(fun(static_cast<push_back>(&ContainerType::push_back)),
[&]()->std::string{ [&]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
m.eval( m->eval(
"# Pushes the second value onto the container while making a clone of the value\n" "# Pushes the second value onto the container while making a clone of the value\n"
"def push_back(" + type + " container, x)\n" "def push_back(" + type + " container, x)\n"
"{ \n" "{ \n"
@ -363,13 +349,7 @@ namespace chaiscript
} }
}()); }());
m.add(fun(&ContainerType::pop_back), "pop_back"); m->add(fun(&ContainerType::pop_back), "pop_back");
}
template<typename ContainerType>
ModulePtr back_insertion_sequence_type(const std::string &type)
{
auto m = std::make_shared<Module>();
back_insertion_sequence_type<ContainerType>(type, *m);
return m; return m;
} }
@ -378,20 +358,20 @@ namespace chaiscript
/// Front insertion sequence /// Front insertion sequence
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html /// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
template<typename ContainerType> template<typename ContainerType>
void front_insertion_sequence_type(const std::string &type, Module& m) ModulePtr front_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
typedef typename ContainerType::reference (ContainerType::*front_ptr)(); typedef typename ContainerType::reference (ContainerType::*front_ptr)();
typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const; typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const;
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference); typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference);
typedef void (ContainerType::*pop_ptr)(); typedef void (ContainerType::*pop_ptr)();
m.add(fun(static_cast<front_ptr>(&ContainerType::front)), "front"); m->add(fun(static_cast<front_ptr>(&ContainerType::front)), "front");
m.add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front"); m->add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front");
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)), m->add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
[&]()->std::string{ [&]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
m.eval( m->eval(
"# Pushes the second value onto the front of container while making a clone of the value\n" "# Pushes the second value onto the front of container while making a clone of the value\n"
"def push_front(" + type + " container, x)\n" "def push_front(" + type + " container, x)\n"
"{ \n" "{ \n"
@ -409,13 +389,7 @@ namespace chaiscript
} }
}()); }());
m.add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front"); m->add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front");
}
template<typename ContainerType>
ModulePtr front_insertion_sequence_type(const std::string &type)
{
auto m = std::make_shared<Module>();
front_insertion_sequence_type<ContainerType>(type, *m);
return m; return m;
} }
@ -423,21 +397,20 @@ namespace chaiscript
/// bootstrap a given PairType /// bootstrap a given PairType
/// http://www.sgi.com/tech/stl/pair.html /// http://www.sgi.com/tech/stl/pair.html
template<typename PairType> template<typename PairType>
void pair_type(const std::string &type, Module& m) ModulePtr pair_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(user_type<PairType>(), type); m->add(user_type<PairType>(), type);
m.add(fun(&PairType::first), "first");
m.add(fun(&PairType::second), "second"); typename PairType::first_type PairType::* f = &PairType::first;
typename PairType::second_type PairType::* s = &PairType::second;
m->add(fun(f), "first");
m->add(fun(s), "second");
basic_constructors<PairType>(type, m); basic_constructors<PairType>(type, m);
m.add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type); m->add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
}
template<typename PairType>
ModulePtr pair_type(const std::string &type)
{
auto m = std::make_shared<Module>();
pair_type<PairType>(type, *m);
return m; return m;
} }
@ -447,15 +420,10 @@ namespace chaiscript
/// http://www.sgi.com/tech/stl/PairAssociativeContainer.html /// http://www.sgi.com/tech/stl/PairAssociativeContainer.html
template<typename ContainerType> template<typename ContainerType>
void pair_associative_container_type(const std::string &type, Module& m) ModulePtr pair_associative_container_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
pair_type<typename ContainerType::value_type>(type + "_Pair", m); pair_type<typename ContainerType::value_type>(type + "_Pair", m);
}
template<typename ContainerType>
ModulePtr pair_associative_container_type(const std::string &type)
{
auto m = std::make_shared<Module>();
pair_associative_container_type<ContainerType>(type, *m);
return m; return m;
} }
@ -463,17 +431,17 @@ namespace chaiscript
/// Add unique associative container concept to the given ContainerType /// Add unique associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html /// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
template<typename ContainerType> template<typename ContainerType>
void unique_associative_container_type(const std::string &/*type*/, Module& m) ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
{ {
m.add(fun(detail::count<ContainerType>), "count"); m->add(fun(detail::count<ContainerType>), "count");
typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &); typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &);
m.add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase"); m->add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
m.add(fun(&detail::insert<ContainerType>), "insert"); m->add(fun(&detail::insert<ContainerType>), "insert");
m.add(fun(&detail::insert_ref<ContainerType>), m->add(fun(&detail::insert_ref<ContainerType>),
[]()->std::string{ []()->std::string{
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
return "insert_ref"; return "insert_ref";
@ -481,12 +449,8 @@ namespace chaiscript
return "insert"; return "insert";
} }
}()); }());
}
template<typename ContainerType>
ModulePtr unique_associative_container_type(const std::string &type)
{
auto m = std::make_shared<Module>();
unique_associative_container_type<ContainerType>(type, *m);
return m; return m;
} }
@ -494,21 +458,21 @@ namespace chaiscript
/// Add a MapType container /// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html /// http://www.sgi.com/tech/stl/Map.html
template<typename MapType> template<typename MapType>
void map_type(const std::string &type, Module& m) ModulePtr map_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(user_type<MapType>(), type); m->add(user_type<MapType>(), type);
typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &); typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &);
typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const; typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const;
m.add(fun(static_cast<elem_access>(&MapType::operator[])), "[]"); m->add(fun(static_cast<elem_access>(&MapType::operator[])), "[]");
m.add(fun(static_cast<elem_access>(&MapType::at)), "at"); m->add(fun(static_cast<elem_access>(&MapType::at)), "at");
m.add(fun(static_cast<const_elem_access>(&MapType::at)), "at"); m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>)) if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>))
{ {
m.eval(R"( m->eval(R"(
def Map::`==`(Map rhs) { def Map::`==`(Map rhs) {
if ( rhs.size() != this.size() ) { if ( rhs.size() != this.size() ) {
return false; return false;
@ -536,36 +500,26 @@ namespace chaiscript
unique_associative_container_type<MapType>(type, m); unique_associative_container_type<MapType>(type, m);
pair_associative_container_type<MapType>(type, m); pair_associative_container_type<MapType>(type, m);
input_range_type<MapType>(type, m); input_range_type<MapType>(type, m);
}
template<typename MapType>
ModulePtr map_type(const std::string &type)
{
auto m = std::make_shared<Module>();
map_type<MapType>(type, *m);
return m; return m;
} }
/// hopefully working List type
/// http://www.sgi.com/tech/stl/List.html /// http://www.sgi.com/tech/stl/List.html
template<typename ListType> template<typename ListType>
void list_type(const std::string &type, Module& m) ModulePtr list_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(user_type<ListType>(), type); m->add(user_type<ListType>(), type);
front_insertion_sequence_type<ListType>(type, m); front_insertion_sequence_type<ListType>(type, m);
back_insertion_sequence_type<ListType>(type, m); back_insertion_sequence_type<ListType>(type, m);
sequence_type<ListType>(type, m); sequence_type<ListType>(type, m);
resizable_type<ListType>(type, m);
container_type<ListType>(type, m); container_type<ListType>(type, m);
default_constructible_type<ListType>(type, m); default_constructible_type<ListType>(type, m);
assignable_type<ListType>(type, m); assignable_type<ListType>(type, m);
input_range_type<ListType>(type, m); input_range_type<ListType>(type, m);
}
template<typename ListType>
ModulePtr list_type(const std::string &type)
{
auto m = std::make_shared<Module>();
list_type<ListType>(type, m);
return m; return m;
} }
@ -573,22 +527,20 @@ namespace chaiscript
/// Create a vector type with associated concepts /// Create a vector type with associated concepts
/// http://www.sgi.com/tech/stl/Vector.html /// http://www.sgi.com/tech/stl/Vector.html
template<typename VectorType> template<typename VectorType>
void vector_type(const std::string &type, Module& m) ModulePtr vector_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(user_type<VectorType>(), type); m->add(user_type<VectorType>(), type);
typedef typename VectorType::reference (VectorType::*frontptr)(); typedef typename VectorType::reference (VectorType::*frontptr)();
typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const; typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const;
m.add(fun(static_cast<frontptr>(&VectorType::front)), "front"); m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
m.add(fun(static_cast<constfrontptr>(&VectorType::front)), "front"); m->add(fun(static_cast<constfrontptr>(&VectorType::front)), "front");
back_insertion_sequence_type<VectorType>(type, m); back_insertion_sequence_type<VectorType>(type, m);
sequence_type<VectorType>(type, m); sequence_type<VectorType>(type, m);
random_access_container_type<VectorType>(type, m); random_access_container_type<VectorType>(type, m);
resizable_type<VectorType>(type, m);
reservable_type<VectorType>(type, m);
container_type<VectorType>(type, m); container_type<VectorType>(type, m);
default_constructible_type<VectorType>(type, m); default_constructible_type<VectorType>(type, m);
assignable_type<VectorType>(type, m); assignable_type<VectorType>(type, m);
@ -596,7 +548,7 @@ namespace chaiscript
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{ {
m.eval(R"( m->eval(R"(
def Vector::`==`(Vector rhs) { def Vector::`==`(Vector rhs) {
if ( rhs.size() != this.size() ) { if ( rhs.size() != this.size() ) {
return false; return false;
@ -617,21 +569,16 @@ namespace chaiscript
} )" } )"
); );
} }
}
template<typename VectorType>
ModulePtr vector_type(const std::string &type)
{
auto m = std::make_shared<Module>();
vector_type<VectorType>(type, *m);
return m; return m;
} }
/// Add a String container /// Add a String container
/// http://www.sgi.com/tech/stl/basic_string.html /// http://www.sgi.com/tech/stl/basic_string.html
template<typename String> template<typename String>
void string_type(const std::string &type, Module& m) ModulePtr string_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(user_type<String>(), type); m->add(user_type<String>(), type);
operators::addition<String>(m); operators::addition<String>(m);
operators::assign_sum<String>(m); operators::assign_sum<String>(m);
opers_comparison<String>(m); opers_comparison<String>(m);
@ -643,7 +590,7 @@ namespace chaiscript
input_range_type<String>(type, m); input_range_type<String>(type, m);
//Special case: add push_back to string (which doesn't support other back_insertion operations //Special case: add push_back to string (which doesn't support other back_insertion operations
m.add(fun(&String::push_back), m->add(fun(&String::push_back),
[]()->std::string{ []()->std::string{
if (typeid(typename String::value_type) == typeid(Boxed_Value)) { if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
return "push_back_ref"; return "push_back_ref";
@ -653,26 +600,21 @@ namespace chaiscript
}()); }());
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find"); m->add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind"); m->add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ), "find_first_of"); m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ), "find_first_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of"); m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of"); m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of"); m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of");
m.add(fun([](String *s) { s->clear(); } ), "clear"); m->add(fun([](String *s) { s->clear(); } ), "clear");
m.add(fun([](const String *s) { return s->empty(); } ), "empty"); m->add(fun([](const String *s) { return s->empty(); } ), "empty");
m.add(fun([](const String *s) { return s->size(); } ), "size"); m->add(fun([](const String *s) { return s->size(); } ), "size");
m->add(fun([](const String *s) { return s->c_str(); } ), "c_str");
m->add(fun([](const String *s) { return s->data(); } ), "data");
m->add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr");
m.add(fun([](const String *s) { return s->c_str(); } ), "c_str");
m.add(fun([](const String *s) { return s->data(); } ), "data");
m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr");
}
template<typename String>
ModulePtr string_type(const std::string &type)
{
auto m = std::make_shared<Module>();
string_type<String>(type, *m);
return m; return m;
} }
@ -681,19 +623,14 @@ namespace chaiscript
/// Add a MapType container /// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html /// http://www.sgi.com/tech/stl/Map.html
template<typename FutureType> template<typename FutureType>
void future_type(const std::string &type, Module& m) ModulePtr future_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
{ {
m.add(user_type<FutureType>(), type); m->add(user_type<FutureType>(), type);
m->add(fun([](const FutureType &t) { return t.valid(); }), "valid");
m->add(fun(&FutureType::get), "get");
m->add(fun(&FutureType::wait), "wait");
m.add(fun([](const FutureType &t) { return t.valid(); }), "valid");
m.add(fun(&FutureType::get), "get");
m.add(fun(&FutureType::wait), "wait");
}
template<typename FutureType>
ModulePtr future_type(const std::string &type)
{
auto m = std::make_shared<Module>();
future_type<FutureType>(type, *m);
return m; return m;
} }
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_ #define CHAISCRIPT_BOXED_CAST_HPP_
@ -73,32 +69,34 @@ namespace chaiscript
/// assert(i == 5); /// assert(i == 5);
/// \endcode /// \endcode
template<typename Type> template<typename Type>
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr) typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
{ {
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) { if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !t_conversions->convertable_type<Type>())) {
try { try {
return(detail::Cast_Helper<Type>::cast(bv, t_conversions)); return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
} }
} }
if (t_conversions && (*t_conversions)->convertable_type<Type>()) if (t_conversions && t_conversions->convertable_type<Type>())
{ {
try { try {
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work // either way, we are not responsible if it doesn't work
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions)); return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
} catch (...) { } catch (...) {
try { try {
// try going the other way // std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions)); // try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
} }
} else { } else {
// If it's not convertable, just throw the error, don't waste the time on the // If it's not polymorphic, just throw the error, don't waste the time on the
// attempted dynamic_cast // attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
@ -20,7 +16,7 @@
namespace chaiscript namespace chaiscript
{ {
class Type_Conversions_State; class Type_Conversions;
namespace detail namespace detail
{ {
@ -29,54 +25,25 @@ namespace chaiscript
template<typename T> template<typename T>
T* throw_if_null(T *t) T* throw_if_null(T *t)
{ {
if (t) { return t; } if (t) return t;
throw std::runtime_error("Attempted to dereference null Boxed_Value"); throw std::runtime_error("Attempted to dereference null Boxed_Value");
} }
template<typename T>
static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info() == ti) {
return ptr;
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
if (!ob.is_const() && ob.get_type_info() == ti) {
return ptr;
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info().bare_equal_type_info(ti)) {
return throw_if_null(ptr);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static T *verify_type(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
if (!ob.is_const() && ob.get_type_info().bare_equal_type_info(ti)) {
return throw_if_null(ptr);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
/// Generic Cast_Helper_Inner, for casting to any type /// Generic Cast_Helper_Inner, for casting to any type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner struct Cast_Helper_Inner
{ {
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef typename std::add_const<Result>::type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr())); if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
auto p = throw_if_null(ob.get_const_ptr());
return *static_cast<const Result *>(p);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
} }
}; };
@ -90,9 +57,15 @@ namespace chaiscript
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result *> struct Cast_Helper_Inner<const Result *>
{ {
static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr())); if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
return static_cast<const Result *>(ob.get_const_ptr());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
} }
}; };
@ -100,9 +73,15 @@ namespace chaiscript
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result *> struct Cast_Helper_Inner<Result *>
{ {
static Result * cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr())); if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
{
return static_cast<Result *>(ob.get_ptr());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
} }
}; };
@ -121,9 +100,17 @@ namespace chaiscript
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result &> struct Cast_Helper_Inner<const Result &>
{ {
static const Result & cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef const Result& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr())); if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
auto p = throw_if_null(ob.get_const_ptr());
return *static_cast<const Result *>(p);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
} }
}; };
@ -133,61 +120,26 @@ namespace chaiscript
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<Result &>
{ {
static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef Result& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())); if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
} }
}; };
/// Cast_Helper_Inner for casting to a && type
template<typename Result>
struct Cast_Helper_Inner<Result &&>
{
static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &&>
{
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &>
{
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<const std::unique_ptr<Result> &>
{
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type /// Cast_Helper_Inner for casting to a std::shared_ptr<> type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<std::shared_ptr<Result> >
{ {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef std::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return ob.get().cast<std::shared_ptr<Result> >(); return ob.get().cast<std::shared_ptr<Result> >();
} }
@ -197,7 +149,9 @@ namespace chaiscript
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<const Result> > struct Cast_Helper_Inner<std::shared_ptr<const Result> >
{ {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef std::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (!ob.get_type_info().is_const()) if (!ob.get_type_info().is_const())
{ {
@ -219,18 +173,6 @@ namespace chaiscript
{ {
}; };
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> &>
{
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
return ob.pointer_sentinel(res);
}
};
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type /// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> > struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
@ -247,7 +189,9 @@ namespace chaiscript
template<> template<>
struct Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<Boxed_Value>
{ {
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef Boxed_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return ob; return ob;
} }
@ -257,7 +201,9 @@ namespace chaiscript
template<> template<>
struct Cast_Helper_Inner<Boxed_Value &> struct Cast_Helper_Inner<Boxed_Value &>
{ {
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef std::reference_wrapper<Boxed_Value> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return std::ref(const_cast<Boxed_Value &>(ob)); return std::ref(const_cast<Boxed_Value &>(ob));
} }
@ -311,9 +257,11 @@ namespace chaiscript
template<typename T> template<typename T>
struct Cast_Helper struct Cast_Helper
{ {
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
return(Cast_Helper_Inner<T>::cast(ob, t_conversions)); return Cast_Helper_Inner<T>::cast(ob, t_conversions);
} }
}; };
} }

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_ #ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_
#define CHAISCRIPT_BOXED_NUMERIC_HPP_ #define CHAISCRIPT_BOXED_NUMERIC_HPP_
@ -31,9 +28,9 @@ namespace chaiscript
{ {
struct arithmetic_error : std::runtime_error struct arithmetic_error : std::runtime_error
{ {
explicit arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {} arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {}
arithmetic_error(const arithmetic_error &) = default; arithmetic_error(const arithmetic_error &) = default;
~arithmetic_error() noexcept override = default; virtual ~arithmetic_error() CHAISCRIPT_NOEXCEPT {}
}; };
} }
} }
@ -46,19 +43,16 @@ namespace chaiscript
// this is OK, so we're disabling size/and sign type warnings // this is OK, so we're disabling size/and sign type warnings
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4244 4018 4389 4146 4365 4267 4242) #pragma warning(disable : 4244 4018 4389 4146 4365 4267)
#endif #endif
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wfloat-equal" #pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic ignored "-Wsign-conversion"
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#endif #endif
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values /// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
@ -94,7 +88,7 @@ namespace chaiscript
{ {
} }
static constexpr Common_Types get_common_type(size_t t_size, bool t_signed) static CHAISCRIPT_CONSTEXPR Common_Types get_common_type(size_t t_size, bool t_signed)
{ {
return (t_size == 1 && t_signed)?(Common_Types::t_int8) return (t_size == 1 && t_signed)?(Common_Types::t_int8)
:(t_size == 1)?(Common_Types::t_uint8) :(t_size == 1)?(Common_Types::t_uint8)
@ -165,17 +159,17 @@ namespace chaiscript
{ {
switch (t_oper) switch (t_oper)
{ {
case Operators::Opers::equals: case Operators::equals:
return const_var(t == u); return const_var(t == u);
case Operators::Opers::less_than: case Operators::less_than:
return const_var(t < u); return const_var(t < u);
case Operators::Opers::greater_than: case Operators::greater_than:
return const_var(t > u); return const_var(t > u);
case Operators::Opers::less_than_equal: case Operators::less_than_equal:
return const_var(t <= u); return const_var(t <= u);
case Operators::Opers::greater_than_equal: case Operators::greater_than_equal:
return const_var(t >= u); return const_var(t >= u);
case Operators::Opers::not_equal: case Operators::not_equal:
return const_var(t != u); return const_var(t != u);
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
@ -187,10 +181,10 @@ namespace chaiscript
{ {
switch (t_oper) switch (t_oper)
{ {
case Operators::Opers::pre_increment: case Operators::pre_increment:
++t; ++t;
break; break;
case Operators::Opers::pre_decrement: case Operators::pre_decrement:
--t; --t;
break; break;
default: default:
@ -205,20 +199,20 @@ namespace chaiscript
{ {
switch (t_oper) switch (t_oper)
{ {
case Operators::Opers::assign: case Operators::assign:
t = u; t = u;
break; break;
case Operators::Opers::assign_product: case Operators::assign_product:
t *= u; t *= u;
break; break;
case Operators::Opers::assign_sum: case Operators::assign_sum:
t += u; t += u;
break; break;
case Operators::Opers::assign_quotient: case Operators::assign_quotient:
check_divide_by_zero(u); check_divide_by_zero(u);
t /= u; t /= u;
break; break;
case Operators::Opers::assign_difference: case Operators::assign_difference:
t -= u; t -= u;
break; break;
default: default:
@ -233,23 +227,23 @@ namespace chaiscript
{ {
switch (t_oper) switch (t_oper)
{ {
case Operators::Opers::assign_bitwise_and: case Operators::assign_bitwise_and:
t &= u; t &= u;
break; break;
case Operators::Opers::assign_bitwise_or: case Operators::assign_bitwise_or:
t |= u; t |= u;
break; break;
case Operators::Opers::assign_shift_left: case Operators::assign_shift_left:
t <<= u; t <<= u;
break; break;
case Operators::Opers::assign_shift_right: case Operators::assign_shift_right:
t >>= u; t >>= u;
break; break;
case Operators::Opers::assign_remainder: case Operators::assign_remainder:
check_divide_by_zero(u); check_divide_by_zero(u);
t %= u; t %= u;
break; break;
case Operators::Opers::assign_bitwise_xor: case Operators::assign_bitwise_xor:
t ^= u; t ^= u;
break; break;
default: default:
@ -263,7 +257,7 @@ namespace chaiscript
{ {
switch (t_oper) switch (t_oper)
{ {
case Operators::Opers::bitwise_complement: case Operators::bitwise_complement:
return const_var(~t); return const_var(~t);
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
@ -275,18 +269,18 @@ namespace chaiscript
{ {
switch (t_oper) switch (t_oper)
{ {
case Operators::Opers::shift_left: case Operators::shift_left:
return const_var(t << u); return const_var(t << u);
case Operators::Opers::shift_right: case Operators::shift_right:
return const_var(t >> u); return const_var(t >> u);
case Operators::Opers::remainder: case Operators::remainder:
check_divide_by_zero(u); check_divide_by_zero(u);
return const_var(t % u); return const_var(t % u);
case Operators::Opers::bitwise_and: case Operators::bitwise_and:
return const_var(t & u); return const_var(t & u);
case Operators::Opers::bitwise_or: case Operators::bitwise_or:
return const_var(t | u); return const_var(t | u);
case Operators::Opers::bitwise_xor: case Operators::bitwise_xor:
return const_var(t ^ u); return const_var(t ^ u);
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
@ -298,9 +292,9 @@ namespace chaiscript
{ {
switch (t_oper) switch (t_oper)
{ {
case Operators::Opers::unary_minus: case Operators::unary_minus:
return const_var(-t); return const_var(-t);
case Operators::Opers::unary_plus: case Operators::unary_plus:
return const_var(+t); return const_var(+t);
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
@ -312,14 +306,14 @@ namespace chaiscript
{ {
switch (t_oper) switch (t_oper)
{ {
case Operators::Opers::sum: case Operators::sum:
return const_var(t + u); return const_var(t + u);
case Operators::Opers::quotient: case Operators::quotient:
check_divide_by_zero(u); check_divide_by_zero(u);
return const_var(t / u); return const_var(t / u);
case Operators::Opers::product: case Operators::product:
return const_var(t * u); return const_var(t * u);
case Operators::Opers::difference: case Operators::difference:
return const_var(t - u); return const_var(t - u);
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
@ -331,16 +325,16 @@ namespace chaiscript
-> typename std::enable_if<!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value, Boxed_Value>::type -> typename std::enable_if<!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value, Boxed_Value>::type
{ {
typedef typename std::common_type<LHS, RHS>::type common_type; typedef typename std::common_type<LHS, RHS>::type common_type;
if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag) if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
{ {
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { } else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs); return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
} else if (t_oper > Operators::Opers::non_const_int_flag && t_oper < Operators::Opers::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { } else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return binary_int_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs); return binary_int_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
} else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) { } else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
return const_binary_int_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); return const_binary_int_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else if (t_oper > Operators::Opers::const_flag) { } else if (t_oper > Operators::const_flag) {
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
@ -352,12 +346,12 @@ namespace chaiscript
-> typename std::enable_if<std::is_floating_point<LHS>::value || std::is_floating_point<RHS>::value, Boxed_Value>::type -> typename std::enable_if<std::is_floating_point<LHS>::value || std::is_floating_point<RHS>::value, Boxed_Value>::type
{ {
typedef typename std::common_type<LHS, RHS>::type common_type; typedef typename std::common_type<LHS, RHS>::type common_type;
if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag) if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
{ {
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { } else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs); return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
} else if (t_oper > Operators::Opers::const_flag) { } else if (t_oper > Operators::const_flag) {
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
@ -369,11 +363,11 @@ namespace chaiscript
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs) static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
-> typename std::enable_if<!std::is_floating_point<LHS>::value, Boxed_Value>::type -> typename std::enable_if<!std::is_floating_point<LHS>::value, Boxed_Value>::type
{ {
if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs); return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
} else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) { } else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
return const_unary_int_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr())); return const_unary_int_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
} else if (t_oper > Operators::Opers::const_flag) { } else if (t_oper > Operators::const_flag) {
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr())); return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
@ -384,9 +378,9 @@ namespace chaiscript
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs) static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
-> typename std::enable_if<std::is_floating_point<LHS>::value, Boxed_Value>::type -> typename std::enable_if<std::is_floating_point<LHS>::value, Boxed_Value>::type
{ {
if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs); return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
} else if (t_oper > Operators::Opers::const_flag) { } else if (t_oper > Operators::const_flag) {
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr())); return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
@ -505,15 +499,18 @@ namespace chaiscript
{ {
} }
explicit Boxed_Number(Boxed_Value v) Boxed_Number(Boxed_Value v)
: bv(std::move(v)) : bv(std::move(v))
{ {
validate_boxed_number(bv); validate_boxed_number(bv);
} }
Boxed_Number(const Boxed_Number &) = default; Boxed_Number(const Boxed_Number &) = default;
#if !defined(_MSC_VER) || _MSC_VER != 1800
Boxed_Number(Boxed_Number &&) = default; Boxed_Number(Boxed_Number &&) = default;
Boxed_Number& operator=(Boxed_Number &&) = default; Boxed_Number& operator=(Boxed_Number &&) = default;
#endif
template<typename T> explicit Boxed_Number(T t) template<typename T> explicit Boxed_Number(T t)
: bv(Boxed_Value(t)) : bv(Boxed_Value(t))
@ -588,67 +585,6 @@ namespace chaiscript
} }
template<typename Source, typename Target>
static void check_type()
{
#ifdef CHAISCRIPT_MSVC
// MSVC complains about this being redundant / tautologica l
#pragma warning(push)
#pragma warning(disable : 4127 6287)
#endif
if (sizeof(Source) != sizeof(Target)
|| std::is_signed<Source>() != std::is_signed<Target>()
|| std::is_floating_point<Source>() != std::is_floating_point<Target>())
{
throw chaiscript::detail::exception::bad_any_cast();
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
template<typename Target> Target get_as_checked() const
{
switch (get_common_type(bv)) {
case Common_Types::t_int32:
check_type<int32_t, Target>();
return get_as_aux<Target, int32_t>(bv);
case Common_Types::t_uint8:
check_type<uint8_t, Target>();
return get_as_aux<Target, uint8_t>(bv);
case Common_Types::t_int8:
check_type<int8_t, Target>();
return get_as_aux<Target, int8_t>(bv);
case Common_Types::t_uint16:
check_type<uint16_t, Target>();
return get_as_aux<Target, uint16_t>(bv);
case Common_Types::t_int16:
check_type<int16_t, Target>();
return get_as_aux<Target, int16_t>(bv);
case Common_Types::t_uint32:
check_type<uint32_t, Target>();
return get_as_aux<Target, uint32_t>(bv);
case Common_Types::t_uint64:
check_type<uint64_t, Target>();
return get_as_aux<Target, uint64_t>(bv);
case Common_Types::t_int64:
check_type<int64_t, Target>();
return get_as_aux<Target, int64_t>(bv);
case Common_Types::t_double:
check_type<double, Target>();
return get_as_aux<Target, double>(bv);
case Common_Types::t_float:
check_type<float, Target>();
return get_as_aux<Target, float>(bv);
case Common_Types::t_long_double:
check_type<long double, Target>();
return get_as_aux<Target, long double>(bv);
}
throw chaiscript::detail::exception::bad_any_cast();
}
template<typename Target> Target get_as() const template<typename Target> Target get_as() const
{ {
switch (get_common_type(bv)) { switch (get_common_type(bv)) {
@ -709,6 +645,71 @@ namespace chaiscript
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
bool operator==(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::equals, this->bv, t_rhs.bv));
}
bool operator<(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::less_than, this->bv, t_rhs.bv));
}
bool operator>(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::greater_than, this->bv, t_rhs.bv));
}
bool operator>=(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::greater_than_equal, this->bv, t_rhs.bv));
}
bool operator<=(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::less_than_equal, this->bv, t_rhs.bv));
}
bool operator!=(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::not_equal, this->bv, t_rhs.bv));
}
Boxed_Number operator--()
{
return oper(Operators::pre_decrement, this->bv);
}
Boxed_Number operator++()
{
return oper(Operators::pre_increment, this->bv);
}
Boxed_Number operator+(const Boxed_Number &t_rhs) const
{
return oper(Operators::sum, this->bv, t_rhs.bv);
}
Boxed_Number operator+() const
{
return oper(Operators::unary_plus, this->bv);
}
Boxed_Number operator-() const
{
return oper(Operators::unary_minus, this->bv);
}
Boxed_Number operator-(const Boxed_Number &t_rhs) const
{
return oper(Operators::difference, this->bv, t_rhs.bv);
}
Boxed_Number operator&=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_bitwise_and, this->bv, t_rhs.bv);
}
static void validate_boxed_number(const Boxed_Value &v) static void validate_boxed_number(const Boxed_Value &v)
{ {
const Type_Info &inp_ = v.get_type_info(); const Type_Info &inp_ = v.get_type_info();
@ -723,165 +724,266 @@ namespace chaiscript
} }
} }
// cppcheck-suppress operatorEq
Boxed_Number operator=(const Boxed_Value &v)
{
validate_boxed_number(v);
bv = v;
return *this;
}
// cppcheck-suppress operatorEq
Boxed_Number operator=(const Boxed_Number &t_rhs) const
{
return oper(Operators::assign, this->bv, t_rhs.bv);
}
Boxed_Number operator|=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_bitwise_or, this->bv, t_rhs.bv);
}
Boxed_Number operator^=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_bitwise_xor, this->bv, t_rhs.bv);
}
Boxed_Number operator%=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_remainder, this->bv, t_rhs.bv);
}
Boxed_Number operator<<=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_shift_left, this->bv, t_rhs.bv);
}
Boxed_Number operator>>=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_shift_right, this->bv, t_rhs.bv);
}
Boxed_Number operator&(const Boxed_Number &t_rhs) const
{
return oper(Operators::bitwise_and, this->bv, t_rhs.bv);
}
Boxed_Number operator~() const
{
return oper(Operators::bitwise_complement, this->bv);
}
Boxed_Number operator^(const Boxed_Number &t_rhs) const
{
return oper(Operators::bitwise_xor, this->bv, t_rhs.bv);
}
Boxed_Number operator|(const Boxed_Number &t_rhs) const
{
return oper(Operators::bitwise_or, this->bv, t_rhs.bv);
}
Boxed_Number operator*=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_product, this->bv, t_rhs.bv);
}
Boxed_Number operator/=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_quotient, this->bv, t_rhs.bv);
}
Boxed_Number operator+=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_sum, this->bv, t_rhs.bv);
}
Boxed_Number operator-=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_difference, this->bv, t_rhs.bv);
}
Boxed_Number operator/(const Boxed_Number &t_rhs) const
{
return oper(Operators::quotient, this->bv, t_rhs.bv);
}
Boxed_Number operator<<(const Boxed_Number &t_rhs) const
{
return oper(Operators::shift_left, this->bv, t_rhs.bv);
}
Boxed_Number operator*(const Boxed_Number &t_rhs) const
{
return oper(Operators::product, this->bv, t_rhs.bv);
}
Boxed_Number operator%(const Boxed_Number &t_rhs) const
{
return oper(Operators::remainder, this->bv, t_rhs.bv);
}
Boxed_Number operator>>(const Boxed_Number &t_rhs) const
{
return oper(Operators::shift_right, this->bv, t_rhs.bv);
}
static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return boxed_cast<bool>(oper(Operators::Opers::equals, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::equals, t_lhs.bv, t_rhs.bv));
} }
static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return boxed_cast<bool>(oper(Operators::Opers::less_than, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::less_than, t_lhs.bv, t_rhs.bv));
} }
static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return boxed_cast<bool>(oper(Operators::Opers::greater_than, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::greater_than, t_lhs.bv, t_rhs.bv));
} }
static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return boxed_cast<bool>(oper(Operators::Opers::greater_than_equal, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::greater_than_equal, t_lhs.bv, t_rhs.bv));
} }
static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return boxed_cast<bool>(oper(Operators::Opers::less_than_equal, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::less_than_equal, t_lhs.bv, t_rhs.bv));
} }
static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return boxed_cast<bool>(oper(Operators::Opers::not_equal, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::not_equal, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number pre_decrement(Boxed_Number t_lhs) static Boxed_Number pre_decrement(Boxed_Number t_lhs)
{ {
return Boxed_Number(oper(Operators::Opers::pre_decrement, t_lhs.bv)); return oper(Operators::pre_decrement, t_lhs.bv);
} }
static Boxed_Number pre_increment(Boxed_Number t_lhs) static Boxed_Number pre_increment(Boxed_Number t_lhs)
{ {
return Boxed_Number(oper(Operators::Opers::pre_increment, t_lhs.bv)); return oper(Operators::pre_increment, t_lhs.bv);
} }
static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::sum, t_lhs.bv, t_rhs.bv)); return oper(Operators::sum, t_lhs.bv, t_rhs.bv);
} }
static const Boxed_Number unary_plus(const Boxed_Number &t_lhs) static const Boxed_Number unary_plus(const Boxed_Number &t_lhs)
{ {
return Boxed_Number(oper(Operators::Opers::unary_plus, t_lhs.bv)); return oper(Operators::unary_plus, t_lhs.bv);
} }
static const Boxed_Number unary_minus(const Boxed_Number &t_lhs) static const Boxed_Number unary_minus(const Boxed_Number &t_lhs)
{ {
return Boxed_Number(oper(Operators::Opers::unary_minus, t_lhs.bv)); return oper(Operators::unary_minus, t_lhs.bv);
} }
static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::difference, t_lhs.bv, t_rhs.bv)); return oper(Operators::difference, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_bitwise_and(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_bitwise_and(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_bitwise_and, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_bitwise_and, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_bitwise_or(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_bitwise_or(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_bitwise_or, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_bitwise_or, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_bitwise_xor(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_bitwise_xor(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_bitwise_xor, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_bitwise_xor, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_remainder(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_remainder(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_remainder, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_remainder, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_shift_left(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_shift_left(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_shift_left, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_shift_left, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_shift_right(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_shift_right(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_shift_right, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_shift_right, t_lhs.bv, t_rhs.bv);
} }
static const Boxed_Number bitwise_and(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number bitwise_and(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::bitwise_and, t_lhs.bv, t_rhs.bv)); return oper(Operators::bitwise_and, t_lhs.bv, t_rhs.bv);
} }
static const Boxed_Number bitwise_complement(const Boxed_Number &t_lhs) static const Boxed_Number bitwise_complement(const Boxed_Number &t_lhs)
{ {
return Boxed_Number(oper(Operators::Opers::bitwise_complement, t_lhs.bv, Boxed_Value(0))); return oper(Operators::bitwise_complement, t_lhs.bv, Boxed_Value(0));
} }
static const Boxed_Number bitwise_xor(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number bitwise_xor(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::bitwise_xor, t_lhs.bv, t_rhs.bv)); return oper(Operators::bitwise_xor, t_lhs.bv, t_rhs.bv);
} }
static const Boxed_Number bitwise_or(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number bitwise_or(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::bitwise_or, t_lhs.bv, t_rhs.bv)); return oper(Operators::bitwise_or, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_product(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_product(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_product, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_product, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_quotient(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_quotient(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_quotient, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_quotient, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_sum(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_sum(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_sum, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_sum, t_lhs.bv, t_rhs.bv);
} }
static Boxed_Number assign_difference(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_difference(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::assign_difference, t_lhs.bv, t_rhs.bv)); return oper(Operators::assign_difference, t_lhs.bv, t_rhs.bv);
} }
static const Boxed_Number quotient(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number quotient(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::quotient, t_lhs.bv, t_rhs.bv)); return oper(Operators::quotient, t_lhs.bv, t_rhs.bv);
} }
static const Boxed_Number shift_left(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number shift_left(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::shift_left, t_lhs.bv, t_rhs.bv)); return oper(Operators::shift_left, t_lhs.bv, t_rhs.bv);
} }
static const Boxed_Number product(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number product(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::product, t_lhs.bv, t_rhs.bv)); return oper(Operators::product, t_lhs.bv, t_rhs.bv);
} }
static const Boxed_Number remainder(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number remainder(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::remainder, t_lhs.bv, t_rhs.bv)); return oper(Operators::remainder, t_lhs.bv, t_rhs.bv);
} }
static const Boxed_Number shift_right(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number shift_right(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{ {
return Boxed_Number(oper(Operators::Opers::shift_right, t_lhs.bv, t_rhs.bv)); return oper(Operators::shift_right, t_lhs.bv, t_rhs.bv);
} }
@ -907,7 +1009,9 @@ namespace chaiscript
template<> template<>
struct Cast_Helper<Boxed_Number> struct Cast_Helper<Boxed_Number>
{ {
static Boxed_Number cast(const Boxed_Value &ob, const Type_Conversions_State *) typedef Boxed_Number Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return Boxed_Number(ob); return Boxed_Number(ob);
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_ #ifndef CHAISCRIPT_BOXED_VALUE_HPP_
#define CHAISCRIPT_BOXED_VALUE_HPP_ #define CHAISCRIPT_BOXED_VALUE_HPP_
@ -39,11 +35,11 @@ namespace chaiscript
{ {
Data(const Type_Info &ti, Data(const Type_Info &ti,
chaiscript::detail::Any to, chaiscript::detail::Any to,
bool is_ref, bool tr,
const void *t_void_ptr, const void *t_void_ptr,
bool t_return_value) bool t_return_value)
: m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr), : m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
m_is_ref(is_ref), m_return_value(t_return_value) m_is_ref(tr), m_return_value(t_return_value)
{ {
} }
@ -58,7 +54,7 @@ namespace chaiscript
if (rhs.m_attrs) if (rhs.m_attrs)
{ {
m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs); m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*rhs.m_attrs));
} }
return *this; return *this;
@ -66,8 +62,10 @@ namespace chaiscript
Data(const Data &) = delete; Data(const Data &) = delete;
#if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER != 1800)
Data(Data &&) = default; Data(Data &&) = default;
Data &operator=(Data &&rhs) = default; Data &operator=(Data &&rhs) = default;
#endif
Type_Info m_type_info; Type_Info m_type_info;
@ -81,7 +79,7 @@ namespace chaiscript
struct Object_Data struct Object_Data
{ {
static auto get(Boxed_Value::Void_Type, bool t_return_value) static std::shared_ptr<Data> get(Boxed_Value::Void_Type, bool t_return_value)
{ {
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(), detail::Get_Type_Info<void>::get(),
@ -93,13 +91,13 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj, bool t_return_value)
{ {
return get(*obj, t_return_value); return get(*obj, t_return_value);
} }
template<typename T> template<typename T>
static auto get(const std::shared_ptr<T> &obj, bool t_return_value) static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj, bool t_return_value)
{ {
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
@ -111,7 +109,7 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static auto get(std::shared_ptr<T> &&obj, bool t_return_value) static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj, bool t_return_value)
{ {
auto ptr = obj.get(); auto ptr = obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(
@ -123,23 +121,21 @@ namespace chaiscript
); );
} }
template<typename T> template<typename T>
static auto get(T *t, bool t_return_value) static std::shared_ptr<Data> get(T *t, bool t_return_value)
{ {
return get(std::ref(*t), t_return_value); return get(std::ref(*t), t_return_value);
} }
template<typename T> template<typename T>
static auto get(const T *t, bool t_return_value) static std::shared_ptr<Data> get(const T *t, bool t_return_value)
{ {
return get(std::cref(*t), t_return_value); return get(std::cref(*t), t_return_value);
} }
template<typename T> template<typename T>
static auto get(std::reference_wrapper<T> obj, bool t_return_value) static std::shared_ptr<Data> get(std::reference_wrapper<T> obj, bool t_return_value)
{ {
auto p = &obj.get(); auto p = &obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(
@ -152,20 +148,7 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static auto get(std::unique_ptr<T> &&obj, bool t_return_value) static std::shared_ptr<Data> get(T t, bool t_return_value)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
true,
ptr,
t_return_value
);
}
template<typename T>
static auto get(T t, bool t_return_value)
{ {
auto p = std::make_shared<T>(std::move(t)); auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get(); auto ptr = p.get();
@ -201,10 +184,16 @@ namespace chaiscript
} }
/// Unknown-type constructor /// Unknown-type constructor
Boxed_Value() = default; Boxed_Value()
: m_data(Object_Data::get())
{
}
#if !defined(_MSC_VER) || _MSC_VER != 1800
Boxed_Value(Boxed_Value&&) = default; Boxed_Value(Boxed_Value&&) = default;
Boxed_Value& operator=(Boxed_Value&&) = default; Boxed_Value& operator=(Boxed_Value&&) = default;
#endif
Boxed_Value(const Boxed_Value&) = default; Boxed_Value(const Boxed_Value&) = default;
Boxed_Value& operator=(const Boxed_Value&) = default; Boxed_Value& operator=(const Boxed_Value&) = default;
@ -221,99 +210,63 @@ namespace chaiscript
return *this; return *this;
} }
const Type_Info &get_type_info() const noexcept const Type_Info &get_type_info() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info; return m_data->m_type_info;
} }
/// return true if the object is uninitialized /// return true if the object is uninitialized
bool is_undef() const noexcept bool is_undef() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.is_undef(); return m_data->m_type_info.is_undef();
} }
bool is_const() const noexcept bool is_const() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.is_const(); return m_data->m_type_info.is_const();
} }
bool is_type(const Type_Info &ti) const noexcept bool is_type(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.bare_equal(ti); return m_data->m_type_info.bare_equal(ti);
} }
bool is_null() const CHAISCRIPT_NOEXCEPT
template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const
{
struct Sentinel {
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
: m_ptr(t_ptr), m_data(data)
{
}
~Sentinel()
{
// save new pointer data
const auto ptr_ = m_ptr.get().get();
m_data.get().m_data_ptr = ptr_;
m_data.get().m_const_data_ptr = ptr_;
}
Sentinel& operator=(Sentinel&&s) = default;
Sentinel(Sentinel &&s) = default;
operator std::shared_ptr<T>&() const
{
return m_ptr.get();
}
Sentinel &operator=(const Sentinel &) = delete;
Sentinel(Sentinel&) = delete;
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
std::reference_wrapper<Data> m_data;
};
return Sentinel(ptr, *(m_data.get()));
}
bool is_null() const noexcept
{ {
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
} }
const chaiscript::detail::Any & get() const noexcept const chaiscript::detail::Any & get() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_obj; return m_data->m_obj;
} }
bool is_ref() const noexcept bool is_ref() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_is_ref; return m_data->m_is_ref;
} }
bool is_return_value() const noexcept bool is_return_value() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_return_value; return m_data->m_return_value;
} }
void reset_return_value() const noexcept void reset_return_value() const CHAISCRIPT_NOEXCEPT
{ {
m_data->m_return_value = false; m_data->m_return_value = false;
} }
bool is_pointer() const noexcept bool is_pointer() const CHAISCRIPT_NOEXCEPT
{ {
return !is_ref(); return !is_ref();
} }
void *get_ptr() const noexcept void *get_ptr() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_data_ptr; return m_data->m_data_ptr;
} }
const void *get_const_ptr() const noexcept const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_const_data_ptr; return m_data->m_const_data_ptr;
} }
@ -322,7 +275,7 @@ namespace chaiscript
{ {
if (!m_data->m_attrs) if (!m_data->m_attrs)
{ {
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(); m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>());
} }
auto &attr = (*m_data->m_attrs)[t_name]; auto &attr = (*m_data->m_attrs)[t_name];
@ -339,7 +292,7 @@ namespace chaiscript
{ {
if (t_obj.m_data->m_attrs) if (t_obj.m_data->m_attrs)
{ {
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs); m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*t_obj.m_data->m_attrs));
} }
return *this; return *this;
} }
@ -353,7 +306,7 @@ namespace chaiscript
/// \returns true if the two Boxed_Values share the same internal type /// \returns true if the two Boxed_Values share the same internal type
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT
{ {
return l.get_type_info() == r.get_type_info(); return l.get_type_info() == r.get_type_info();
} }
@ -362,11 +315,11 @@ namespace chaiscript
// necessary to avoid hitting the templated && constructor of Boxed_Value // necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction{}; struct Internal_Construction{};
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction) Boxed_Value(const std::shared_ptr<Data> &t_data, Internal_Construction)
: m_data(std::move(t_data)) { : m_data(t_data) {
} }
std::shared_ptr<Data> m_data = Object_Data::get(); std::shared_ptr<Data> m_data;
}; };
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type /// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
@ -463,14 +416,10 @@ namespace chaiscript
return detail::const_var_impl(t); return detail::const_var_impl(t);
} }
inline Boxed_Value void_var() { #ifdef CHAISCRIPT_HAS_MAGIC_STATICS
static const auto v = Boxed_Value(Boxed_Value::Void_Type());
return v;
}
inline Boxed_Value const_var(bool b) { inline Boxed_Value const_var(bool b) {
static const auto t = detail::const_var_impl(true); static auto t = detail::const_var_impl(true);
static const auto f = detail::const_var_impl(false); static auto f = detail::const_var_impl(false);
if (b) { if (b) {
return t; return t;
@ -478,6 +427,7 @@ namespace chaiscript
return f; return f;
} }
} }
#endif
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_ #ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
@ -25,7 +25,7 @@ namespace chaiscript {
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename ... Param>
struct Const_Caller struct Const_Caller
{ {
explicit Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {} Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
template<typename ... Inner> template<typename ... Inner>
Ret operator()(const Class &o, Inner&& ... inner) const { Ret operator()(const Class &o, Inner&& ... inner) const {
@ -38,7 +38,7 @@ namespace chaiscript {
template<typename Ret, typename ... Param> template<typename Ret, typename ... Param>
struct Fun_Caller struct Fun_Caller
{ {
explicit Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {} Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
template<typename ... Inner> template<typename ... Inner>
Ret operator()(Inner&& ... inner) const { Ret operator()(Inner&& ... inner) const {
@ -51,7 +51,7 @@ namespace chaiscript {
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename ... Param>
struct Caller struct Caller
{ {
explicit Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {} Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
template<typename ... Inner> template<typename ... Inner>
Ret operator()(Class &o, Inner&& ... inner) const { Ret operator()(Class &o, Inner&& ... inner) const {

View File

@ -1,17 +1,14 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DISPATCHKIT_HPP_ #ifndef CHAISCRIPT_DISPATCHKIT_HPP_
#define CHAISCRIPT_DISPATCHKIT_HPP_ #define CHAISCRIPT_DISPATCHKIT_HPP_
#include <algorithm> #include <algorithm>
#include <deque>
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <map> #include <map>
@ -34,16 +31,12 @@
#include "proxy_constructors.hpp" #include "proxy_constructors.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "short_alloc.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Number; class Boxed_Number;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript { namespace chaiscript {
namespace parser {
class ChaiScript_Parser_Base;
}
namespace dispatch { namespace dispatch {
class Dynamic_Proxy_Function; class Dynamic_Proxy_Function;
class Proxy_Function_Base; class Proxy_Function_Base;
@ -52,7 +45,6 @@ struct Placeholder_Object;
} // namespace chaiscript } // namespace chaiscript
/// \namespace chaiscript::dispatch /// \namespace chaiscript::dispatch
/// \brief Classes and functions specific to the runtime dispatch side of ChaiScript. Some items may be of use to the end user. /// \brief Classes and functions specific to the runtime dispatch side of ChaiScript. Some items may be of use to the end user.
@ -64,14 +56,14 @@ namespace chaiscript
class reserved_word_error : public std::runtime_error class reserved_word_error : public std::runtime_error
{ {
public: public:
explicit reserved_word_error(const std::string &t_word) noexcept reserved_word_error(const std::string &t_word) CHAISCRIPT_NOEXCEPT
: std::runtime_error("Reserved word not allowed in object name: " + t_word), m_word(t_word) : std::runtime_error("Reserved word not allowed in object name: " + t_word), m_word(t_word)
{ {
} }
reserved_word_error(const reserved_word_error &) = default; reserved_word_error(const reserved_word_error &) = default;
~reserved_word_error() noexcept override = default; virtual ~reserved_word_error() CHAISCRIPT_NOEXCEPT {}
std::string word() const std::string word() const
{ {
@ -86,14 +78,14 @@ namespace chaiscript
class illegal_name_error : public std::runtime_error class illegal_name_error : public std::runtime_error
{ {
public: public:
explicit illegal_name_error(const std::string &t_name) noexcept illegal_name_error(const std::string &t_name) CHAISCRIPT_NOEXCEPT
: std::runtime_error("Reserved name not allowed in object name: " + t_name), m_name(t_name) : std::runtime_error("Reserved name not allowed in object name: " + t_name), m_name(t_name)
{ {
} }
illegal_name_error(const illegal_name_error &) = default; illegal_name_error(const illegal_name_error &) = default;
~illegal_name_error() noexcept override = default; virtual ~illegal_name_error() CHAISCRIPT_NOEXCEPT {}
std::string name() const std::string name() const
{ {
@ -109,14 +101,14 @@ namespace chaiscript
class name_conflict_error : public std::runtime_error class name_conflict_error : public std::runtime_error
{ {
public: public:
explicit name_conflict_error(const std::string &t_name) noexcept name_conflict_error(const std::string &t_name) CHAISCRIPT_NOEXCEPT
: std::runtime_error("Name already exists in current context " + t_name), m_name(t_name) : std::runtime_error("Name already exists in current context " + t_name), m_name(t_name)
{ {
} }
name_conflict_error(const name_conflict_error &) = default; name_conflict_error(const name_conflict_error &) = default;
~name_conflict_error() noexcept override = default; virtual ~name_conflict_error() CHAISCRIPT_NOEXCEPT {}
std::string name() const std::string name() const
{ {
@ -133,13 +125,13 @@ namespace chaiscript
class global_non_const : public std::runtime_error class global_non_const : public std::runtime_error
{ {
public: public:
global_non_const() noexcept global_non_const() CHAISCRIPT_NOEXCEPT
: std::runtime_error("a global object must be const") : std::runtime_error("a global object must be const")
{ {
} }
global_non_const(const global_non_const &) = default; global_non_const(const global_non_const &) = default;
~global_non_const() noexcept override = default; virtual ~global_non_const() CHAISCRIPT_NOEXCEPT {}
}; };
} }
@ -151,7 +143,7 @@ namespace chaiscript
public: public:
Module &add(Type_Info ti, std::string name) Module &add(Type_Info ti, std::string name)
{ {
m_typeinfos.emplace_back(ti, std::move(name)); m_typeinfos.emplace_back(std::move(ti), std::move(name));
return *this; return *this;
} }
@ -186,6 +178,12 @@ namespace chaiscript
return *this; return *this;
} }
Module &add(const std::shared_ptr<Module> &m)
{
m->apply(*this, *this);
return *m;
}
template<typename Eval, typename Engine> template<typename Eval, typename Engine>
void apply(Eval &t_eval, Engine &t_engine) const void apply(Eval &t_eval, Engine &t_engine) const
{ {
@ -196,28 +194,30 @@ namespace chaiscript
apply_globals(m_globals.begin(), m_globals.end(), t_engine); apply_globals(m_globals.begin(), m_globals.end(), t_engine);
} }
~Module()
{
}
bool has_function(const Proxy_Function &new_f, const std::string &name) bool has_function(const Proxy_Function &new_f, const std::string &name)
{ {
return std::any_of(m_funcs.begin(), m_funcs.end(), return std::any_of(m_funcs.begin(), m_funcs.end(), [&](const std::pair<Proxy_Function, std::string> &existing_f) {
[&](const std::pair<Proxy_Function, std::string> &existing_f) {
return existing_f.second == name && *(existing_f.first) == *(new_f); return existing_f.second == name && *(existing_f.first) == *(new_f);
} });
);
} }
private: private:
std::vector<std::pair<Type_Info, std::string>> m_typeinfos; std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
std::vector<std::pair<Proxy_Function, std::string>> m_funcs; std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
std::vector<std::pair<Boxed_Value, std::string>> m_globals; std::vector<std::pair<Boxed_Value, std::string> > m_globals;
std::vector<std::string> m_evals; std::vector<std::string> m_evals;
std::vector<Type_Conversion> m_conversions; std::vector<Type_Conversion> m_conversions;
template<typename T, typename InItr> template<typename T, typename InItr>
static void apply(InItr begin, const InItr end, T &t) static void apply(InItr begin, const InItr end, T &t)
{ {
for_each(begin, end, for_each(begin, end, [&t](typename std::iterator_traits<InItr>::reference obj)
[&t](const auto &obj) { {
try { try {
t.add(obj.first, obj.second); t.add(obj.first, obj.second);
} catch (const chaiscript::exception::name_conflict_error &) { } catch (const chaiscript::exception::name_conflict_error &) {
@ -267,16 +267,16 @@ namespace chaiscript
/// A Proxy_Function implementation that is able to take /// A Proxy_Function implementation that is able to take
/// a vector of Proxy_Functions and perform a dispatch on them. It is /// a vector of Proxy_Functions and perform a dispatch on them. It is
/// used specifically in the case of dealing with Function object variables /// used specifically in the case of dealing with Function object variables
class Dispatch_Function final : public dispatch::Proxy_Function_Base class Dispatch_Function : public dispatch::Proxy_Function_Base
{ {
public: public:
explicit Dispatch_Function(std::vector<Proxy_Function> t_funcs) Dispatch_Function(std::vector<Proxy_Function> t_funcs)
: Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)), : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)),
m_funcs(std::move(t_funcs)) m_funcs(std::move(t_funcs))
{ {
} }
bool operator==(const dispatch::Proxy_Function_Base &rhs) const override virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE
{ {
try { try {
const auto &dispatch_fun = dynamic_cast<const Dispatch_Function &>(rhs); const auto &dispatch_fun = dynamic_cast<const Dispatch_Function &>(rhs);
@ -286,7 +286,9 @@ namespace chaiscript
} }
} }
std::vector<Const_Proxy_Function> get_contained_functions() const override virtual ~Dispatch_Function() {}
virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
{ {
return std::vector<Const_Proxy_Function>(m_funcs.begin(), m_funcs.end()); return std::vector<Const_Proxy_Function>(m_funcs.begin(), m_funcs.end());
} }
@ -312,14 +314,19 @@ namespace chaiscript
return arity; return arity;
} }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return std::any_of(std::begin(m_funcs), std::end(m_funcs), return std::any_of(m_funcs.cbegin(), m_funcs.cend(),
[&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); }); [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return "Multiple method dispatch function wrapper.";
}
protected: protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return dispatch::dispatch(m_funcs, params, t_conversions); return dispatch::dispatch(m_funcs, params, t_conversions);
} }
@ -360,7 +367,7 @@ namespace chaiscript
++begin; ++begin;
} }
assert(!type_infos.empty() && " type_info vector size is < 0, this is only possible if something else is broken"); assert(type_infos.size() > 0 && " type_info vector size is < 0, this is only possible if something else is broken");
if (size_mismatch) if (size_mismatch)
{ {
@ -380,56 +387,22 @@ namespace chaiscript
{ {
struct Stack_Holder struct Stack_Holder
{ {
//template <class T, std::size_t BufSize = sizeof(T)*20000> typedef std::vector<std::pair<std::string, Boxed_Value>> Scope;
// using SmallVector = std::vector<T, short_alloc<T, BufSize>>; typedef std::vector<Scope> StackData;
template <class T>
using SmallVector = std::vector<T>;
typedef SmallVector<std::pair<std::string, Boxed_Value>> Scope;
typedef SmallVector<Scope> StackData;
typedef SmallVector<StackData> Stacks;
typedef SmallVector<Boxed_Value> Call_Param_List;
typedef SmallVector<Call_Param_List> Call_Params;
Stack_Holder() Stack_Holder()
: call_depth(0)
{ {
push_stack(); stacks.reserve(2);
push_call_params();
}
void push_stack_data()
{
stacks.back().emplace_back();
// stacks.back().emplace_back(Scope(scope_allocator));
}
void push_stack()
{
stacks.emplace_back(1); stacks.emplace_back(1);
// stacks.emplace_back(StackData(1, Scope(scope_allocator), stack_data_allocator));
}
void push_call_params()
{
call_params.emplace_back(); call_params.emplace_back();
// call_params.emplace_back(Call_Param_List(call_param_list_allocator)); call_params.back().reserve(2);
} }
//Scope::allocator_type::arena_type scope_allocator; std::vector<StackData> stacks;
//StackData::allocator_type::arena_type stack_data_allocator;
//Stacks::allocator_type::arena_type stacks_allocator;
//Call_Param_List::allocator_type::arena_type call_param_list_allocator;
//Call_Params::allocator_type::arena_type call_params_allocator;
// Stacks stacks = Stacks(stacks_allocator); std::vector<std::vector<Boxed_Value>> call_params;
// Call_Params call_params = Call_Params(call_params_allocator); int call_depth;
Stacks stacks;
Call_Params call_params;
int call_depth = 0;
}; };
/// Main class for the dispatchkit. Handles management /// Main class for the dispatchkit. Handles management
@ -440,7 +413,7 @@ namespace chaiscript
public: public:
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map; typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::vector<std::pair<std::string, Boxed_Value>> Scope; typedef std::vector<std::pair<std::string, Boxed_Value>> Scope;
typedef Stack_Holder::StackData StackData; typedef std::vector<Scope> StackData;
struct State struct State
{ {
@ -449,20 +422,27 @@ namespace chaiscript
std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions; std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions;
std::map<std::string, Boxed_Value> m_global_objects; std::map<std::string, Boxed_Value> m_global_objects;
Type_Name_Map m_types; Type_Name_Map m_types;
std::set<std::string> m_reserved_words;
State &operator=(const State &) = default;
State() = default;
State(const State &) = default;
}; };
explicit Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser) Dispatch_Engine()
: m_stack_holder(), : m_stack_holder(this)
m_parser(parser) {
}
~Dispatch_Engine()
{ {
} }
/// \brief casts an object while applying any Dynamic_Conversion available /// \brief casts an object while applying any Dynamic_Conversion available
template<typename Type> template<typename Type>
decltype(auto) boxed_cast(const Boxed_Value &bv) const typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
{ {
Type_Conversions_State state(m_conversions, m_conversions.conversion_saves()); return chaiscript::boxed_cast<Type>(bv, &m_conversions);
return(chaiscript::boxed_cast<Type>(bv, &state));
} }
/// Add a new conversion for upcasting to a base class /// Add a new conversion for upcasting to a base class
@ -474,6 +454,7 @@ namespace chaiscript
/// Add a new named Proxy_Function to the system /// Add a new named Proxy_Function to the system
void add(const Proxy_Function &f, const std::string &name) void add(const Proxy_Function &f, const std::string &name)
{ {
validate_object_name(name);
add_function(f, name); add_function(f, name);
} }
@ -481,6 +462,7 @@ namespace chaiscript
/// is not available in the current scope it is created /// is not available in the current scope it is created
void add(Boxed_Value obj, const std::string &name) void add(Boxed_Value obj, const std::string &name)
{ {
validate_object_name(name);
auto &stack = get_stack_data(); auto &stack = get_stack_data();
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
@ -500,26 +482,6 @@ namespace chaiscript
add_object(name, std::move(obj)); add_object(name, std::move(obj));
} }
/// Adds a named object to the current scope
/// \warning This version does not check the validity of the name
/// it is meant for internal use only
Boxed_Value &add_get_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder)
{
auto &stack_elem = get_stack_data(t_holder).back();
if (std::any_of(stack_elem.begin(), stack_elem.end(),
[&](const std::pair<std::string, Boxed_Value> &o) {
return o.first == t_name;
}))
{
throw chaiscript::exception::name_conflict_error(t_name);
}
stack_elem.emplace_back(t_name, std::move(obj));
return stack_elem.back().second;
}
/// Adds a named object to the current scope /// Adds a named object to the current scope
/// \warning This version does not check the validity of the name /// \warning This version does not check the validity of the name
/// it is meant for internal use only /// it is meant for internal use only
@ -535,7 +497,7 @@ namespace chaiscript
throw chaiscript::exception::name_conflict_error(t_name); throw chaiscript::exception::name_conflict_error(t_name);
} }
stack_elem.emplace_back(t_name, std::move(obj)); get_stack_data(t_holder).back().emplace_back(t_name, std::move(obj));
} }
@ -550,6 +512,7 @@ namespace chaiscript
/// Adds a new global shared object, between all the threads /// Adds a new global shared object, between all the threads
void add_global_const(const Boxed_Value &obj, const std::string &name) void add_global_const(const Boxed_Value &obj, const std::string &name)
{ {
validate_object_name(name);
if (!obj.is_const()) if (!obj.is_const())
{ {
throw chaiscript::exception::global_non_const(); throw chaiscript::exception::global_non_const();
@ -568,6 +531,8 @@ namespace chaiscript
/// Adds a new global (non-const) shared object, between all the threads /// Adds a new global (non-const) shared object, between all the threads
Boxed_Value add_global_no_throw(const Boxed_Value &obj, const std::string &name) Boxed_Value add_global_no_throw(const Boxed_Value &obj, const std::string &name)
{ {
validate_object_name(name);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto itr = m_state.m_global_objects.find(name); const auto itr = m_state.m_global_objects.find(name);
@ -584,6 +549,8 @@ namespace chaiscript
/// Adds a new global (non-const) shared object, between all the threads /// Adds a new global (non-const) shared object, between all the threads
void add_global(const Boxed_Value &obj, const std::string &name) void add_global(const Boxed_Value &obj, const std::string &name)
{ {
validate_object_name(name);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
@ -594,19 +561,6 @@ namespace chaiscript
} }
} }
/// Updates an existing global shared object or adds a new global shared object if not found
void set_global(const Boxed_Value &obj, const std::string &name)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto itr = m_state.m_global_objects.find(name);
if (itr != m_state.m_global_objects.end())
{
itr->second.assign(obj);
} else {
m_state.m_global_objects.insert(std::make_pair(name, obj));
}
}
/// Adds a new scope to the stack /// Adds a new scope to the stack
void new_scope() void new_scope()
@ -621,32 +575,34 @@ namespace chaiscript
} }
/// Adds a new scope to the stack /// Adds a new scope to the stack
static void new_scope(Stack_Holder &t_holder) void new_scope(Stack_Holder &t_holder)
{ {
t_holder.push_stack_data(); get_stack_data(t_holder).emplace_back();
t_holder.push_call_params(); t_holder.call_params.emplace_back();
} }
/// Pops the current scope from the stack /// Pops the current scope from the stack
static void pop_scope(Stack_Holder &t_holder) void pop_scope(Stack_Holder &t_holder)
{ {
t_holder.call_params.pop_back(); t_holder.call_params.pop_back();
StackData &stack = get_stack_data(t_holder); StackData &stack = get_stack_data(t_holder);
if (stack.size() > 1)
assert(!stack.empty()); {
stack.pop_back(); stack.pop_back();
} else {
throw std::range_error("Unable to pop global stack");
}
} }
/// Pushes a new stack on to the list of stacks /// Pushes a new stack on to the list of stacks
static void new_stack(Stack_Holder &t_holder) void new_stack(Stack_Holder &t_holder)
{ {
// add a new Stack with 1 element // add a new Stack with 1 element
t_holder.push_stack(); t_holder.stacks.emplace_back(1);
} }
static void pop_stack(Stack_Holder &t_holder) void pop_stack(Stack_Holder &t_holder)
{ {
t_holder.stacks.pop_back(); t_holder.stacks.pop_back();
} }
@ -654,7 +610,7 @@ namespace chaiscript
/// Searches the current stack for an object of the given name /// Searches the current stack for an object of the given name
/// includes a special overload for the _ place holder object to /// includes a special overload for the _ place holder object to
/// ensure that it is always in scope. /// ensure that it is always in scope.
Boxed_Value get_object(const std::string &name, std::atomic_uint_fast32_t &t_loc, Stack_Holder &t_holder) const Boxed_Value get_object(const std::string &name, std::atomic_uint_fast32_t &t_loc) const
{ {
enum class Loc : uint_fast32_t { enum class Loc : uint_fast32_t {
located = 0x80000000, located = 0x80000000,
@ -663,11 +619,11 @@ namespace chaiscript
loc_mask = 0x0000FFFF loc_mask = 0x0000FFFF
}; };
uint_fast32_t loc = t_loc; uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
if (loc == 0) if (loc == 0)
{ {
auto &stack = get_stack_data(t_holder); auto &stack = get_stack_data();
// Is it in the stack? // Is it in the stack?
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
@ -675,18 +631,19 @@ namespace chaiscript
for (auto s = stack_elem->begin(); s != stack_elem->end(); ++s ) for (auto s = stack_elem->begin(); s != stack_elem->end(); ++s )
{ {
if (s->first == name) { if (s->first == name) {
t_loc = static_cast<uint_fast32_t>(std::distance(stack.rbegin(), stack_elem) << 16) t_loc.store( static_cast<uint_fast32_t>(std::distance(stack.rbegin(), stack_elem) << 16)
| static_cast<uint_fast32_t>(std::distance(stack_elem->begin(), s)) | static_cast<uint_fast32_t>(std::distance(stack_elem->begin(), s))
| static_cast<uint_fast32_t>(Loc::located) | static_cast<uint_fast32_t>(Loc::located)
| static_cast<uint_fast32_t>(Loc::is_local); | static_cast<uint_fast32_t>(Loc::is_local),
std::memory_order_relaxed);
return s->second; return s->second;
} }
} }
} }
t_loc = static_cast<uint_fast32_t>(Loc::located); t_loc.store( static_cast<uint_fast32_t>(Loc::located), std::memory_order_relaxed);
} else if ((loc & static_cast<uint_fast32_t>(Loc::is_local)) != 0u) { } else if (loc & static_cast<uint_fast32_t>(Loc::is_local)) {
auto &stack = get_stack_data(t_holder); auto &stack = get_stack_data();
return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second; return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second;
} }
@ -702,10 +659,10 @@ namespace chaiscript
// no? is it a function object? // no? is it a function object?
auto obj = get_function_object_int(name, loc); auto obj = get_function_object_int(name, loc);
if (obj.first != loc) { t_loc = uint_fast32_t(obj.first); } if (obj.first != loc) t_loc.store(uint_fast32_t(obj.first), std::memory_order_relaxed);
return obj.second; return obj.second;
} }
/// Registers a new named type /// Registers a new named type
@ -765,12 +722,9 @@ namespace chaiscript
std::shared_ptr<std::vector<Proxy_Function>> get_method_missing_functions() const std::shared_ptr<std::vector<Proxy_Function>> get_method_missing_functions() const
{ {
uint_fast32_t method_missing_loc = m_method_missing_loc; uint_fast32_t method_missing_loc = m_method_missing_loc.load(std::memory_order_relaxed);
auto method_missing_funs = get_function("method_missing", method_missing_loc); auto method_missing_funs = get_function("method_missing", method_missing_loc);
if (method_missing_funs.first != method_missing_loc) { if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(uint_fast32_t(method_missing_funs.first), std::memory_order_relaxed);
m_method_missing_loc = uint_fast32_t(method_missing_funs.first);
}
return std::move(method_missing_funs.second); return std::move(method_missing_funs.second);
} }
@ -858,7 +812,7 @@ namespace chaiscript
{ {
auto &stack = get_stack_data(); auto &stack = get_stack_data();
auto &scope = stack.front(); auto &scope = stack.front();
scope.assign(t_locals.begin(), t_locals.end()); scope = std::vector<std::pair<std::string, Boxed_Value>>(t_locals.begin(), t_locals.end());
} }
@ -929,25 +883,34 @@ namespace chaiscript
return rets; return rets;
} }
void add_reserved_word(const std::string &name)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_state.m_reserved_words.insert(name);
}
const Type_Conversions &conversions() const const Type_Conversions &conversions() const
{ {
return m_conversions; return m_conversions;
} }
static bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const std::vector<Boxed_Value> &t_params, bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const std::vector<Boxed_Value> &t_params,
bool t_has_params, const Type_Conversions_State &t_conversions) bool t_has_params) const
{ {
if (!t_has_params || t_params.empty()) { if (!t_has_params || t_params.empty()) {
return false; return false;
} }
return std::any_of(std::begin(t_funs), std::end(t_funs), for (const auto &fun : t_funs) {
[&](const auto &fun) { if (fun->is_attribute_function()) {
return fun->is_attribute_function() && fun->compare_first_type(t_params[0], t_conversions); if (fun->compare_first_type(t_params[0], m_conversions)) {
return true;
}
}
} }
);
return false;
} }
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
@ -956,15 +919,14 @@ namespace chaiscript
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4715) #pragma warning(disable : 4715)
#endif #endif
Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> &params, bool t_has_params, Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> &params, bool t_has_params)
const Type_Conversions_State &t_conversions)
{ {
uint_fast32_t loc = t_loc; uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
const auto funs = get_function(t_name, loc); const auto funs = get_function(t_name, loc);
if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); } if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed);
const auto do_attribute_call = const auto do_attribute_call =
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value [this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions &l_conversions)->Boxed_Value
{ {
std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params}; std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params};
Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions);
@ -984,34 +946,27 @@ namespace chaiscript
This_Foist fi(*this, l_params.front()); This_Foist fi(*this, l_params.front());
try { auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv);
auto func = boxed_cast<const dispatch::Proxy_Function_Base *>(bv);
try { try {
return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions); return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions);
} catch (const chaiscript::exception::bad_boxed_cast &) { } catch (const chaiscript::exception::bad_boxed_cast &) {
} catch (const chaiscript::exception::arity_error &) { } catch (const chaiscript::exception::arity_error &) {
} catch (const chaiscript::exception::guard_error &) { } catch (const chaiscript::exception::guard_error &) {
} }
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector<Const_Proxy_Function>{func});
std::vector<Const_Proxy_Function>{boxed_cast<Const_Proxy_Function>(bv)});
} catch (const chaiscript::exception::bad_boxed_cast &) {
// unable to convert bv into a Proxy_Function_Base
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()},
std::vector<Const_Proxy_Function>(l_funs.begin(), l_funs.end()));
}
} else { } else {
return bv; return bv;
} }
}; };
if (is_attribute_call(*funs.second, params, t_has_params, t_conversions)) { if (is_attribute_call(*funs.second, params, t_has_params)) {
return do_attribute_call(1, params, *funs.second, t_conversions); return do_attribute_call(1, params, *funs.second, m_conversions);
} else { } else {
std::exception_ptr except; std::exception_ptr except;
if (!funs.second->empty()) { if (!funs.second->empty()) {
try { try {
return dispatch::dispatch(*funs.second, params, t_conversions); return dispatch::dispatch(*funs.second, params, m_conversions);
} catch(chaiscript::exception::dispatch_error&) { } catch(chaiscript::exception::dispatch_error&) {
except = std::current_exception(); except = std::current_exception();
} }
@ -1027,7 +982,7 @@ namespace chaiscript
for (const auto &f : *method_missing_funs) for (const auto &f : *method_missing_funs)
{ {
if(f->compare_first_type(params[0], t_conversions)) { if(f->compare_first_type(params[0], m_conversions)) {
fs.push_back(f); fs.push_back(f);
} }
} }
@ -1051,9 +1006,9 @@ namespace chaiscript
if (is_no_param) { if (is_no_param) {
std::vector<Boxed_Value> tmp_params(params); std::vector<Boxed_Value> tmp_params(params);
tmp_params.insert(tmp_params.begin() + 1, var(t_name)); tmp_params.insert(tmp_params.begin() + 1, var(t_name));
return do_attribute_call(2, tmp_params, functions, t_conversions); return do_attribute_call(2, tmp_params, functions, m_conversions);
} else { } else {
return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, t_conversions); return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, m_conversions);
} }
} catch (const dispatch::option_explicit_set &e) { } catch (const dispatch::option_explicit_set &e) {
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()), throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()),
@ -1076,14 +1031,12 @@ namespace chaiscript
Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> &params, Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> &params) const
const Type_Conversions_State &t_conversions) const
{ {
uint_fast32_t loc = t_loc; uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
const auto funs = get_function(t_name, loc); const auto funs = get_function(t_name, loc);
if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed);
} return dispatch::dispatch(*funs.second, params, m_conversions);
return dispatch::dispatch(*funs.second, params, t_conversions);
} }
@ -1103,7 +1056,11 @@ namespace chaiscript
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
{ {
std::vector<Type_Info> params = f.second->get_param_types(); std::vector<Type_Info> params = f.second->get_param_types();
std::string annotation = f.second->annotation();
if (annotation.size() > 0) {
std::cout << annotation;
}
dump_type(params.front()); dump_type(params.front());
std::cout << " " << f.first << "("; std::cout << " " << f.first << "(";
@ -1125,7 +1082,7 @@ namespace chaiscript
/// Returns true if a call can be made that consists of the first parameter /// Returns true if a call can be made that consists of the first parameter
/// (the function) with the remaining parameters as its arguments. /// (the function) with the remaining parameters as its arguments.
Boxed_Value call_exists(const std::vector<Boxed_Value> &params) const Boxed_Value call_exists(const std::vector<Boxed_Value> &params)
{ {
if (params.empty()) if (params.empty())
{ {
@ -1133,9 +1090,8 @@ namespace chaiscript
} }
const Const_Proxy_Function &f = this->boxed_cast<Const_Proxy_Function>(params[0]); const Const_Proxy_Function &f = this->boxed_cast<Const_Proxy_Function>(params[0]);
const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves());
return const_var(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), convs)); return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), m_conversions));
} }
/// Dump all system info to stdout /// Dump all system info to stdout
@ -1204,12 +1160,12 @@ namespace chaiscript
m_state = t_state; m_state = t_state;
} }
static void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params) void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params)
{ {
t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params); t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(t_params));
} }
static void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params) void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params)
{ {
for (auto &&param : t_params) for (auto &&param : t_params)
{ {
@ -1217,14 +1173,14 @@ namespace chaiscript
} }
} }
static void save_function_params(Stack_Holder &t_s, const std::vector<Boxed_Value> &t_params) void save_function_params(Stack_Holder &t_s, const std::vector<Boxed_Value> &t_params)
{ {
t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end()); t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end());
} }
void save_function_params(std::initializer_list<Boxed_Value> t_params) void save_function_params(std::initializer_list<Boxed_Value> t_params)
{ {
save_function_params(*m_stack_holder, t_params); save_function_params(*m_stack_holder, std::move(t_params));
} }
void save_function_params(std::vector<Boxed_Value> &&t_params) void save_function_params(std::vector<Boxed_Value> &&t_params)
@ -1237,19 +1193,19 @@ namespace chaiscript
save_function_params(*m_stack_holder, t_params); save_function_params(*m_stack_holder, t_params);
} }
void new_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves) void new_function_call(Stack_Holder &t_s)
{ {
if (t_s.call_depth == 0) if (t_s.call_depth == 0)
{ {
m_conversions.enable_conversion_saves(t_saves, true); m_conversions.enable_conversion_saves(true);
} }
++t_s.call_depth; ++t_s.call_depth;
save_function_params(m_conversions.take_saves(t_saves)); save_function_params(m_conversions.take_saves());
} }
void pop_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves) void pop_function_call(Stack_Holder &t_s)
{ {
--t_s.call_depth; --t_s.call_depth;
@ -1258,18 +1214,18 @@ namespace chaiscript
if (t_s.call_depth == 0) if (t_s.call_depth == 0)
{ {
t_s.call_params.back().clear(); t_s.call_params.back().clear();
m_conversions.enable_conversion_saves(t_saves, false); m_conversions.enable_conversion_saves(false);
} }
} }
void new_function_call() void new_function_call()
{ {
new_function_call(*m_stack_holder, m_conversions.conversion_saves()); new_function_call(*m_stack_holder);
} }
void pop_function_call() void pop_function_call()
{ {
pop_function_call(*m_stack_holder, m_conversions.conversion_saves()); pop_function_call(*m_stack_holder);
} }
Stack_Holder &get_stack_holder() Stack_Holder &get_stack_holder()
@ -1284,7 +1240,7 @@ namespace chaiscript
return m_stack_holder->stacks.back(); return m_stack_holder->stacks.back();
} }
static StackData &get_stack_data(Stack_Holder &t_holder) StackData &get_stack_data(Stack_Holder &t_holder)
{ {
return t_holder.stacks.back(); return t_holder.stacks.back();
} }
@ -1294,11 +1250,6 @@ namespace chaiscript
return m_stack_holder->stacks.back(); return m_stack_holder->stacks.back();
} }
parser::ChaiScript_Parser_Base &get_parser()
{
return m_parser.get();
}
private: private:
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const
@ -1363,8 +1314,13 @@ namespace chaiscript
const auto lhssize = lhsparamtypes.size(); const auto lhssize = lhsparamtypes.size();
const auto rhssize = rhsparamtypes.size(); const auto rhssize = rhsparamtypes.size();
static const auto boxed_type = user_type<Boxed_Value>(); #ifdef CHAISCRIPT_HAS_MAGIC_STATICS
static const auto boxed_pod_type = user_type<Boxed_Number>(); static auto boxed_type = user_type<Boxed_Value>();
static auto boxed_pod_type = user_type<Boxed_Number>();
#else
auto boxed_type = user_type<Boxed_Value>();
auto boxed_pod_type = user_type<Boxed_Number>();
#endif
for (size_t i = 1; i < lhssize && i < rhssize; ++i) for (size_t i = 1; i < lhssize && i < rhssize; ++i)
{ {
@ -1395,6 +1351,10 @@ namespace chaiscript
if (rt.bare_equal(boxed_type)) if (rt.bare_equal(boxed_type))
{ {
if (lt.bare_equal(boxed_pod_type))
{
return true;
}
return true; return true;
} }
@ -1416,6 +1376,20 @@ namespace chaiscript
} }
/// Throw a reserved_word exception if the name is not allowed
void validate_object_name(const std::string &name) const
{
if (name.find("::") != std::string::npos) {
throw chaiscript::exception::illegal_name_error(name);
}
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end())
{
throw chaiscript::exception::reserved_word_error(name);
}
}
template<typename Container, typename Key, typename Value> template<typename Container, typename Key, typename Value>
static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value) static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value)
@ -1453,7 +1427,7 @@ namespace chaiscript
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint) static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint)
{ {
if (t_c.size() > t_hint && t_c[t_hint].first == t_key) { if (t_c.size() > t_hint && t_c[t_hint].first == t_key) {
return std::next(t_c.begin(), static_cast<typename std::iterator_traits<typename Container::const_iterator>::difference_type>(t_hint)); return t_c.begin() + t_hint;
} else { } else {
return find_keyed_value(t_c, t_key); return find_keyed_value(t_c, t_key);
} }
@ -1510,9 +1484,8 @@ namespace chaiscript
Type_Conversions m_conversions; Type_Conversions m_conversions;
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder; chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
std::reference_wrapper<parser::ChaiScript_Parser_Base> m_parser;
mutable std::atomic_uint_fast32_t m_method_missing_loc = {0}; mutable std::atomic_uint_fast32_t m_method_missing_loc;
State m_state; State m_state;
}; };
@ -1520,10 +1493,9 @@ namespace chaiscript
class Dispatch_State class Dispatch_State
{ {
public: public:
explicit Dispatch_State(Dispatch_Engine &t_engine) Dispatch_State(Dispatch_Engine &t_engine)
: m_engine(t_engine), : m_engine(t_engine),
m_stack_holder(t_engine.get_stack_holder()), m_stack_holder(t_engine.get_stack_holder())
m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves())
{ {
} }
@ -1539,34 +1511,16 @@ namespace chaiscript
return m_stack_holder.get(); return m_stack_holder.get();
} }
const Type_Conversions_State &conversions() const {
return m_conversions;
}
Type_Conversions::Conversion_Saves &conversion_saves() const {
return m_conversions.saves();
}
Boxed_Value &add_get_object(const std::string &t_name, Boxed_Value obj) const {
return m_engine.get().add_get_object(t_name, std::move(obj), m_stack_holder.get());
}
void add_object(const std::string &t_name, Boxed_Value obj) const { void add_object(const std::string &t_name, Boxed_Value obj) const {
return m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get()); m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get());
}
Boxed_Value get_object(const std::string &t_name, std::atomic_uint_fast32_t &t_loc) const {
return m_engine.get().get_object(t_name, t_loc, m_stack_holder.get());
} }
private: private:
std::reference_wrapper<Dispatch_Engine> m_engine; std::reference_wrapper<Dispatch_Engine> m_engine;
std::reference_wrapper<Stack_Holder> m_stack_holder; std::reference_wrapper<Stack_Holder> m_stack_holder;
Type_Conversions_State m_conversions;
}; };
} }
} }
#endif #endif

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
@ -29,7 +25,7 @@ namespace chaiscript
namespace dispatch namespace dispatch
{ {
struct option_explicit_set : std::runtime_error { struct option_explicit_set : std::runtime_error {
explicit option_explicit_set(const std::string &t_param_name) option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") : std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
{ {
@ -37,18 +33,20 @@ namespace chaiscript
option_explicit_set(const option_explicit_set &) = default; option_explicit_set(const option_explicit_set &) = default;
~option_explicit_set() noexcept override = default; virtual ~option_explicit_set() CHAISCRIPT_NOEXCEPT {}
}; };
class Dynamic_Object class Dynamic_Object
{ {
public: public:
explicit Dynamic_Object(std::string t_type_name) Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name)), m_option_explicit(false) : m_type_name(std::move(t_type_name)), m_option_explicit(false)
{ {
} }
Dynamic_Object() = default; Dynamic_Object() : m_type_name(""), m_option_explicit(false)
{
}
bool is_explicit() const bool is_explicit() const
{ {
@ -86,10 +84,6 @@ namespace chaiscript
} }
} }
bool has_attr(const std::string &t_attr_name) const {
return m_attrs.find(t_attr_name) != m_attrs.end();
}
Boxed_Value &get_attr(const std::string &t_attr_name) Boxed_Value &get_attr(const std::string &t_attr_name)
{ {
return m_attrs[t_attr_name]; return m_attrs[t_attr_name];
@ -113,14 +107,15 @@ namespace chaiscript
return get_attr(t_method_name); return get_attr(t_method_name);
} }
std::map<std::string, Boxed_Value> get_attrs() const std::map<std::string, Boxed_Value> get_attrs() const
{ {
return m_attrs; return m_attrs;
} }
private: private:
const std::string m_type_name = ""; std::string m_type_name;
bool m_option_explicit = false; bool m_option_explicit;
std::map<std::string, Boxed_Value> m_attrs; std::map<std::string, Boxed_Value> m_attrs;
}; };

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
@ -39,7 +39,7 @@ namespace chaiscript
/// A Proxy_Function implementation designed for calling a function /// A Proxy_Function implementation designed for calling a function
/// that is automatically guarded based on the first param based on the /// that is automatically guarded based on the first param based on the
/// param's type name /// param's type name
class Dynamic_Object_Function final : public Proxy_Function_Base class Dynamic_Object_Function : public Proxy_Function_Base
{ {
public: public:
Dynamic_Object_Function( Dynamic_Object_Function(
@ -67,11 +67,12 @@ namespace chaiscript
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
} }
virtual ~Dynamic_Object_Function() {}
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete; Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
bool operator==(const Proxy_Function_Base &f) const override virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{ {
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f)) if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
{ {
@ -81,9 +82,9 @@ namespace chaiscript
} }
} }
bool is_attribute_function() const override { return m_is_attribute; } virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return m_is_attribute; }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{ {
@ -93,13 +94,19 @@ namespace chaiscript
} }
} }
std::vector<Const_Proxy_Function> get_contained_functions() const override virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
{ {
return {m_func}; return {m_func};
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected: protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{ {
@ -109,7 +116,7 @@ namespace chaiscript
} }
} }
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
} }
@ -127,7 +134,7 @@ namespace chaiscript
} }
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{ {
if (bv.get_type_info().bare_equal(m_doti)) if (bv.get_type_info().bare_equal(m_doti))
{ {
@ -149,9 +156,9 @@ namespace chaiscript
} }
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name, bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{ {
if (!bvs.empty()) if (bvs.size() > 0)
{ {
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions); return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else { } else {
@ -163,7 +170,9 @@ namespace chaiscript
Proxy_Function m_func; Proxy_Function m_func;
std::unique_ptr<Type_Info> m_ti; std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti; const Type_Info m_doti;
const bool m_is_attribute; bool m_is_attribute;
}; };
@ -173,7 +182,7 @@ namespace chaiscript
* that is automatically guarded based on the first param based on the * that is automatically guarded based on the first param based on the
* param's type name * param's type name
*/ */
class Dynamic_Object_Constructor final : public Proxy_Function_Base class Dynamic_Object_Constructor : public Proxy_Function_Base
{ {
public: public:
Dynamic_Object_Constructor( Dynamic_Object_Constructor(
@ -199,13 +208,15 @@ namespace chaiscript
return std::vector<Type_Info>(begin, end); return std::vector<Type_Info>(begin, end);
} }
bool operator==(const Proxy_Function_Base &f) const override virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{ {
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f); const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))}; std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.insert(new_vals.end(), vals.begin(), vals.end()); new_vals.insert(new_vals.end(), vals.begin(), vals.end());
@ -213,8 +224,13 @@ namespace chaiscript
return m_func->call_match(new_vals, t_conversions); return m_func->call_match(new_vals, t_conversions);
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected: protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
std::vector<Boxed_Value> new_params{bv}; std::vector<Boxed_Value> new_params{bv};
@ -226,8 +242,8 @@ namespace chaiscript
} }
private: private:
const std::string m_type_name; std::string m_type_name;
const Proxy_Function m_func; Proxy_Function m_func;
}; };
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
@ -27,26 +23,80 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
/// \todo make this a variadic template
struct Exception_Handler_Base struct Exception_Handler_Base
{ {
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0; virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
virtual ~Exception_Handler_Base() = default; virtual ~Exception_Handler_Base() {}
protected: protected:
template<typename T> template<typename T>
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{ {
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {} try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
} }
}; };
template<typename ... T> template<typename T1>
struct Exception_Handler_Impl : Exception_Handler_Base struct Exception_Handler_Impl1 : Exception_Handler_Base
{ {
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override virtual ~Exception_Handler_Impl1() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{ {
(void)std::initializer_list<int>{(throw_type<T>(bv, t_engine), 0)...}; throw_type<T1>(bv, t_engine);
}
};
template<typename T1, typename T2>
struct Exception_Handler_Impl2 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl2() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3>
struct Exception_Handler_Impl3 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl3() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4>
struct Exception_Handler_Impl4 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl4() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4, typename T5>
struct Exception_Handler_Impl5 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl5() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
throw_type<T5>(bv, t_engine);
} }
}; };
} }
@ -105,10 +155,42 @@ namespace chaiscript
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing /// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
/// \sa \ref exceptions /// \sa \ref exceptions
template<typename ... T> template<typename T1>
Exception_Handler exception_specification() Exception_Handler exception_specification()
{ {
return std::make_shared<detail::Exception_Handler_Impl<T...>>(); return Exception_Handler(new detail::Exception_Handler_Impl1<T1>());
}
/// \brief creates a chaiscript::Exception_Handler which handles two types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl2<T1, T2>());
}
/// \brief creates a chaiscript::Exception_Handler which handles three types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl3<T1, T2, T3>());
}
/// \brief creates a chaiscript::Exception_Handler which handles four types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3, typename T4>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl4<T1, T2, T3, T4>());
}
/// \brief creates a chaiscript::Exception_Handler which handles five types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3, typename T4, typename T5>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl5<T1, T2, T3, T4, T5>());
} }
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_HPP_
@ -22,7 +18,7 @@
namespace chaiscript { namespace chaiscript {
class Boxed_Value; class Boxed_Value;
class Type_Conversions_State; class Type_Conversions;
namespace detail { namespace detail {
template <typename T> struct Cast_Helper; template <typename T> struct Cast_Helper;
} // namespace detail } // namespace detail
@ -39,7 +35,8 @@ namespace chaiscript
/// \returns A std::function object for dispatching /// \returns A std::function object for dispatching
/// \param[in] funcs the set of functions to dispatch on. /// \param[in] funcs the set of functions to dispatch on.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
{ {
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
[](const Const_Proxy_Function &f) { [](const Const_Proxy_Function &f) {
@ -66,7 +63,8 @@ namespace chaiscript
/// \returns A std::function object for dispatching /// \returns A std::function object for dispatching
/// \param[in] func A function to execute. /// \param[in] func A function to execute.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) std::function<FunctionType>
functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
{ {
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions); return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
} }
@ -74,7 +72,8 @@ namespace chaiscript
/// Helper for automatically unboxing a Boxed_Value that contains a function object /// Helper for automatically unboxing a Boxed_Value that contains a function object
/// and creating a typesafe C++ function caller from it. /// and creating a typesafe C++ function caller from it.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) std::function<FunctionType>
functor(const Boxed_Value &bv, const Type_Conversions *t_conversions)
{ {
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions); return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
} }
@ -85,7 +84,9 @@ namespace chaiscript
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> &> struct Cast_Helper<const std::function<Signature> &>
{ {
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@ -100,7 +101,9 @@ namespace chaiscript
template<typename Signature> template<typename Signature>
struct Cast_Helper<std::function<Signature> > struct Cast_Helper<std::function<Signature> >
{ {
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@ -115,7 +118,9 @@ namespace chaiscript
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> > struct Cast_Helper<const std::function<Signature> >
{ {
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
@ -35,15 +31,9 @@ namespace chaiscript
struct Function_Caller_Ret struct Function_Caller_Ret
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions)
{ {
if (t_conversions != nullptr) { return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()), t_conversions);
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions);
} else {
Type_Conversions conv;
Type_Conversions_State state(conv, conv.conversion_saves());
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, state), t_conversions);
}
} }
}; };
@ -54,15 +44,9 @@ namespace chaiscript
struct Function_Caller_Ret<Ret, true> struct Function_Caller_Ret<Ret, true>
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions)
{ {
if (t_conversions != nullptr) { return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions())).get_as<Ret>();
return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>();
} else {
Type_Conversions conv;
Type_Conversions_State state(conv, conv.conversion_saves());
return Boxed_Number(dispatch::dispatch(t_funcs, params, state)).get_as<Ret>();
}
} }
}; };
@ -74,15 +58,9 @@ namespace chaiscript
struct Function_Caller_Ret<void, false> struct Function_Caller_Ret<void, false>
{ {
static void call(const std::vector<Const_Proxy_Function> &t_funcs, static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions)
{ {
if (t_conversions != nullptr) { dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions());
dispatch::dispatch(t_funcs, params, *t_conversions);
} else {
Type_Conversions conv;
Type_Conversions_State state(conv, conv.conversion_saves());
dispatch::dispatch(t_funcs, params, state);
}
} }
}; };
@ -101,18 +79,11 @@ namespace chaiscript
template<typename ... P> template<typename ... P>
Ret operator()(P&& ... param) Ret operator()(P&& ... param)
{ {
if (m_conversions) {
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, { return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
box<P>(std::forward<P>(param))... box<P>(std::forward<P>(param))...
}, &state }, m_conversions
); );
} else {
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
box<P>(std::forward<P>(param))...
}, nullptr
);
}
} }
@ -143,7 +114,7 @@ namespace chaiscript
/// \todo what happens if t_conversions is deleted out from under us?! /// \todo what happens if t_conversions is deleted out from under us?!
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
{ {
/* /*
if (funcs.size() == 1) if (funcs.size() == 1)
@ -161,7 +132,7 @@ namespace chaiscript
} }
*/ */
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?t_conversions->get():nullptr)); return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions));
} }
} }
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_ #ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
#define CHAISCRIPT_HANDLE_RETURN_HPP_ #define CHAISCRIPT_HANDLE_RETURN_HPP_
@ -31,7 +27,9 @@ namespace chaiscript
namespace detail namespace detail
{ {
/// Used internally for handling a return value from a Proxy_Function call /**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret> template<typename Ret>
struct Handle_Return struct Handle_Return
{ {
@ -61,8 +59,13 @@ namespace chaiscript
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &> struct Handle_Return<std::function<Ret>>
{ {
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
);
}
}; };
template<typename Ret> template<typename Ret>
@ -76,13 +79,23 @@ namespace chaiscript
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>> struct Handle_Return<const std::shared_ptr<std::function<Ret>> &>
{ {
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>> struct Handle_Return<std::shared_ptr<std::function<Ret>>>
{ {
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
);
}
}; };
template<typename Ret> template<typename Ret>
@ -102,24 +115,6 @@ namespace chaiscript
} }
}; };
template<typename Ret>
struct Handle_Return<Ret *&>
{
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
};
template<typename Ret>
struct Handle_Return<const Ret *&>
{
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret *> struct Handle_Return<Ret *>
{ {
@ -148,26 +143,22 @@ namespace chaiscript
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<std::shared_ptr<Ret> >
{ {
}; static Boxed_Value handle(const std::shared_ptr<Ret> &r)
template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &>
{ {
}; return Boxed_Value(r, true);
template<typename Ret>
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &>
{
static Boxed_Value handle(std::unique_ptr<Ret> &&r)
{
return Boxed_Value(std::move(r), true);
} }
}; };
template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &>
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret &> struct Handle_Return<const Ret &>
@ -178,15 +169,10 @@ namespace chaiscript
} }
}; };
template<typename Ret>
struct Handle_Return<const Ret>
{
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret &> struct Handle_Return<Ret &>
{ {
@ -194,8 +180,16 @@ namespace chaiscript
{ {
return Boxed_Value(std::ref(r)); return Boxed_Value(std::ref(r));
} }
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r));
}
}; };
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<> template<>
struct Handle_Return<Boxed_Value> struct Handle_Return<Boxed_Value>
{ {
@ -205,19 +199,40 @@ namespace chaiscript
} }
}; };
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<> template<>
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> struct Handle_Return<const Boxed_Value>
{ {
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
}; };
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<> template<>
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> struct Handle_Return<Boxed_Value &>
{ {
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
}; };
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<> template<>
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value> struct Handle_Return<const Boxed_Value &>
{ {
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
}; };
/** /**
@ -232,9 +247,16 @@ namespace chaiscript
} }
}; };
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<> template<>
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number> struct Handle_Return<const Boxed_Number>
{ {
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
}; };
@ -246,7 +268,7 @@ namespace chaiscript
{ {
static Boxed_Value handle() static Boxed_Value handle()
{ {
return void_var(); return Boxed_Value(Boxed_Value::Void_Type());
} }
}; };
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_OPERATORS_HPP_ #ifndef CHAISCRIPT_OPERATORS_HPP_
#define CHAISCRIPT_OPERATORS_HPP_ #define CHAISCRIPT_OPERATORS_HPP_
@ -20,202 +16,447 @@ namespace chaiscript
{ {
namespace operators namespace operators
{ {
template<typename T> namespace detail
void assign(Module& m)
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "="); /// \todo make this return a decltype once we drop gcc 4.6
template<typename L, typename R>
auto assign(L l, R r) -> L&
{
return (l = r);
}
template<typename L, typename R>
auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
{
return (l &= r);
}
template<typename L, typename R>
auto assign_xor(L l, R r) -> decltype((l^=r))
{
return (l ^= r);
}
template<typename L, typename R>
auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
{
return (l |= r);
}
template<typename L, typename R>
auto assign_difference(L l, R r) -> decltype(( l -= r))
{
return (l -= r);
}
template<typename L, typename R>
auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
{
return (l <<= r);
}
template<typename L, typename R>
auto assign_product(L l, R r) -> decltype(( l *= r ))
{
return (l *= r);
}
template<typename L, typename R>
auto assign_quotient(L l, R r) -> decltype(( l /= r ))
{
return (l /= r);
}
template<typename L, typename R>
auto assign_remainder(L l, R r) -> decltype(( l %= r ))
{
return (l %= r);
}
template<typename L, typename R>
auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
{
return (l >>= r);
}
/// \todo make this return a decltype once we drop gcc 4.6
template<typename L, typename R>
auto assign_sum(L l, R r) -> L&
{
return (l += r);
}
template<typename L>
auto prefix_decrement(L l) -> decltype(( --l ))
{
return (--l);
}
template<typename L>
auto prefix_increment(L l) -> decltype(( ++l ))
{
return (++l);
}
template<typename L, typename R>
auto equal(L l, R r) -> decltype(( l == r ))
{
return (l == r);
}
template<typename L, typename R>
auto greater_than(L l, R r) -> decltype(( l > r ))
{
return (l > r);
}
template<typename L, typename R>
auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
{
return (l >= r);
}
template<typename L, typename R>
auto less_than(L l, R r) -> decltype(( l < r ))
{
return (l < r);
}
template<typename L, typename R>
auto less_than_equal(L l, R r) -> decltype(( l <= r ))
{
return (l <= r);
}
template<typename L>
auto logical_compliment(L l) -> decltype(( !l ))
{
return (!l);
}
template<typename L, typename R>
auto not_equal(L l, R r) -> decltype(( l != r ))
{
return (l != r);
}
template<typename L, typename R>
auto addition(L l, R r) -> decltype(( l + r ))
{
return (l + r);
}
template<typename L>
auto unary_plus(L l) -> decltype(( +l ))
{
return (+l);
}
template<typename L, typename R>
auto subtraction(L l, R r) -> decltype(( l - r ))
{
return (l - r);
}
template<typename L>
auto unary_minus(L l) -> decltype(( -l ))
{
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4146)
return (-l);
#pragma warning(pop)
#else
return (-l);
#endif
}
template<typename L, typename R>
auto bitwise_and(L l, R r) -> decltype(( l & r ))
{
return (l & r);
}
template<typename L>
auto bitwise_compliment(L l) -> decltype(( ~l ))
{
return (~l);
}
template<typename L, typename R>
auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
{
return (l ^ r);
}
template<typename L, typename R>
auto bitwise_or(L l, R r) -> decltype(( l | r ))
{
return (l | r);
}
template<typename L, typename R>
auto division(L l, R r) -> decltype(( l / r ))
{
return (l / r);
}
template<typename L, typename R>
auto left_shift(L l, R r) -> decltype(( l << r ))
{
return l << r;
}
template<typename L, typename R>
auto multiplication(L l, R r) -> decltype(( l * r ))
{
return l * r;
}
template<typename L, typename R>
auto remainder(L l, R r) -> decltype(( l % r ))
{
return (l % r);
}
template<typename L, typename R>
auto right_shift(L l, R r) -> decltype(( l >> r ))
{
return (l >> r);
}
}
template<typename T>
ModulePtr assign(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
return m;
} }
template<typename T> template<typename T>
void assign_bitwise_and(Module& m) ModulePtr assign_bitwise_and(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&="); m->add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
return m;
} }
template<typename T> template<typename T>
void assign_xor(Module& m) ModulePtr assign_xor(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^="); m->add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
return m;
} }
template<typename T> template<typename T>
void assign_bitwise_or(Module& m) ModulePtr assign_bitwise_or(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|="); m->add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
return m;
} }
template<typename T> template<typename T>
void assign_difference(Module& m) ModulePtr assign_difference(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-="); m->add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
return m;
} }
template<typename T> template<typename T>
void assign_left_shift(Module& m) ModulePtr assign_left_shift(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<="); m->add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
return m;
} }
template<typename T> template<typename T>
void assign_product(Module& m) ModulePtr assign_product(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*="); m->add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
return m;
} }
template<typename T> template<typename T>
void assign_quotient(Module& m) ModulePtr assign_quotient(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/="); m->add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
return m;
} }
template<typename T> template<typename T>
void assign_remainder(Module& m) ModulePtr assign_remainder(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%="); m->add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
return m;
} }
template<typename T> template<typename T>
void assign_right_shift(Module& m) ModulePtr assign_right_shift(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>="); m->add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
return m;
} }
template<typename T> template<typename T>
void assign_sum(Module& m) ModulePtr assign_sum(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+="); m->add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
return m;
} }
template<typename T> template<typename T>
void prefix_decrement(Module& m) ModulePtr prefix_decrement(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--"); m->add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
return m;
} }
template<typename T> template<typename T>
void prefix_increment(Module& m) ModulePtr prefix_increment(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++"); m->add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
return m;
} }
template<typename T> template<typename T>
void equal(Module& m) ModulePtr equal(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "=="); m->add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
return m;
} }
template<typename T> template<typename T>
void greater_than(Module& m) ModulePtr greater_than(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">"); m->add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
return m;
} }
template<typename T> template<typename T>
void greater_than_equal(Module& m) ModulePtr greater_than_equal(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">="); m->add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
return m;
} }
template<typename T> template<typename T>
void less_than(Module& m) ModulePtr less_than(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<"); m->add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
return m;
} }
template<typename T> template<typename T>
void less_than_equal(Module& m) ModulePtr less_than_equal(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<="); m->add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
return m;
} }
template<typename T> template<typename T>
void logical_compliment(Module& m) ModulePtr logical_compliment(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!"); m->add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
return m;
} }
template<typename T> template<typename T>
void not_equal(Module& m) ModulePtr not_equal(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!="); m->add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
return m;
} }
template<typename T> template<typename T>
void addition(Module& m) ModulePtr addition(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+"); m->add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
return m;
} }
template<typename T> template<typename T>
void unary_plus(Module& m) ModulePtr unary_plus(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+"); m->add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
return m;
} }
template<typename T> template<typename T>
void subtraction(Module& m) ModulePtr subtraction(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-"); m->add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
return m;
} }
template<typename T> template<typename T>
void unary_minus(Module& m) ModulePtr unary_minus(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-"); m->add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
return m;
} }
template<typename T> template<typename T>
void bitwise_and(Module& m) ModulePtr bitwise_and(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&"); m->add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
return m;
} }
template<typename T> template<typename T>
void bitwise_compliment(Module& m) ModulePtr bitwise_compliment(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~"); m->add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
return m;
} }
template<typename T> template<typename T>
void bitwise_xor(Module& m) ModulePtr bitwise_xor(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^"); m->add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
return m;
} }
template<typename T> template<typename T>
void bitwise_or(Module& m) ModulePtr bitwise_or(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|"); m->add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
return m;
} }
template<typename T> template<typename T>
void division(Module& m) ModulePtr division(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/"); m->add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
return m;
} }
template<typename T> template<typename T>
void left_shift(Module& m) ModulePtr left_shift(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<"); m->add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
return m;
} }
template<typename T> template<typename T>
void multiplication(Module& m) ModulePtr multiplication(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*"); m->add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
return m;
} }
template<typename T> template<typename T>
void remainder(Module& m) ModulePtr remainder(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%"); m->add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
return m;
} }
template<typename T> template<typename T>
void right_shift(Module& m) ModulePtr right_shift(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>"); m->add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
return m;
} }
} }
} }

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_HPP_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_HPP_
@ -46,7 +43,7 @@ namespace chaiscript
namespace dispatch namespace dispatch
{ {
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func, const Type_Conversions_State *t_conversions); std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func, const Type_Conversions *t_conversions);
class Param_Types class Param_Types
{ {
@ -56,7 +53,7 @@ namespace chaiscript
m_doti(user_type<Dynamic_Object>()) m_doti(user_type<Dynamic_Object>())
{} {}
explicit Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types) Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
: m_types(std::move(t_types)), : m_types(std::move(t_types)),
m_has_types(false), m_has_types(false),
m_doti(user_type<Dynamic_Object>()) m_doti(user_type<Dynamic_Object>())
@ -66,7 +63,7 @@ namespace chaiscript
void push_front(std::string t_name, Type_Info t_ti) void push_front(std::string t_name, Type_Info t_ti)
{ {
m_types.emplace(m_types.begin(), std::move(t_name), t_ti); m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti));
update_has_types(); update_has_types();
} }
@ -75,51 +72,10 @@ namespace chaiscript
return m_types == t_rhs.m_types; return m_types == t_rhs.m_types;
} }
std::vector<Boxed_Value> convert(std::vector<Boxed_Value> vals, const Type_Conversions_State &t_conversions) const bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
{ {
for (size_t i = 0; i < vals.size(); ++i) if (!m_has_types) return true;
{ if (vals.size() != m_types.size()) return false;
const auto &name = m_types[i].first;
if (!name.empty()) {
const auto &bv = vals[i];
if (!bv.get_type_info().bare_equal(m_doti))
{
const auto &ti = m_types[i].second;
if (!ti.is_undef())
{
if (!bv.get_type_info().bare_equal(ti)) {
if (t_conversions->converts(ti, bv.get_type_info())) {
try {
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
vals[i] = t_conversions->boxed_type_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
} catch (...) {
try {
// try going the other way
vals[i] = t_conversions->boxed_type_down_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), *m_types[i].second.bare_type_info());
}
}
}
}
}
}
}
}
return vals;
}
// first result: is a match
// second result: needs conversions
std::pair<bool, bool> match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
{
bool needs_conversion = false;
if (!m_has_types) { return std::make_pair(true, needs_conversion); }
if (vals.size() != m_types.size()) { return std::make_pair(false, needs_conversion); }
for (size_t i = 0; i < vals.size(); ++i) for (size_t i = 0; i < vals.size(); ++i)
{ {
@ -131,31 +87,25 @@ namespace chaiscript
{ {
try { try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions); const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
if (!(name == "Dynamic_Object" || d.get_type_name() == name)) { return name == "Dynamic_Object" || d.get_type_name() == name;
return std::make_pair(false, false);
}
} catch (const std::bad_cast &) { } catch (const std::bad_cast &) {
return std::make_pair(false, false); return false;
} }
} else { } else {
const auto &ti = m_types[i].second; const auto &ti = m_types[i].second;
if (!ti.is_undef()) if (!ti.is_undef())
{ {
if (!bv.get_type_info().bare_equal(ti)) { if (!bv.get_type_info().bare_equal(ti)) {
if (!t_conversions->converts(ti, bv.get_type_info())) { return false;
return std::make_pair(false, false);
} else {
needs_conversion = true;
}
} }
} else { } else {
return std::make_pair(false, false); return false;
} }
} }
} }
} }
return std::make_pair(true, needs_conversion); return true;
} }
const std::vector<std::pair<std::string, Type_Info>> &types() const const std::vector<std::pair<std::string, Type_Info>> &types() const
@ -195,9 +145,9 @@ namespace chaiscript
class Proxy_Function_Base class Proxy_Function_Base
{ {
public: public:
virtual ~Proxy_Function_Base() = default; virtual ~Proxy_Function_Base() {}
Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions_State &t_conversions) const Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions &t_conversions) const
{ {
if (m_arity < 0 || size_t(m_arity) == params.size()) { if (m_arity < 0 || size_t(m_arity) == params.size()) {
return do_call(params, t_conversions); return do_call(params, t_conversions);
@ -213,7 +163,7 @@ namespace chaiscript
const std::vector<Type_Info> &get_param_types() const { return m_types; } const std::vector<Type_Info> &get_param_types() const { return m_types; }
virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
virtual bool is_attribute_function() const { return false; } virtual bool is_attribute_function() const { return false; }
@ -229,11 +179,13 @@ namespace chaiscript
//! Return true if the function is a possible match //! Return true if the function is a possible match
//! to the passed in values //! to the passed in values
bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
{ {
assert(m_arity == -1 || (m_arity > 0 && static_cast<int>(vals.size()) == m_arity));
if (m_arity < 0) if (m_arity < 0)
{
return true;
} else if (static_cast<size_t>(m_arity) == vals.size()) {
if (m_arity == 0)
{ {
return true; return true;
} else if (m_arity > 1) { } else if (m_arity > 1) {
@ -241,6 +193,9 @@ namespace chaiscript
} else { } else {
return compare_type_to_param(m_types[1], vals[0], t_conversions); return compare_type_to_param(m_types[1], vals[0], t_conversions);
} }
} else {
return false;
}
} }
/// \returns the number of arguments the function takes or -1 if it is variadic /// \returns the number of arguments the function takes or -1 if it is variadic
@ -249,7 +204,9 @@ namespace chaiscript
return m_arity; return m_arity;
} }
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions) virtual std::string annotation() const = 0;
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions)
{ {
if (ti.is_undef() if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>()) || ti.bare_equal(user_type<Boxed_Value>())
@ -257,7 +214,7 @@ namespace chaiscript
&& ( (ti.bare_equal(user_type<Boxed_Number>()) && bv.get_type_info().is_arithmetic()) && ( (ti.bare_equal(user_type<Boxed_Number>()) && bv.get_type_info().is_arithmetic())
|| ti.bare_equal(bv.get_type_info()) || ti.bare_equal(bv.get_type_info())
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >()) || bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|| t_conversions->converts(ti, bv.get_type_info()) || t_conversions.converts(ti, bv.get_type_info())
) )
) )
) )
@ -268,13 +225,13 @@ namespace chaiscript
} }
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const
{ {
return compare_type_to_param(m_types[1], bv, t_conversions); return compare_type_to_param(m_types[1], bv, t_conversions);
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const = 0; virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const = 0;
Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity) Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
: m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false) : m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false)
@ -291,8 +248,7 @@ namespace chaiscript
} }
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs, static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs, const Type_Conversions &t_conversions)
const Type_Conversions_State &t_conversions)
{ {
if (tis.size() - 1 != bvs.size()) if (tis.size() - 1 != bvs.size())
{ {
@ -326,13 +282,14 @@ namespace chaiscript
class guard_error : public std::runtime_error class guard_error : public std::runtime_error
{ {
public: public:
guard_error() noexcept guard_error() CHAISCRIPT_NOEXCEPT
: std::runtime_error("Guard evaluation failed") : std::runtime_error("Guard evaluation failed")
{ } { }
guard_error(const guard_error &) = default; guard_error(const guard_error &) = default;
~guard_error() noexcept override = default; virtual ~guard_error() CHAISCRIPT_NOEXCEPT
{ }
}; };
} }
@ -349,28 +306,31 @@ namespace chaiscript
int t_arity=-1, int t_arity=-1,
AST_NodePtr t_parsenode = AST_NodePtr(), AST_NodePtr t_parsenode = AST_NodePtr(),
Param_Types t_param_types = Param_Types(), Param_Types t_param_types = Param_Types(),
std::string t_description = "",
Proxy_Function t_guard = Proxy_Function()) Proxy_Function t_guard = Proxy_Function())
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity), : Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
m_param_types(std::move(t_param_types)), m_param_types(std::move(t_param_types)),
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)) m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description))
{ {
} }
virtual ~Dynamic_Proxy_Function() {}
bool operator==(const Proxy_Function_Base &rhs) const override virtual bool operator==(const Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE
{ {
const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs); const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs);
return this == &rhs return this == &rhs
|| ((prhs != nullptr) || (prhs
&& this->m_arity == prhs->m_arity && this->m_arity == prhs->m_arity
&& !this->m_guard && !prhs->m_guard && !this->m_guard && !prhs->m_guard
&& this->m_param_types == prhs->m_param_types); && this->m_param_types == prhs->m_param_types);
} }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return call_match_internal(vals, t_conversions).first; return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions)))
&& test_guard(vals, t_conversions);
} }
@ -384,9 +344,14 @@ namespace chaiscript
return m_parsenode; return m_parsenode;
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_description;
}
protected: protected:
bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
{ {
if (m_guard) if (m_guard)
{ {
@ -402,26 +367,6 @@ namespace chaiscript
} }
} }
// first result: is a match
// second result: needs conversions
std::pair<bool, bool> call_match_internal(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
{
const auto comparison_result = [&](){
if (m_arity < 0) {
return std::make_pair(true, false);
} else if (vals.size() == size_t(m_arity)) {
return m_param_types.match(vals, t_conversions);
} else {
return std::make_pair(false, false);
}
}();
return std::make_pair(
comparison_result.first && test_guard(vals, t_conversions),
comparison_result.second
);
}
private: private:
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types) static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
{ {
@ -440,18 +385,16 @@ namespace chaiscript
return types; return types;
} }
protected:
Param_Types m_param_types; Param_Types m_param_types;
private:
Proxy_Function m_guard; Proxy_Function m_guard;
AST_NodePtr m_parsenode; AST_NodePtr m_parsenode;
std::string m_description;
}; };
template<typename Callable> template<typename Callable>
class Dynamic_Proxy_Function_Impl final : public Dynamic_Proxy_Function class Dynamic_Proxy_Function_Impl : public Dynamic_Proxy_Function
{ {
public: public:
Dynamic_Proxy_Function_Impl( Dynamic_Proxy_Function_Impl(
@ -459,35 +402,35 @@ namespace chaiscript
int t_arity=-1, int t_arity=-1,
AST_NodePtr t_parsenode = AST_NodePtr(), AST_NodePtr t_parsenode = AST_NodePtr(),
Param_Types t_param_types = Param_Types(), Param_Types t_param_types = Param_Types(),
std::string t_description = "",
Proxy_Function t_guard = Proxy_Function()) Proxy_Function t_guard = Proxy_Function())
: Dynamic_Proxy_Function( : Dynamic_Proxy_Function(
t_arity, t_arity,
std::move(t_parsenode), std::move(t_parsenode),
std::move(t_param_types), std::move(t_param_types),
std::move(t_description),
std::move(t_guard) std::move(t_guard)
), ),
m_f(std::move(t_f)) m_f(std::move(t_f))
{ {
} }
virtual ~Dynamic_Proxy_Function_Impl() {}
protected: protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
const auto match_results = call_match_internal(params, t_conversions); if (call_match(params, t_conversions) && test_guard(params, t_conversions))
if (match_results.first)
{ {
if (match_results.second) {
return m_f(m_param_types.convert(params, t_conversions));
} else {
return m_f(params); return m_f(params);
}
} else { } else {
throw exception::guard_error(); throw exception::guard_error();
} }
} }
private: private:
Callable m_f; Callable m_f;
}; };
@ -508,7 +451,7 @@ namespace chaiscript
/// and substitutes bound parameters into the parameter list /// and substitutes bound parameters into the parameter list
/// at runtime, when call() is executed. /// at runtime, when call() is executed.
/// it is used for bind(function, param1, _, param2) style calls /// it is used for bind(function, param1, _, param2) style calls
class Bound_Function final : public Proxy_Function_Base class Bound_Function : public Proxy_Function_Base
{ {
public: public:
Bound_Function(const Const_Proxy_Function &t_f, Bound_Function(const Const_Proxy_Function &t_f,
@ -519,18 +462,19 @@ namespace chaiscript
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size())); assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
} }
bool operator==(const Proxy_Function_Base &t_f) const override virtual bool operator==(const Proxy_Function_Base &t_f) const CHAISCRIPT_OVERRIDE
{ {
return &t_f == this; return &t_f == this;
} }
virtual ~Bound_Function() {}
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return m_f->call_match(build_param_list(vals), t_conversions); return m_f->call_match(build_param_list(vals), t_conversions);
} }
std::vector<Const_Proxy_Function> get_contained_functions() const override virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
{ {
return std::vector<Const_Proxy_Function>{m_f}; return std::vector<Const_Proxy_Function>{m_f};
} }
@ -567,6 +511,10 @@ namespace chaiscript
return args; return args;
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return "Bound: " + m_f->annotation();
}
protected: protected:
static std::vector<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f, static std::vector<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f,
@ -576,11 +524,18 @@ namespace chaiscript
if (t_f->get_arity() < 0) { return std::vector<Type_Info>(); } if (t_f->get_arity() < 0) { return std::vector<Type_Info>(); }
const auto types = t_f->get_param_types(); std::vector<Type_Info> types = t_f->get_param_types();
assert(types.size() == t_args.size() + 1); assert(types.size() == t_args.size() + 1);
#ifdef CHAISCRIPT_MSVC_12
#pragma warning(push)
#pragma warning(disable : 6011)
#endif
// this analysis warning is invalid in MSVC12 and doesn't exist in MSVC14 // this analysis warning is invalid in MSVC12 and doesn't exist in MSVC14
std::vector<Type_Info> retval{types[0]}; std::vector<Type_Info> retval{types[0]};
#ifdef CHAISCRIPT_MSVC_12
#pragma warning(pop)
#endif
for (size_t i = 0; i < types.size() - 1; ++i) for (size_t i = 0; i < types.size() - 1; ++i)
{ {
@ -593,7 +548,7 @@ namespace chaiscript
return retval; return retval;
} }
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return (*m_f)(build_param_list(params), t_conversions); return (*m_f)(build_param_list(params), t_conversions);
} }
@ -606,48 +561,57 @@ namespace chaiscript
class Proxy_Function_Impl_Base : public Proxy_Function_Base class Proxy_Function_Impl_Base : public Proxy_Function_Base
{ {
public: public:
explicit Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types) Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
: Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1) : Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
{ {
} }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override virtual ~Proxy_Function_Impl_Base() {}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return static_cast<int>(vals.size()) == get_arity() return "";
&& (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions));
} }
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return static_cast<int>(vals.size()) == get_arity() && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions));
}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
}; };
/// For any callable object /// For any callable object
template<typename Func, typename Callable> template<typename Func, typename Callable>
class Proxy_Function_Callable_Impl final : public Proxy_Function_Impl_Base class Proxy_Function_Callable_Impl : public Proxy_Function_Impl_Base
{ {
public: public:
explicit Proxy_Function_Callable_Impl(Callable f) Proxy_Function_Callable_Impl(Callable f)
: Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))), : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
m_f(std::move(f)) m_f(std::move(f))
{ {
} }
bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override virtual ~Proxy_Function_Callable_Impl() {}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions); return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
} }
bool operator==(const Proxy_Function_Base &t_func) const override virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
{ {
return dynamic_cast<const Proxy_Function_Callable_Impl<Func, Callable> *>(&t_func) != nullptr; return dynamic_cast<const Proxy_Function_Callable_Impl<Func, Callable> *>(&t_func) != nullptr;
} }
protected: protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return detail::call_func(detail::Function_Signature<Func>(), m_f, params, t_conversions); typedef typename detail::Function_Signature<Func>::Return_Type Return_Type;
return detail::Do_Call<Return_Type>::template go<Func>(m_f, params, t_conversions);
} }
private: private:
@ -658,16 +622,21 @@ namespace chaiscript
class Assignable_Proxy_Function : public Proxy_Function_Impl_Base class Assignable_Proxy_Function : public Proxy_Function_Impl_Base
{ {
public: public:
explicit Assignable_Proxy_Function(const std::vector<Type_Info> &t_types) Assignable_Proxy_Function(const std::vector<Type_Info> &t_types)
: Proxy_Function_Impl_Base(t_types) : Proxy_Function_Impl_Base(t_types)
{ {
} }
virtual ~Assignable_Proxy_Function() {}
virtual void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) = 0; virtual void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) = 0;
}; };
template<typename Func> template<typename Func>
class Assignable_Proxy_Function_Impl final : public Assignable_Proxy_Function class Assignable_Proxy_Function_Impl : public Assignable_Proxy_Function
{ {
public: public:
Assignable_Proxy_Function_Impl(std::reference_wrapper<std::function<Func>> t_f, std::shared_ptr<std::function<Func>> t_ptr) Assignable_Proxy_Function_Impl(std::reference_wrapper<std::function<Func>> t_f, std::shared_ptr<std::function<Func>> t_ptr)
@ -677,12 +646,14 @@ namespace chaiscript
assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get()); assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get());
} }
bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override virtual ~Assignable_Proxy_Function_Impl() {}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions); return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
} }
bool operator==(const Proxy_Function_Base &t_func) const override virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
{ {
return dynamic_cast<const Assignable_Proxy_Function_Impl<Func> *>(&t_func) != nullptr; return dynamic_cast<const Assignable_Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
} }
@ -692,14 +663,14 @@ namespace chaiscript
return m_f.get(); return m_f.get();
} }
void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) override { virtual void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) CHAISCRIPT_OVERRIDE {
m_f.get() = dispatch::functor<Func>(t_rhs, nullptr); m_f.get() = dispatch::functor<Func>(t_rhs, nullptr);
} }
protected: protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return detail::call_func(detail::Function_Signature<Func>(), m_f.get(), params, t_conversions); return detail::Do_Call<typename std::function<Func>::result_type>::template go<Func>(m_f.get(), params, t_conversions);
} }
@ -707,22 +678,22 @@ namespace chaiscript
std::reference_wrapper<std::function<Func>> m_f; std::reference_wrapper<std::function<Func>> m_f;
std::shared_ptr<std::function<Func>> m_shared_ptr_holder; std::shared_ptr<std::function<Func>> m_shared_ptr_holder;
}; };
/// Attribute getter Proxy_Function implementation /// Attribute getter Proxy_Function implementation
template<typename T, typename Class> template<typename T, typename Class>
class Attribute_Access final : public Proxy_Function_Base class Attribute_Access : public Proxy_Function_Base
{ {
public: public:
explicit Attribute_Access(T Class::* t_attr) Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types(), 1), : Proxy_Function_Base(param_types(), 1),
m_attr(t_attr) m_attr(t_attr)
{ {
} }
bool is_attribute_function() const override { return true; } virtual ~Attribute_Access() {}
bool operator==(const Proxy_Function_Base &t_func) const override virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return true; }
virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
{ {
const Attribute_Access<T, Class> * aa const Attribute_Access<T, Class> * aa
= dynamic_cast<const Attribute_Access<T, Class> *>(&t_func); = dynamic_cast<const Attribute_Access<T, Class> *>(&t_func);
@ -734,7 +705,7 @@ namespace chaiscript
} }
} }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &) const override virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE
{ {
if (vals.size() != 1) if (vals.size() != 1)
{ {
@ -744,47 +715,26 @@ namespace chaiscript
return vals[0].get_type_info().bare_equal(user_type<Class>()); return vals[0].get_type_info().bare_equal(user_type<Class>());
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return "";
}
protected: protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
const Boxed_Value &bv = params[0]; const Boxed_Value &bv = params[0];
if (bv.is_const()) if (bv.is_const())
{ {
const Class *o = boxed_cast<const Class *>(bv, &t_conversions); const Class *o = boxed_cast<const Class *>(bv, &t_conversions);
return do_call_impl<T>(o); return detail::Handle_Return<const typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
} else { } else {
Class *o = boxed_cast<Class *>(bv, &t_conversions); Class *o = boxed_cast<Class *>(bv, &t_conversions);
return do_call_impl<T>(o); return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
} }
} }
private: private:
template<typename Type>
auto do_call_impl(Class *o) const -> std::enable_if_t<std::is_pointer<Type>::value, Boxed_Value>
{
return detail::Handle_Return<Type>::handle(o->*m_attr);
}
template<typename Type>
auto do_call_impl(const Class *o) const -> std::enable_if_t<std::is_pointer<Type>::value, Boxed_Value>
{
return detail::Handle_Return<const Type>::handle(o->*m_attr);
}
template<typename Type>
auto do_call_impl(Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
{
return detail::Handle_Return<typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
}
template<typename Type>
auto do_call_impl(const Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
{
return detail::Handle_Return<typename std::add_lvalue_reference<typename std::add_const<Type>::type>::type>::handle(o->*m_attr);
}
static std::vector<Type_Info> param_types() static std::vector<Type_Info> param_types()
{ {
return {user_type<T>(), user_type<Class>()}; return {user_type<T>(), user_type<Class>()};
@ -819,7 +769,7 @@ namespace chaiscript
dispatch_error(const dispatch_error &) = default; dispatch_error(const dispatch_error &) = default;
~dispatch_error() noexcept override = default; virtual ~dispatch_error() CHAISCRIPT_NOEXCEPT {}
std::vector<Boxed_Value> parameters; std::vector<Boxed_Value> parameters;
std::vector<Const_Proxy_Function> functions; std::vector<Const_Proxy_Function> functions;
@ -832,11 +782,11 @@ namespace chaiscript
{ {
template<typename FuncType> template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist, bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
const Type_Conversions_State &t_conversions) const Type_Conversions &t_conversions)
{ {
const std::vector<Type_Info> &types = t_func->get_param_types(); const std::vector<Type_Info> &types = t_func->get_param_types();
if (t_func->get_arity() == -1) { return false; } if (t_func->get_arity() == -1) return false;
assert(plist.size() == types.size() - 1); assert(plist.size() == types.size() - 1);
@ -851,7 +801,7 @@ namespace chaiscript
template<typename InItr, typename Funcs> template<typename InItr, typename Funcs>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist, Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
const Type_Conversions_State &t_conversions, const Funcs &t_funcs) const Type_Conversions &t_conversions, const Funcs &t_funcs)
{ {
InItr matching_func(end); InItr matching_func(end);
@ -896,8 +846,7 @@ namespace chaiscript
plist.begin(), plist.begin(),
std::back_inserter(newplist), std::back_inserter(newplist),
[](const Type_Info &ti, const Boxed_Value &param) -> Boxed_Value { [](const Type_Info &ti, const Boxed_Value &param) -> Boxed_Value {
if (ti.is_arithmetic() && param.get_type_info().is_arithmetic() if (ti.is_arithmetic() && param.get_type_info().is_arithmetic()) {
&& param.get_type_info() != ti) {
return Boxed_Number(param).get_as(ti).bv; return Boxed_Number(param).get_as(ti).bv;
} else { } else {
return param; return param;
@ -905,6 +854,8 @@ namespace chaiscript
} }
); );
try { try {
return (*(matching_func->second))(newplist, t_conversions); return (*(matching_func->second))(newplist, t_conversions);
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
@ -920,12 +871,14 @@ namespace chaiscript
} }
} }
/// Take a vector of functions and a vector of parameters. Attempt to execute /**
/// each function against the set of parameters, in order, until a matching * Take a vector of functions and a vector of parameters. Attempt to execute
/// function is found or throw dispatch_error if no matching function is found * each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found
*/
template<typename Funcs> template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs, Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Type_Conversions_State &t_conversions) const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
{ {
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs; std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
ordered_funcs.reserve(funcs.size()); ordered_funcs.reserve(funcs.size());
@ -956,7 +909,7 @@ namespace chaiscript
for (const auto &func : ordered_funcs ) for (const auto &func : ordered_funcs )
{ {
try { try {
if (func.first == i && (i == 0 || func.second->filter(plist, t_conversions))) if (func.first == i && func.second->filter(plist, t_conversions))
{ {
return (*(func.second))(plist, t_conversions); return (*(func.second))(plist, t_conversions);
} }

View File

@ -1,20 +1,15 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#include <functional> #include <functional>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <array>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
@ -24,7 +19,7 @@
#include "callable_traits.hpp" #include "callable_traits.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions_State; class Type_Conversions;
namespace exception { namespace exception {
class bad_boxed_cast; class bad_boxed_cast;
} // namespace exception } // namespace exception
@ -48,7 +43,7 @@ namespace chaiscript
arity_error(const arity_error &) = default; arity_error(const arity_error &) = default;
~arity_error() noexcept override = default; virtual ~arity_error() CHAISCRIPT_NOEXCEPT {}
int got; int got;
int expected; int expected;
@ -71,6 +66,34 @@ namespace chaiscript
} }
#ifdef CHAISCRIPT_GCC_4_6
/// \todo REMOVE THIS WHEN WE DROP G++4.6
// Forward declaration
template<typename ... Rest>
struct Try_Cast;
template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...>
{
static void do_try(const std::vector<Boxed_Value> &params, size_t generation, const Type_Conversions &t_conversions)
{
boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
}
};
// 0th case
template<>
struct Try_Cast<>
{
static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions &)
{
}
};
/** /**
* Used by Proxy_Function_Impl to determine if it is equivalent to another * Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent * Proxy_Function_Impl object. This function is primarily used to prevent
@ -78,57 +101,140 @@ namespace chaiscript
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...), bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
try {
Try_Cast<Params...>::do_try(params, 0, t_conversions);
} catch (const exception::bad_boxed_cast &) {
return false;
}
return true;
}
template<typename Ret, int count, typename ... Params>
struct Call_Func
{
template<typename Callable, typename ... InnerParams>
static Ret do_call(const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
}
};
template<typename Ret, typename ... Params>
struct Call_Func<Ret, 0, Params...>
{
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4100) /// Disable unreferenced formal parameter warning, which only shows up in MSVC I don't think there's any way around it \todo evaluate this
#endif
template<typename Callable, typename ... InnerParams>
static Ret do_call(const Callable &f,
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
};
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each parameter to the expected type.
* if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Callable, typename Ret, typename ... Params>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
if (params.size() == sizeof...(Params))
{
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params, t_conversions);
}
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
}
#else
template<size_t ... I>
struct Indexes
{
};
template<size_t S, size_t ... I>
struct Make_Indexes
{
typedef typename Make_Indexes<S-1, I..., sizeof...(I)>::indexes indexes;
};
template<size_t ... I>
struct Make_Indexes<0, I...>
{
typedef Indexes<I...> indexes;
};
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret, typename ... Params, size_t ... I>
bool compare_types_cast(Indexes<I...>, Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
try { try {
std::vector<Boxed_Value>::size_type i = 0;
(void)i;
(void)params; (void)t_conversions; (void)params; (void)t_conversions;
// this is ok because the order of evaluation of initializer lists is well defined (void)std::initializer_list<int>{(boxed_cast<Params>(params[I], &t_conversions), 0)...};
(void)std::initializer_list<int>{(boxed_cast<Params>(params[i++], &t_conversions), 0)...};
return true; return true;
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
return false; return false;
} }
}
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*f)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
return compare_types_cast(indexes(), f, params, t_conversions);
} }
template<typename Callable, typename Ret, typename ... Params, size_t ... I> template<typename Callable, typename Ret, typename ... Params, size_t ... I>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, Indexes<I...>, const Callable &f,
std::index_sequence<I...>, const Callable &f, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
(void)params; (void)t_conversions; (void)params; (void)t_conversions;
return f(boxed_cast<Params>(params[I], &t_conversions)...); return f(boxed_cast<Params>(params[I], &t_conversions)...);
} }
/// Used by Proxy_Function_Impl to perform typesafe execution of a function. /**
/// The function attempts to unbox each parameter to the expected type. * Used by Proxy_Function_Impl to perform typesafe execution of a function.
/// if any unboxing fails the execution of the function fails and * The function attempts to unbox each parameter to the expected type.
/// the bad_boxed_cast is passed up to the caller. * if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Callable, typename Ret, typename ... Params> template<typename Callable, typename Ret, typename ... Params>
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f, Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions)); typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
return call_func(sig, indexes(), f, params, t_conversions);
} }
template<typename Callable, typename ... Params>
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<void (Params...)> &sig, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4702)
#endif #endif
// MSVC is reporting that this is unreachable code - and it's wrong.
return Handle_Return<void>::handle();
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
} }
} }
@ -136,4 +242,34 @@ namespace chaiscript
} }
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
template<typename Ret>
struct Do_Call
{
template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions));
}
};
template<>
struct Do_Call<void>
{
template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
call_func(Function_Signature<Signature>(), fun, params, t_conversions);
return Handle_Return<void>::handle();
}
};
}
}
}
#endif #endif

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_ #ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_ #define CHAISCRIPT_REGISTER_FUNCTION_HPP_
@ -111,6 +107,31 @@ namespace chaiscript
return fun(detail::bind_first(std::forward<T>(t), q)); return fun(detail::bind_first(std::forward<T>(t), q));
} }
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it
/// \param[in] t Function / member to expose
/// \param[in] q Value to bind to first parameter
/// \param[in] r Value to bind to second parameter
///
/// \b Example:
/// \code
/// struct MyClass
/// {
/// void memberfunction(int);
/// };
///
/// MyClass obj;
/// chaiscript::ChaiScript chai;
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
/// // memberfunction() will be equivalent to obj.memberfunction(1)
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
/// \endcode
///
/// \sa \ref adding_functions
template<typename T, typename Q, typename R>
Proxy_Function fun(T &&t, Q &&q, R &&r)
{
return fun(detail::bind_first(detail::bind_first(std::forward<T>(t), std::forward<Q>(q)), std::forward<R>(r)));
}
} }

View File

@ -1,159 +0,0 @@
#ifndef SHORT_ALLOC_H
#define SHORT_ALLOC_H
// The MIT License (MIT)
//
// Copyright (c) 2015 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <cstddef>
#include <cassert>
template <std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
class arena
{
alignas(alignment) char buf_[N];
char* ptr_;
public:
~arena() {ptr_ = nullptr;}
arena() noexcept : ptr_(buf_) {}
arena(const arena&) = delete;
arena& operator=(const arena&) = delete;
template <std::size_t ReqAlign> char* allocate(std::size_t n);
void deallocate(char* p, std::size_t n) noexcept;
static constexpr std::size_t size() noexcept {return N;}
std::size_t used() const noexcept {return static_cast<std::size_t>(ptr_ - buf_);}
void reset() noexcept {ptr_ = buf_;}
private:
static
std::size_t
align_up(std::size_t n) noexcept
{return (n + (alignment-1)) & ~(alignment-1);}
bool
pointer_in_buffer(char* p) noexcept
{return buf_ <= p && p <= buf_ + N;}
};
template <std::size_t N, std::size_t alignment>
template <std::size_t ReqAlign>
char*
arena<N, alignment>::allocate(std::size_t n)
{
static_assert(ReqAlign <= alignment, "alignment is too small for this arena");
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
auto const aligned_n = align_up(n);
if (static_cast<decltype(aligned_n)>(buf_ + N - ptr_) >= aligned_n)
{
char* r = ptr_;
ptr_ += aligned_n;
return r;
}
static_assert(alignment <= alignof(std::max_align_t), "you've chosen an "
"alignment that is larger than alignof(std::max_align_t), and "
"cannot be guaranteed by normal operator new");
return static_cast<char*>(::operator new(n));
}
template <std::size_t N, std::size_t alignment>
void
arena<N, alignment>::deallocate(char* p, std::size_t n) noexcept
{
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
if (pointer_in_buffer(p))
{
n = align_up(n);
if (p + n == ptr_) {
ptr_ = p;
}
}
else {
::operator delete(p);
}
}
template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
class short_alloc
{
public:
using value_type = T;
static auto constexpr alignment = Align;
static auto constexpr size = N;
using arena_type = arena<size, alignment>;
private:
arena_type& a_;
public:
short_alloc(const short_alloc&) = default;
short_alloc& operator=(const short_alloc&) = delete;
explicit short_alloc(arena_type& a) noexcept : a_(a)
{
static_assert(size % alignment == 0,
"size N needs to be a multiple of alignment Align");
}
template <class U>
explicit short_alloc(const short_alloc<U, N, alignment>& a) noexcept
: a_(a.a_) {}
template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;};
T* allocate(std::size_t n)
{
return reinterpret_cast<T*>(a_.template allocate<alignof(T)>(n*sizeof(T)));
}
void deallocate(T* p, std::size_t n) noexcept
{
a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
}
template <class T1, std::size_t N1, std::size_t A1,
class U, std::size_t M, std::size_t A2>
friend
bool
operator==(const short_alloc<T1, N1, A1>& x, const short_alloc<U, M, A2>& y) noexcept;
template <class U, std::size_t M, std::size_t A> friend class short_alloc;
};
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline
bool
operator==(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
{
return N == M && A1 == A2 && &x.a_ == &y.a_;
}
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline
bool
operator!=(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
{
return !(x == y);
}
#endif // SHORT_ALLOC_HPP

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
@ -33,48 +29,48 @@ namespace chaiscript
{ {
public: public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what) : bad_boxed_cast(t_from, t_to, t_what)
{ {
} }
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to) : bad_boxed_cast(t_from, t_to)
{ {
} }
explicit bad_boxed_dynamic_cast(const std::string &w) noexcept bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w) : bad_boxed_cast(w)
{ {
} }
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default; bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
~bad_boxed_dynamic_cast() noexcept override = default; virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
}; };
class bad_boxed_type_cast : public bad_boxed_cast class bad_boxed_type_cast : public bad_boxed_cast
{ {
public: public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what) : bad_boxed_cast(t_from, t_to, t_what)
{ {
} }
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to) : bad_boxed_cast(t_from, t_to)
{ {
} }
explicit bad_boxed_type_cast(const std::string &w) noexcept bad_boxed_type_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w) : bad_boxed_cast(w)
{ {
} }
bad_boxed_type_cast(const bad_boxed_type_cast &) = default; bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
~bad_boxed_type_cast() noexcept override = default; virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {}
}; };
} }
@ -101,18 +97,18 @@ namespace chaiscript
return true; return true;
} }
virtual ~Type_Conversion_Base() = default; virtual ~Type_Conversion_Base() {}
protected: protected:
Type_Conversion_Base(Type_Info t_to, Type_Info t_from) Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from)
: m_to(std::move(t_to)), m_from(std::move(t_from)) : m_to(t_to), m_from(t_from)
{ {
} }
private: private:
const Type_Info m_to; Type_Info m_to;
const Type_Info m_from; Type_Info m_from;
}; };
@ -130,7 +126,7 @@ namespace chaiscript
if (t_from.is_const()) if (t_from.is_const())
{ {
return Boxed_Value( return Boxed_Value(
[&](){ [&]()->std::shared_ptr<const To>{
if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr))) if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
{ {
return data; return data;
@ -141,7 +137,7 @@ namespace chaiscript
); );
} else { } else {
return Boxed_Value( return Boxed_Value(
[&](){ [&]()->std::shared_ptr<To>{
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr))) if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
{ {
return data; return data;
@ -186,7 +182,7 @@ namespace chaiscript
if (t_from.is_const()) if (t_from.is_const())
{ {
return Boxed_Value( return Boxed_Value(
[&](){ [&]()->std::shared_ptr<const To>{
if (auto data = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr))) if (auto data = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
{ {
return data; return data;
@ -197,7 +193,7 @@ namespace chaiscript
); );
} else { } else {
return Boxed_Value( return Boxed_Value(
[&](){ [&]()->std::shared_ptr<To>{
if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr))) if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
{ {
return data; return data;
@ -246,12 +242,12 @@ namespace chaiscript
{ {
} }
Boxed_Value convert_down(const Boxed_Value &t_base) const override virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
{ {
return Dynamic_Caster<Base, Derived>::cast(t_base); return Dynamic_Caster<Base, Derived>::cast(t_base);
} }
Boxed_Value convert(const Boxed_Value &t_derived) const override virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
{ {
return Static_Caster<Derived, Base>::cast(t_derived); return Static_Caster<Derived, Base>::cast(t_derived);
} }
@ -266,18 +262,17 @@ namespace chaiscript
{ {
} }
Boxed_Value convert_down(const Boxed_Value &t_base) const override virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
{ {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), "Unable to cast down inheritance hierarchy with non-polymorphic types");
"Unable to cast down inheritance hierarchy with non-polymorphic types");
} }
bool bidir() const override virtual bool bidir() const CHAISCRIPT_OVERRIDE
{ {
return false; return false;
} }
Boxed_Value convert(const Boxed_Value &t_derived) const override virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
{ {
return Static_Caster<Derived, Base>::cast(t_derived); return Static_Caster<Derived, Base>::cast(t_derived);
} }
@ -290,23 +285,23 @@ namespace chaiscript
{ {
public: public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(t_to, t_from), : Type_Conversion_Base(std::move(t_to), std::move(t_from)),
m_func(std::move(t_func)) m_func(std::move(t_func))
{ {
} }
Boxed_Value convert_down(const Boxed_Value &) const override virtual Boxed_Value convert_down(const Boxed_Value &) const CHAISCRIPT_OVERRIDE
{ {
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists"); throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
} }
Boxed_Value convert(const Boxed_Value &t_from) const override virtual Boxed_Value convert(const Boxed_Value &t_from) const CHAISCRIPT_OVERRIDE
{ {
/// \todo better handling of errors from the conversion function /// \todo better handling of errors from the conversion function
return m_func(t_from); return m_func(t_from);
} }
bool bidir() const override virtual bool bidir() const CHAISCRIPT_OVERRIDE
{ {
return false; return false;
} }
@ -315,17 +310,12 @@ namespace chaiscript
private: private:
Callable m_func; Callable m_func;
}; };
} }
class Type_Conversions class Type_Conversions
{ {
public: public:
struct Conversion_Saves
{
bool enabled = false;
std::vector<Boxed_Value> saves;
};
struct Less_Than struct Less_Than
{ {
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
@ -338,15 +328,22 @@ namespace chaiscript
: m_mutex(), : m_mutex(),
m_conversions(), m_conversions(),
m_convertableTypes(), m_convertableTypes(),
m_num_types(0) m_num_types(0),
m_thread_cache(this),
m_conversion_saves(this)
{ {
} }
Type_Conversions(const Type_Conversions &t_other) = delete; Type_Conversions(const Type_Conversions &t_other)
Type_Conversions(Type_Conversions &&) = default; : m_mutex(),
m_conversions(t_other.get_conversions()),
m_convertableTypes(t_other.m_convertableTypes),
m_num_types(m_conversions.size()),
m_thread_cache(this),
m_conversion_saves(this)
Type_Conversions &operator=(const Type_Conversions &) = delete; {
Type_Conversions &operator=(Type_Conversions &&) = default; }
const std::set<const std::type_info *, Less_Than> &thread_cache() const const std::set<const std::type_info *, Less_Than> &thread_cache() const
{ {
@ -390,56 +387,46 @@ namespace chaiscript
} else { } else {
return false; return false;
} }
} }
template<typename To> template<typename To>
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const Boxed_Value boxed_type_conversion(const Boxed_Value &from) const
{ {
return boxed_type_conversion(user_type<To>(), t_saves, from); try {
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation");
}
} }
template<typename From> template<typename From>
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const
{
return boxed_type_down_conversion(user_type<From>(), t_saves, to);
}
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const
{ {
try { try {
Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from); Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to);
if (t_saves.enabled) { t_saves.saves.push_back(ret); } if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion"); throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion");
} catch (const std::bad_cast &) { } catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation"); throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation");
} }
} }
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const void enable_conversion_saves(bool t_val)
{ {
try { m_conversion_saves->enabled = t_val;
Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation");
}
} }
static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) std::vector<Boxed_Value> take_saves()
{
t_saves.enabled = t_val;
}
std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves)
{ {
std::vector<Boxed_Value> ret; std::vector<Boxed_Value> ret;
std::swap(ret, t_saves.saves); std::swap(ret, m_conversion_saves->saves);
return ret; return ret;
} }
@ -453,7 +440,7 @@ namespace chaiscript
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto itr = find(to, from); auto itr = find(to, from);
if (itr != m_conversions.end()) if (itr != m_conversions.end())
{ {
@ -463,10 +450,6 @@ namespace chaiscript
} }
} }
Conversion_Saves &conversion_saves() const {
return *m_conversion_saves;
}
private: private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir( std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir(
const Type_Info &to, const Type_Info &from) const const Type_Info &to, const Type_Info &from) const
@ -476,6 +459,7 @@ namespace chaiscript
{ {
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from)) return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from)); || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
;
} }
); );
} }
@ -499,6 +483,15 @@ namespace chaiscript
} }
struct Conversion_Saves
{
Conversion_Saves()
: enabled(false)
{}
bool enabled;
std::vector<Boxed_Value> saves;
};
mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions; std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
@ -508,33 +501,6 @@ namespace chaiscript
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves; mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
}; };
class Type_Conversions_State
{
public:
Type_Conversions_State(const Type_Conversions &t_conversions,
Type_Conversions::Conversion_Saves &t_saves)
: m_conversions(t_conversions),
m_saves(t_saves)
{
}
const Type_Conversions *operator->() const {
return &m_conversions.get();
}
const Type_Conversions *get() const {
return &m_conversions.get();
}
Type_Conversions::Conversion_Saves &saves() const {
return m_saves;
}
private:
std::reference_wrapper<const Type_Conversions> m_conversions;
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
};
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion; typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you /// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
@ -616,7 +582,7 @@ namespace chaiscript
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr); const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
To vec; To vec;
vec.reserve(from_vec.size());
for (const Boxed_Value &bv : from_vec) { for (const Boxed_Value &bv : from_vec) {
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr)); vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
} }
@ -627,22 +593,6 @@ namespace chaiscript
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func);
} }
template<typename To>
Type_Conversion map_conversion()
{
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::map<std::string, Boxed_Value> &from_map = detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
To map;
for (const std::pair<std::string, Boxed_Value> &p : from_map) {
map.insert(std::make_pair(p.first, detail::Cast_Helper<typename To::mapped_type>::cast(p.second, nullptr)));
}
return Boxed_Value(std::move(map));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
}
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_TYPE_INFO_HPP_ #ifndef CHAISCRIPT_TYPE_INFO_HPP_
#define CHAISCRIPT_TYPE_INFO_HPP_ #define CHAISCRIPT_TYPE_INFO_HPP_
@ -33,66 +29,70 @@ namespace chaiscript
class Type_Info class Type_Info
{ {
public: public:
constexpr Type_Info(const bool t_is_const, const bool t_is_reference, const bool t_is_pointer, const bool t_is_void, CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti) bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
: m_type_info(t_ti), m_bare_type_info(t_bare_ti), : m_type_info(t_ti), m_bare_type_info(t_bare_ti),
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag) m_flags((t_is_const << is_const_flag)
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag) + (t_is_reference << is_reference_flag)
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag) + (t_is_pointer << is_pointer_flag)
+ (static_cast<unsigned int>(t_is_void) << is_void_flag) + (t_is_void << is_void_flag)
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag)) + (t_is_arithmetic << is_arithmetic_flag))
{ {
} }
constexpr Type_Info() = default; CHAISCRIPT_CONSTEXPR Type_Info()
: m_type_info(nullptr), m_bare_type_info(nullptr),
m_flags(1 << is_undef_flag)
{
}
constexpr bool operator<(const Type_Info &ti) const noexcept #if !defined(_MSC_VER) || _MSC_VER != 1800
Type_Info(Type_Info&&) = default;
Type_Info& operator=(Type_Info&&) = default;
#endif
Type_Info(const Type_Info&) = default;
Type_Info& operator=(const Type_Info&) = default;
CHAISCRIPT_CONSTEXPR bool operator<(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_type_info < ti.m_type_info; return m_type_info < ti.m_type_info;
} }
constexpr bool operator!=(const Type_Info &ti) const noexcept CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{
return !(operator==(ti));
}
constexpr bool operator!=(const std::type_info &ti) const noexcept
{
return !(operator==(ti));
}
constexpr bool operator==(const Type_Info &ti) const noexcept
{ {
return ti.m_type_info == m_type_info return ti.m_type_info == m_type_info
|| *ti.m_type_info == *m_type_info; || (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
} }
constexpr bool operator==(const std::type_info &ti) const noexcept CHAISCRIPT_CONSTEXPR bool operator==(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return !is_undef() && (*m_type_info) == ti; return m_type_info != nullptr && (*m_type_info) == ti;
} }
constexpr bool bare_equal(const Type_Info &ti) const noexcept CHAISCRIPT_CONSTEXPR bool bare_equal(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return ti.m_bare_type_info == m_bare_type_info return ti.m_bare_type_info == m_bare_type_info
|| *ti.m_bare_type_info == *m_bare_type_info; || (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
} }
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept CHAISCRIPT_CONSTEXPR bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return !is_undef() && (*m_bare_type_info) == ti; return m_bare_type_info != nullptr
&& (*m_bare_type_info) == ti;
} }
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; } CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_const_flag); }
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; } CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_reference_flag); }
constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; } CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_void_flag); }
constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_flag)) != 0; } CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_arithmetic_flag); }
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; } CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_undef_flag); }
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; } CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_pointer_flag); }
std::string name() const std::string name() const
{ {
if (!is_undef()) if (m_type_info)
{ {
return m_type_info->name(); return m_type_info->name();
} else { } else {
@ -102,7 +102,7 @@ namespace chaiscript
std::string bare_name() const std::string bare_name() const
{ {
if (!is_undef()) if (m_bare_type_info)
{ {
return m_bare_type_info->name(); return m_bare_type_info->name();
} else { } else {
@ -110,23 +110,21 @@ namespace chaiscript
} }
} }
constexpr const std::type_info *bare_type_info() const CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const
{ {
return m_bare_type_info; return m_bare_type_info;
} }
private: private:
struct Unknown_Type {}; const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
const std::type_info *m_type_info = &typeid(Unknown_Type); unsigned int m_flags;
const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
static const int is_const_flag = 0; static const int is_const_flag = 0;
static const int is_reference_flag = 1; static const int is_reference_flag = 1;
static const int is_pointer_flag = 2; static const int is_pointer_flag = 2;
static const int is_void_flag = 3; static const int is_void_flag = 3;
static const int is_arithmetic_flag = 4; static const int is_arithmetic_flag = 4;
static const int is_undef_flag = 5; static const int is_undef_flag = 5;
unsigned int m_flags = (1 << is_undef_flag);
}; };
namespace detail namespace detail
@ -135,7 +133,9 @@ namespace chaiscript
template<typename T> template<typename T>
struct Get_Type_Info struct Get_Type_Info
{ {
static constexpr Type_Info get() typedef T type;
static Type_Info get()
{ {
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value, return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
std::is_reference<T>::value, std::is_pointer<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
@ -150,9 +150,9 @@ namespace chaiscript
template<typename T> template<typename T>
struct Get_Type_Info<std::shared_ptr<T> > struct Get_Type_Info<std::shared_ptr<T> >
{ {
// typedef T type; typedef T type;
static constexpr Type_Info get() static Type_Info get()
{ {
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
@ -162,15 +162,12 @@ namespace chaiscript
} }
}; };
template<typename T>
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>>
{
};
template<typename T> template<typename T>
struct Get_Type_Info<const std::shared_ptr<T> &> struct Get_Type_Info<const std::shared_ptr<T> &>
{ {
static constexpr Type_Info get() typedef T type;
static Type_Info get()
{ {
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
@ -183,7 +180,9 @@ namespace chaiscript
template<typename T> template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> > struct Get_Type_Info<std::reference_wrapper<T> >
{ {
static constexpr Type_Info get() typedef T type;
static Type_Info get()
{ {
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
@ -196,7 +195,9 @@ namespace chaiscript
template<typename T> template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &> struct Get_Type_Info<const std::reference_wrapper<T> &>
{ {
static constexpr Type_Info get() typedef T type;
static Type_Info get()
{ {
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
@ -218,7 +219,7 @@ namespace chaiscript
/// chaiscript::Type_Info ti = chaiscript::user_type(i); /// chaiscript::Type_Info ti = chaiscript::user_type(i);
/// \endcode /// \endcode
template<typename T> template<typename T>
constexpr Type_Info user_type(const T &/*t*/) Type_Info user_type(const T &/*t*/)
{ {
return detail::Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }
@ -233,7 +234,7 @@ namespace chaiscript
/// chaiscript::Type_Info ti = chaiscript::user_type<int>(); /// chaiscript::Type_Info ti = chaiscript::user_type<int>();
/// \endcode /// \endcode
template<typename T> template<typename T>
constexpr Type_Info user_type() Type_Info user_type()
{ {
return detail::Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }

View File

@ -1,25 +1,19 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_ #ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_
#include "../utility/fnv1a.hpp"
#include <string> #include <string>
namespace chaiscript namespace chaiscript
{ {
struct Operators { struct Operators {
enum class Opers enum Opers
{ {
boolean_flag, boolean_flag,
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal, equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
@ -37,7 +31,7 @@ namespace chaiscript
}; };
static const char *to_string(Opers t_oper) { static const char *to_string(Opers t_oper) {
static const char *opers[] = { const char *opers[] = {
"", "",
"==", "<", ">", "<=", ">=", "!=", "==", "<", ">", "<=", ">=", "!=",
"", "",
@ -52,53 +46,81 @@ namespace chaiscript
"+", "/", "*", "-", "+", "-", "+", "/", "*", "-", "+", "-",
"" ""
}; };
return opers[static_cast<int>(t_oper)]; return opers[t_oper];
} }
static Opers to_operator(const std::string &t_str, bool t_is_unary = false) static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
{ {
#ifdef CHAISCRIPT_MSVC if (t_str == "==")
#pragma warning(push) {
#pragma warning(disable : 4307) return equals;
#endif } else if (t_str == "<") {
return less_than;
const auto op_hash = utility::fnv1a_32(t_str.c_str()); } else if (t_str == ">") {
switch (op_hash) { return greater_than;
case utility::fnv1a_32("=="): { return Opers::equals; } } else if (t_str == "<=") {
case utility::fnv1a_32("<"): { return Opers::less_than; } return less_than_equal;
case utility::fnv1a_32(">"): { return Opers::greater_than; } } else if (t_str == ">=") {
case utility::fnv1a_32("<="): { return Opers::less_than_equal; } return greater_than_equal;
case utility::fnv1a_32(">="): { return Opers::greater_than_equal; } } else if (t_str == "!=") {
case utility::fnv1a_32("!="): { return Opers::not_equal; } return not_equal;
case utility::fnv1a_32("="): { return Opers::assign; } } else if (t_str == "=") {
case utility::fnv1a_32("++"): { return Opers::pre_increment; } return assign;
case utility::fnv1a_32("--"): { return Opers::pre_decrement; } } else if (t_str == "++") {
case utility::fnv1a_32("*="): { return Opers::assign_product; } return pre_increment;
case utility::fnv1a_32("+="): { return Opers::assign_sum; } } else if (t_str == "--") {
case utility::fnv1a_32("-="): { return Opers::assign_difference; } return pre_decrement;
case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; } } else if (t_str == "*=") {
case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; } return assign_product;
case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; } } else if (t_str == "+=") {
case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; } return assign_sum;
case utility::fnv1a_32("%="): { return Opers::assign_remainder; } } else if (t_str == "-=") {
case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; } return assign_difference;
case utility::fnv1a_32("<<"): { return Opers::shift_left; } } else if (t_str == "&=") {
case utility::fnv1a_32(">>"): { return Opers::shift_right; } return assign_bitwise_and;
case utility::fnv1a_32("%"): { return Opers::remainder; } } else if (t_str == "|=") {
case utility::fnv1a_32("&"): { return Opers::bitwise_and; } return assign_bitwise_or;
case utility::fnv1a_32("|"): { return Opers::bitwise_or; } } else if (t_str == "<<=") {
case utility::fnv1a_32("^"): { return Opers::bitwise_xor; } return assign_shift_left;
case utility::fnv1a_32("~"): { return Opers::bitwise_complement; } } else if (t_str == ">>=") {
case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; } return assign_shift_right;
case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; } } else if (t_str == "%=") {
case utility::fnv1a_32("/"): { return Opers::quotient; } return assign_remainder;
case utility::fnv1a_32("*"): { return Opers::product; } } else if (t_str == "^=") {
default: { return Opers::invalid; } return assign_bitwise_xor;
} else if (t_str == "<<") {
return shift_left;
} else if (t_str == ">>") {
return shift_right;
} else if (t_str == "%") {
return remainder;
} else if (t_str == "&") {
return bitwise_and;
} else if (t_str == "|") {
return bitwise_or;
} else if (t_str == "^") {
return bitwise_xor;
} else if (t_str == "~") {
return bitwise_complement;
} else if (t_str == "+") {
if (t_is_unary) {
return unary_plus;
} else {
return sum;
}
} else if (t_str == "-") {
if (t_is_unary) {
return unary_minus;
} else {
return difference;
}
} else if (t_str == "/") {
return quotient;
} else if (t_str == "*") {
return product;
} else {
return invalid;
} }
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
} }
}; };

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_COMMON_HPP_ #ifndef CHAISCRIPT_COMMON_HPP_
#define CHAISCRIPT_COMMON_HPP_ #define CHAISCRIPT_COMMON_HPP_
@ -30,60 +26,34 @@ struct AST_Node;
namespace chaiscript namespace chaiscript
{ {
struct Name_Validator {
static bool is_reserved_word(const std::string &name)
{
static const std::set<std::string> m_reserved_words
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_",
"__LINE__", "__FILE__", "__FUNC__", "__CLASS__"};
return m_reserved_words.count(name) > 0;
}
static bool valid_object_name(const std::string &name)
{
return name.find("::") == std::string::npos && !is_reserved_word(name);
}
static void validate_object_name(const std::string &name)
{
if (is_reserved_word(name)) {
throw exception::reserved_word_error(name);
}
if (name.find("::") != std::string::npos) {
throw exception::illegal_name_error(name);
}
}
};
/// Signature of module entry point that all binary loadable modules must implement. /// Signature of module entry point that all binary loadable modules must implement.
typedef ModulePtr (*Create_Module_Func)(); typedef ModulePtr (*Create_Module_Func)();
/// Types of AST nodes available to the parser and eval /// Types of AST nodes available to the parser and eval
enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_Decl, class AST_Node_Type {
Array_Call, Dot_Access, public:
Lambda, Block, Scopeless_Block, Def, While, If, For, Ranged_For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
Inline_Range, Try, Catch, Finally, Method, Attr_Decl, Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl
};
}; };
enum class Operator_Precidence { Ternary_Cond, Logical_Or,
Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And,
Equality, Comparison, Shift, Addition, Multiplication, Prefix };
namespace namespace
{ {
/// Helper lookup to get the name of each node type
inline const char *ast_node_type_to_string(AST_Node_Type ast_node_type) {
static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl",
"Array_Call", "Dot_Access",
"Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
return ast_node_types[static_cast<int>(ast_node_type)]; /// Helper lookup to get the name of each node type
const char *ast_node_type_to_string(int ast_node_type) {
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg"};
return ast_node_types[ast_node_type];
} }
} }
@ -131,36 +101,6 @@ namespace chaiscript
/// \brief Classes which may be thrown during error cases when ChaiScript is executing. /// \brief Classes which may be thrown during error cases when ChaiScript is executing.
namespace exception namespace exception
{ {
/// \brief Thrown if an error occurs while attempting to load a binary module
struct load_module_error : std::runtime_error
{
explicit load_module_error(const std::string &t_reason) noexcept
: std::runtime_error(t_reason)
{
}
load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
: std::runtime_error(format_error(t_name, t_errors))
{
}
load_module_error(const load_module_error &) = default;
~load_module_error() noexcept override = default;
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
{
std::stringstream ss;
ss << "Error loading module '" << t_name << "'\n"
<< " The following locations were searched:\n";
for (const auto &err : t_errors) {
ss << " " << err.what() << "\n";
}
return ss.str();
}
};
/// Errors generated during parsing or evaluation /// Errors generated during parsing or evaluation
struct eval_error : std::runtime_error { struct eval_error : std::runtime_error {
@ -173,7 +113,7 @@ namespace chaiscript
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions, const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept : const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT :
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)), std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss)) reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
{} {}
@ -181,18 +121,18 @@ namespace chaiscript
eval_error(const std::string &t_why, eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions, const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept : const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT :
std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)), std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)),
reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss)) reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss))
{} {}
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept : eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) CHAISCRIPT_NOEXCEPT :
std::runtime_error(format(t_why, t_where, t_fname)), std::runtime_error(format(t_why, t_where, t_fname)),
reason(t_why), start_position(t_where), filename(t_fname) reason(t_why), start_position(t_where), filename(t_fname)
{} {}
explicit eval_error(const std::string &t_why) noexcept eval_error(const std::string &t_why) CHAISCRIPT_NOEXCEPT
: std::runtime_error("Error: \"" + t_why + "\" "), : std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why) reason(t_why)
{} {}
@ -204,7 +144,7 @@ namespace chaiscript
std::ostringstream ss; std::ostringstream ss;
ss << what(); ss << what();
if (!call_stack.empty()) { if (call_stack.size() > 0) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n"; ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
ss << '\n' << detail << '\n'; ss << '\n' << detail << '\n';
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'"; ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
@ -221,12 +161,12 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
~eval_error() noexcept override = default; virtual ~eval_error() CHAISCRIPT_NOEXCEPT {}
private: private:
template<typename T> template<typename T>
static AST_Node_Type id(const T& t) static int id(const T& t)
{ {
return t->identifier; return t->identifier;
} }
@ -480,12 +420,12 @@ namespace chaiscript
/// Errors generated when loading a file /// Errors generated when loading a file
struct file_not_found_error : std::runtime_error { struct file_not_found_error : std::runtime_error {
explicit file_not_found_error(const std::string &t_filename) noexcept file_not_found_error(const std::string &t_filename) CHAISCRIPT_NOEXCEPT
: std::runtime_error("File Not Found: " + t_filename) : std::runtime_error("File Not Found: " + t_filename)
{ } { }
file_not_found_error(const file_not_found_error &) = default; file_not_found_error(const file_not_found_error &) = default;
~file_not_found_error() noexcept override = default; virtual ~file_not_found_error() CHAISCRIPT_NOEXCEPT {}
}; };
} }
@ -494,9 +434,11 @@ namespace chaiscript
/// \brief Struct that doubles as both a parser ast_node and an AST node. /// \brief Struct that doubles as both a parser ast_node and an AST node.
struct AST_Node : std::enable_shared_from_this<AST_Node> { struct AST_Node : std::enable_shared_from_this<AST_Node> {
public: public:
const AST_Node_Type identifier; const int identifier; //< \todo shouldn't this be a strongly typed enum value?
const std::string text; const std::string text;
Parse_Location location; Parse_Location location;
std::vector<AST_NodePtr> children;
AST_NodePtr annotation;
const std::string &filename() const { const std::string &filename() const {
return *location.filename; return *location.filename;
@ -510,22 +452,19 @@ namespace chaiscript
return location.end; return location.end;
} }
std::string pretty_print() const virtual std::string pretty_print() const
{ {
std::ostringstream oss; std::ostringstream oss;
oss << text; oss << text;
for (auto & elem : this->get_children()) { for (auto & elem : this->children) {
oss << elem->pretty_print() << ' '; oss << elem->pretty_print();
} }
return oss.str(); return oss.str();
} }
virtual std::vector<AST_NodePtr> get_children() const = 0;
virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
/// Prints the contents of an AST node, including its children, recursively /// Prints the contents of an AST node, including its children, recursively
std::string to_string(const std::string &t_prepend = "") const { std::string to_string(const std::string &t_prepend = "") const {
@ -534,16 +473,25 @@ namespace chaiscript
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n'; << this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
for (auto & elem : this->get_children()) { for (auto & elem : this->children) {
oss << elem->to_string(t_prepend + " "); oss << elem->to_string(t_prepend + " ");
} }
return oss.str(); return oss.str();
} }
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const
static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) { {
try { try {
return t_ss->boxed_cast<bool>(t_bv); return eval_internal(t_e);
} catch (exception::eval_error &ee) {
ee.call_stack.push_back(shared_from_this());
throw;
}
}
static bool get_bool_condition(const Boxed_Value &t_bv) {
try {
return boxed_cast<bool>(t_bv);
} }
catch (const exception::bad_boxed_cast &) { catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("Condition not boolean"); throw exception::eval_error("Condition not boolean");
@ -551,47 +499,33 @@ namespace chaiscript
} }
virtual ~AST_Node() = default; void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
AST_Node(AST_Node &&) = default; {
AST_Node &operator=(AST_Node &&) = default; std::replace(children.begin(), children.end(), t_child, t_new_child);
}
virtual ~AST_Node() {}
protected:
AST_Node(std::string t_ast_node_text, int t_id, Parse_Location t_loc,
std::vector<AST_NodePtr> t_children = std::vector<AST_NodePtr>()) :
identifier(t_id), text(std::move(t_ast_node_text)),
location(std::move(t_loc)),
children(std::move(t_children))
{
}
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
{
throw std::runtime_error("Undispatched ast_node (internal error)");
}
private:
// Copy and assignment explicitly unimplemented
AST_Node(const AST_Node &) = delete; AST_Node(const AST_Node &) = delete;
AST_Node& operator=(const AST_Node &) = delete; AST_Node& operator=(const AST_Node &) = delete;
protected:
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
: identifier(t_id), text(std::move(t_ast_node_text)),
location(std::move(t_loc))
{
}
}; };
namespace parser {
class ChaiScript_Parser_Base
{
public:
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
virtual void debug_print(AST_NodePtr t, std::string prepend = "") const = 0;
virtual void *get_tracer_ptr() = 0;
virtual ~ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
template<typename T>
T &get_tracer()
{
// to do type check this somehow?
return *static_cast<T*>(get_tracer_ptr());
}
protected:
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
};
}
namespace eval namespace eval
{ {
@ -601,102 +535,96 @@ namespace chaiscript
struct Return_Value { struct Return_Value {
Boxed_Value retval; Boxed_Value retval;
explicit Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { } Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
}; };
/// Special type indicating a call to 'break' /// Special type indicating a call to 'break'
struct Break_Loop { struct Break_Loop {
Break_Loop() = default; Break_Loop() { }
}; };
/// Special type indicating a call to 'continue' /// Special type indicating a call to 'continue'
struct Continue_Loop { struct Continue_Loop {
Continue_Loop() = default; Continue_Loop() { }
}; };
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Scope_Push_Pop struct Scope_Push_Pop
{ {
Scope_Push_Pop(Scope_Push_Pop &&) = default;
Scope_Push_Pop& operator=(Scope_Push_Pop &&) = default;
Scope_Push_Pop(const Scope_Push_Pop &) = delete; Scope_Push_Pop(const Scope_Push_Pop &) = delete;
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete; Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds->new_scope(m_ds.stack_holder()); m_ds.get()->new_scope(m_ds.get().stack_holder());
} }
~Scope_Push_Pop() ~Scope_Push_Pop()
{ {
m_ds->pop_scope(m_ds.stack_holder()); m_ds.get()->pop_scope(m_ds.get().stack_holder());
} }
private: private:
const chaiscript::detail::Dispatch_State &m_ds; std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
}; };
/// Creates a new function call and pops it on destruction /// Creates a new function call and pops it on destruction
struct Function_Push_Pop struct Function_Push_Pop
{ {
Function_Push_Pop(Function_Push_Pop &&) = default;
Function_Push_Pop& operator=(Function_Push_Pop &&) = default;
Function_Push_Pop(const Function_Push_Pop &) = delete; Function_Push_Pop(const Function_Push_Pop &) = delete;
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete; Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); m_ds.get()->new_function_call(m_ds.get().stack_holder());
} }
~Function_Push_Pop() ~Function_Push_Pop()
{ {
m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); m_ds.get()->pop_function_call(m_ds.get().stack_holder());
} }
void save_params(const std::vector<Boxed_Value> &t_params) void save_params(const std::vector<Boxed_Value> &t_params)
{ {
m_ds->save_function_params(t_params); m_ds.get()->save_function_params(t_params);
} }
void save_params(std::initializer_list<Boxed_Value> t_params) void save_params(std::initializer_list<Boxed_Value> t_params)
{ {
m_ds->save_function_params(t_params); m_ds.get()->save_function_params(std::move(t_params));
} }
private: private:
const chaiscript::detail::Dispatch_State &m_ds; std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
}; };
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Stack_Push_Pop struct Stack_Push_Pop
{ {
Stack_Push_Pop(Stack_Push_Pop &&) = default;
Stack_Push_Pop& operator=(Stack_Push_Pop &&) = default;
Stack_Push_Pop(const Stack_Push_Pop &) = delete; Stack_Push_Pop(const Stack_Push_Pop &) = delete;
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete; Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds->new_stack(m_ds.stack_holder()); m_ds.get()->new_stack(m_ds.get().stack_holder());
} }
~Stack_Push_Pop() ~Stack_Push_Pop()
{ {
m_ds->pop_stack(m_ds.stack_holder()); m_ds.get()->pop_stack(m_ds.get().stack_holder());
} }
private: private:
const chaiscript::detail::Dispatch_State &m_ds; std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
}; };
} }
} }

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ENGINE_HPP_ #ifndef CHAISCRIPT_ENGINE_HPP_
#define CHAISCRIPT_ENGINE_HPP_ #define CHAISCRIPT_ENGINE_HPP_
@ -21,7 +17,6 @@
#include <set> #include <set>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <cstring>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "../chaiscript_threading.hpp" #include "../chaiscript_threading.hpp"
@ -36,34 +31,229 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__) #if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
#include <dlfcn.h> #include <dlfcn.h>
#endif
#if defined(CHAISCRIPT_NO_DYNLOAD)
#include "chaiscript_unknown.hpp"
#elif defined(CHAISCRIPT_WINDOWS)
#include "chaiscript_windows.hpp"
#elif _POSIX_VERSION
#include "chaiscript_posix.hpp"
#else #else
#include "chaiscript_unknown.hpp" #ifdef CHAISCRIPT_WINDOWS
#define VC_EXTRA_LEAN
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
#endif #endif
#include "../dispatchkit/exception_specification.hpp" #include "../dispatchkit/exception_specification.hpp"
#include "chaiscript_parser.hpp"
namespace chaiscript namespace chaiscript
{ {
namespace exception
{
/// \brief Thrown if an error occurs while attempting to load a binary module
struct load_module_error : std::runtime_error
{
load_module_error(const std::string &t_reason) CHAISCRIPT_NOEXCEPT
: std::runtime_error(t_reason)
{
}
load_module_error(const load_module_error &) = default;
virtual ~load_module_error() CHAISCRIPT_NOEXCEPT {}
};
}
namespace detail namespace detail
{ {
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
struct Loadable_Module
{
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{
if (!m_data)
{
throw chaiscript::exception::load_module_error(dlerror());
}
}
DLModule(const DLModule &); // Explicitly unimplemented copy constructor
DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator
~DLModule()
{
dlclose(m_data);
}
void *m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(dlerror());
}
}
static T cast_symbol(void *p)
{
union cast_union
{
T func_ptr;
void *in_ptr;
};
cast_union c;
c.in_ptr = p;
return c.func_ptr;
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
#else
#ifdef WIN32
struct Loadable_Module
{
template<typename T>
static std::wstring to_wstring(const T &t_str)
{
return std::wstring(t_str.begin(), t_str.end());
}
template<typename T>
static std::string to_string(const T &t_str)
{
return std::string(t_str.begin(), t_str.end());
}
#if defined(_UNICODE) || defined(UNICODE)
template<typename T>
static std::wstring to_proper_string(const T &t_str)
{
return to_wstring(t_str);
}
#else
template<typename T>
static std::string to_proper_string(const T &t_str)
{
return to_string(t_str);
}
#endif
static std::string get_error_message(DWORD t_err)
{
typedef LPTSTR StringType;
#if defined(_UNICODE) || defined(UNICODE)
std::wstring retval = L"Unknown Error";
#else
std::string retval = "Unknown Error";
#endif
StringType lpMsgBuf = nullptr;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<StringType>(&lpMsgBuf),
0, NULL ) != 0 && lpMsgBuf)
{
retval = lpMsgBuf;
LocalFree(lpMsgBuf);
}
return to_string(retval);
}
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
{
if (!m_data)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
~DLModule()
{
FreeLibrary(m_data);
}
HMODULE m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
#else
struct Loadable_Module
{
Loadable_Module(const std::string &, const std::string &)
{
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
}
ModulePtr m_moduleptr;
};
#endif
#endif
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr; typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
} }
/// \brief The main object that the ChaiScript user will use. /// \brief The main object that the ChaiScript user will use.
class ChaiScript_Basic { class ChaiScript {
mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::shared_mutex m_mutex;
mutable chaiscript::detail::threading::recursive_mutex m_use_mutex; mutable chaiscript::detail::threading::recursive_mutex m_use_mutex;
@ -75,16 +265,19 @@ namespace chaiscript
std::vector<std::string> m_module_paths; std::vector<std::string> m_module_paths;
std::vector<std::string> m_use_paths; std::vector<std::string> m_use_paths;
std::unique_ptr<parser::ChaiScript_Parser_Base> m_parser;
chaiscript::detail::Dispatch_Engine m_engine; chaiscript::detail::Dispatch_Engine m_engine;
/// Evaluates the given string in by parsing it and running the results through the evaluator /// Evaluates the given string in by parsing it and running the results through the evaluator
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
{ {
try { try {
const auto p = m_parser->parse(t_input, t_filename); parser::ChaiScript_Parser parser;
return p->eval(chaiscript::detail::Dispatch_State(m_engine)); if (parser.parse(t_input, t_filename)) {
//parser.show_match_stack();
return parser.optimized_ast()->eval(m_engine);
} else {
return Boxed_Value();
}
} }
catch (chaiscript::eval::detail::Return_Value &rv) { catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval; return rv.retval;
@ -93,6 +286,8 @@ namespace chaiscript
/// Evaluates the given file and looks in the 'use' paths /// Evaluates the given file and looks in the 'use' paths
const Boxed_Value internal_eval_file(const std::string &t_filename) { const Boxed_Value internal_eval_file(const std::string &t_filename) {
for (const auto &path : m_use_paths) for (const auto &path : m_use_paths)
@ -129,7 +324,27 @@ namespace chaiscript
} }
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude. /// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) { void build_eval_system(const ModulePtr &t_lib) {
m_engine.add_reserved_word("def");
m_engine.add_reserved_word("fun");
m_engine.add_reserved_word("while");
m_engine.add_reserved_word("for");
m_engine.add_reserved_word("if");
m_engine.add_reserved_word("else");
m_engine.add_reserved_word("&&");
m_engine.add_reserved_word("||");
m_engine.add_reserved_word(",");
m_engine.add_reserved_word("auto");
m_engine.add_reserved_word("return");
m_engine.add_reserved_word("break");
m_engine.add_reserved_word("true");
m_engine.add_reserved_word("false");
m_engine.add_reserved_word("class");
m_engine.add_reserved_word("attr");
m_engine.add_reserved_word("var");
m_engine.add_reserved_word("GLOBAL");
m_engine.add_reserved_word("_");
if (t_lib) if (t_lib)
{ {
add(t_lib); add(t_lib);
@ -150,14 +365,13 @@ namespace chaiscript
}) })
, "call_exists"); , "call_exists");
// m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
//
m_engine.add(fun( m_engine.add(fun(
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value { [=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) {
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves()); return t_fun(t_params, this->m_engine.conversions());
return t_fun(t_params, s);
}), "call"); }), "call");
m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name"); m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name");
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type"); m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type");
@ -171,30 +385,23 @@ namespace chaiscript
if (std::find(t_opts.begin(), t_opts.end(), Options::No_Load_Modules) == t_opts.end()
&& std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end())
{
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return load_module(t_module, t_file); }), "load_module"); m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return load_module(t_module, t_file); }), "load_module");
m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module"); m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module");
}
if (std::find(t_opts.begin(), t_opts.end(), Options::No_External_Scripts) == t_opts.end()
&& std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end())
{
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use"); m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use");
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file"); m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
}
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval"); m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
m_engine.add(fun([this](const AST_NodePtr &t_ast){ return eval(t_ast); }), "eval"); m_engine.add(fun([this](const AST_NodePtr &t_ast){ return eval(t_ast); }), "eval");
m_engine.add(fun(&parse), "parse");
m_engine.add(fun([this](const std::string &t_str, const bool t_dump){ return parse(t_str, t_dump); }), "parse"); m_engine.add(fun(&ChaiScript::version_major), "version_major");
m_engine.add(fun([this](const std::string &t_str){ return parse(t_str); }), "parse"); m_engine.add(fun(&ChaiScript::version_minor), "version_minor");
m_engine.add(fun(&ChaiScript::version_patch), "version_patch");
m_engine.add(fun(&ChaiScript::version), "version");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
} }
@ -221,43 +428,65 @@ namespace chaiscript
} }
} }
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths)
{
if (paths.empty()) { return {""}; }
else { return paths; }
}
public: public:
/// \brief Constructor for ChaiScript /// \brief Constructor for ChaiScript
/// \param[in] t_lib Standard library to apply to this ChaiScript instance /// \param[in] t_lib Standard library to apply to this ChaiScript instance
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module /// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file /// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
ChaiScript_Basic(const ModulePtr &t_lib, ChaiScript(const ModulePtr &t_lib,
std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser, std::vector<std::string> t_modulepaths = std::vector<std::string>(),
std::vector<std::string> t_module_paths = {}, std::vector<std::string> t_usepaths = std::vector<std::string>())
std::vector<std::string> t_use_paths = {}, : m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths))
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths))),
m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths))),
m_parser(std::move(parser)),
m_engine(*m_parser)
{ {
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__) if (m_module_paths.empty())
{
m_module_paths.push_back("");
}
if (m_use_paths.empty())
{
m_use_paths.push_back("");
}
build_eval_system(t_lib);
}
/// \brief Constructor for ChaiScript.
///
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
/// at runtime generates an error if it cannot be found.
///
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
ChaiScript( std::vector<std::string> t_modulepaths = std::vector<std::string>(),
std::vector<std::string> t_usepaths = std::vector<std::string>())
: m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths))
{
if (m_module_paths.empty())
{
m_module_paths.push_back("");
}
if (m_use_paths.empty())
{
m_use_paths.push_back("");
}
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
// If on Unix, add the path of the current executable to the module search path // If on Unix, add the path of the current executable to the module search path
// as windows would do // as windows would do
union cast_union union cast_union
{ {
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&); Boxed_Value (ChaiScript::*in_ptr)(const std::string&);
void *out_ptr; void *out_ptr;
}; };
Dl_info rInfo; Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) ); memset( &rInfo, 0, sizeof(rInfo) );
cast_union u; cast_union u;
u.in_ptr = &ChaiScript_Basic::use; u.in_ptr = &ChaiScript::use;
if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) { if ( dladdr(static_cast<void*>(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
std::string dllpath(rInfo.dli_fname); std::string dllpath(rInfo.dli_fname);
const size_t lastslash = dllpath.rfind('/'); const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos) if (lastslash != std::string::npos)
@ -267,79 +496,67 @@ namespace chaiscript
// Let's see if this is a link that we should expand // Let's see if this is a link that we should expand
std::vector<char> buf(2048); std::vector<char> buf(2048);
const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size()); const size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size()) if (pathlen > 0 && pathlen < buf.size())
{ {
dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen)); dllpath = std::string(&buf.front(), pathlen);
} }
m_module_paths.insert(m_module_paths.begin(), dllpath+"/"); m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
} }
#endif #endif
build_eval_system(t_lib, t_opts);
}
#ifndef CHAISCRIPT_NO_DYNLOAD
/// \brief Constructor for ChaiScript.
///
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
/// at runtime generates an error if it cannot be found.
///
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
: ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts)
{
try {
// attempt to load the stdlib // attempt to load the stdlib
load_module("chaiscript_stdlib-" + Build_Info::version()); load_module("chaiscript_stdlib-" + version());
} catch (const exception::load_module_error &t_err) {
std::cout << "An error occured while trying to load the chaiscript standard library.\n"
<< "\n"
<< "You must either provide a standard library, or compile it in.\n"
<< "For an example of compiling the standard library in,\n"
<< "see: https://gist.github.com/lefticus/9456197\n"
<< "Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n"
<< "\n"
<< "\n"
<< t_err.what();
throw;
}
}
#else // CHAISCRIPT_NO_DYNLOAD
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) = delete;
#endif
parser::ChaiScript_Parser_Base &get_parser() build_eval_system(ModulePtr());
{
return *m_parser;
} }
const Boxed_Value eval(const AST_NodePtr &t_ast) const Boxed_Value eval(const AST_NodePtr &t_ast)
{ {
try { try {
return t_ast->eval(chaiscript::detail::Dispatch_State(m_engine)); return t_ast->eval(m_engine);
} catch (const exception::eval_error &t_ee) { } catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee); throw Boxed_Value(t_ee);
} }
} }
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false) static AST_NodePtr parse(const std::string &t_input)
{ {
const auto ast = m_parser->parse(t_input, "PARSE"); parser::ChaiScript_Parser parser;
if (t_debug_print) { if (parser.parse(t_input, "PARSE")) {
m_parser->debug_print(ast); //parser.show_match_stack();
return parser.optimized_ast();
} else {
throw chaiscript::exception::eval_error("Unknown error while parsing");
} }
return ast;
} }
static int version_major()
{
return chaiscript::version_major;
}
static int version_minor()
{
return chaiscript::version_minor;
}
static int version_patch()
{
return chaiscript::version_patch;
}
static std::string version()
{
std::stringstream ss;
ss << version_major() << "." << version_minor() << "." << version_patch();
return ss.str();
}
std::string get_type_name(const Type_Info &ti) const std::string get_type_name(const Type_Info &ti) const
{ {
return m_engine.get_type_name(ti); return m_engine.get_type_name(ti);
@ -392,9 +609,8 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \param[in] t_name Name of the value to add /// \param[in] t_name Name of the value to add
/// \throw chaiscript::exception::global_non_const If t_bv is not a constant object /// \throw chaiscript::exception::global_non_const If t_bv is not a constant object
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
ChaiScript_Basic &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) ChaiScript &add_global_const(const Boxed_Value &t_bv, const std::string &t_name)
{ {
Name_Validator::validate_object_name(t_name);
m_engine.add_global_const(t_bv, t_name); m_engine.add_global_const(t_bv, t_name);
return *this; return *this;
} }
@ -404,20 +620,12 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \param[in] t_name Name of the value to add /// \param[in] t_name Name of the value to add
/// \warning The user is responsible for making sure the object is thread-safe if necessary /// \warning The user is responsible for making sure the object is thread-safe if necessary
/// ChaiScript is thread-safe but provides no threading locking mechanism to the script /// ChaiScript is thread-safe but provides no threading locking mechanism to the script
ChaiScript_Basic &add_global(const Boxed_Value &t_bv, const std::string &t_name) ChaiScript &add_global(const Boxed_Value &t_bv, const std::string &t_name)
{ {
Name_Validator::validate_object_name(t_name);
m_engine.add_global(t_bv, t_name); m_engine.add_global(t_bv, t_name);
return *this; return *this;
} }
ChaiScript_Basic &set_global(const Boxed_Value &t_bv, const std::string &t_name)
{
Name_Validator::validate_object_name(t_name);
m_engine.set_global(t_bv, t_name);
return *this;
}
/// \brief Represents the current state of the ChaiScript system. State and be saved and restored /// \brief Represents the current state of the ChaiScript system. State and be saved and restored
/// \warning State object does not contain the user defined type conversions of the engine. They /// \warning State object does not contain the user defined type conversions of the engine. They
/// are left out due to performance considerations involved in tracking the state /// are left out due to performance considerations involved in tracking the state
@ -511,9 +719,8 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// ///
/// \sa \ref adding_items /// \sa \ref adding_items
template<typename T> template<typename T>
ChaiScript_Basic &add(const T &t_t, const std::string &t_name) ChaiScript &add(const T &t_t, const std::string &t_name)
{ {
Name_Validator::validate_object_name(t_name);
m_engine.add(t_t, t_name); m_engine.add(t_t, t_name);
return *this; return *this;
} }
@ -527,7 +734,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>()); /// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode /// \endcode
ChaiScript_Basic &add(const Type_Conversion &d) ChaiScript &add(const Type_Conversion &d)
{ {
m_engine.add(d); m_engine.add(d);
return *this; return *this;
@ -536,7 +743,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \brief Adds all elements of a module to ChaiScript runtime /// \brief Adds all elements of a module to ChaiScript runtime
/// \param[in] t_p The module to add. /// \param[in] t_p The module to add.
/// \sa chaiscript::Module /// \sa chaiscript::Module
ChaiScript_Basic &add(const ModulePtr &t_p) ChaiScript &add(const ModulePtr &t_p)
{ {
t_p->apply(*this, this->get_eval_engine()); t_p->apply(*this, this->get_eval_engine());
return *this; return *this;
@ -556,13 +763,9 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found. /// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
std::string load_module(const std::string &t_module_name) std::string load_module(const std::string &t_module_name)
{ {
#ifdef CHAISCRIPT_NO_DYNLOAD
(void)t_module_name; // -Wunused-parameter
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
#else
std::vector<exception::load_module_error> errors; std::vector<exception::load_module_error> errors;
std::string version_stripped_name = t_module_name; std::string version_stripped_name = t_module_name;
size_t version_pos = version_stripped_name.find("-" + Build_Info::version()); size_t version_pos = version_stripped_name.find("-"+version());
if (version_pos != std::string::npos) if (version_pos != std::string::npos)
{ {
version_stripped_name.erase(version_pos); version_stripped_name.erase(version_pos);
@ -592,8 +795,21 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
} }
} }
throw chaiscript::exception::load_module_error(t_module_name, errors); std::string errstring;
#endif
for (std::vector<exception::load_module_error>::const_iterator itr = errors.begin();
itr != errors.end();
++itr)
{
if (!errstring.empty())
{
errstring += "; ";
}
errstring += itr->what();
}
throw chaiscript::exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring);
} }
/// \brief Load a binary module from a dynamic library. Works on platforms that support /// \brief Load a binary module from a dynamic library. Works on platforms that support
@ -630,7 +846,14 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \throw chaiscript::exception::eval_error In the case that evaluation fails. /// \throw chaiscript::exception::eval_error In the case that evaluation fails.
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler()) Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler())
{ {
return eval(t_script, t_handler); try {
return do_eval(t_script);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv, m_engine);
}
throw;
}
} }
/// \brief Evaluates a string and returns a typesafe result. /// \brief Evaluates a string and returns a typesafe result.
@ -649,14 +872,21 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
template<typename T> template<typename T>
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__") T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{ {
return m_engine.boxed_cast<T>(eval(t_input, t_handler, t_filename)); try {
return m_engine.boxed_cast<T>(do_eval(t_input, t_filename));
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv, m_engine);
}
throw;
}
} }
/// \brief casts an object while applying any Dynamic_Conversion available /// \brief casts an object while applying any Dynamic_Conversion available
template<typename Type> template<typename Type>
decltype(auto) boxed_cast(const Boxed_Value &bv) const typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
{ {
return(m_engine.boxed_cast<Type>(bv)); return m_engine.boxed_cast<Type>(bv);
} }
@ -688,7 +918,14 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \return result of the script execution /// \return result of the script execution
/// \throw chaiscript::exception::eval_error In the case that evaluation fails. /// \throw chaiscript::exception::eval_error In the case that evaluation fails.
Boxed_Value eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) { Boxed_Value eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
return eval(load_file(t_filename), t_handler, t_filename); try {
return do_eval(load_file(t_filename), t_filename);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv, m_engine);
}
throw;
}
} }
/// \brief Loads the file specified by filename, evaluates it, and returns the type safe result. /// \brief Loads the file specified by filename, evaluates it, and returns the type safe result.
@ -701,7 +938,14 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// to the requested type. /// to the requested type.
template<typename T> template<typename T>
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) { T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler)); try {
return m_engine.boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv, m_engine);
}
throw;
}
} }
}; };

File diff suppressed because it is too large Load Diff

View File

@ -1,427 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
#define CHAISCRIPT_OPTIMIZER_HPP_
#include "chaiscript_eval.hpp"
namespace chaiscript {
namespace optimizer {
template<typename ... T>
struct Optimizer : T...
{
Optimizer() = default;
explicit Optimizer(T ... t)
: T(std::move(t))...
{
}
template<typename Tracer>
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
(void)std::initializer_list<int>{ (p = static_cast<T&>(*this).optimize(p), 0)... };
return p;
}
};
template<typename T>
auto child_at(const eval::AST_Node_Impl_Ptr<T> &node, const size_t offset) {
if (node->children[offset]->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node->children[offset]).m_original_node;
} else {
return node->children[offset];
}
/*
if (node->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset];
} else {
return node->children[offset];
}
*/
}
template<typename T>
auto child_count(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children.size();
} else {
return node->children.size();
}
}
template<typename T, typename Callable>
auto make_compiled_node(const eval::AST_Node_Impl_Ptr<T> &original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable)
{
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(original_node, std::move(children), std::move(callable));
}
struct Return {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &p)
{
if ( (p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda)
&& !p->children.empty())
{
auto &last_child = p->children.back();
if (last_child->identifier == AST_Node_Type::Block) {
auto &block_last_child = last_child->children.back();
if (block_last_child->identifier == AST_Node_Type::Return) {
if (block_last_child->children.size() == 1) {
last_child->children.back() = block_last_child->children[0];
}
}
}
}
return p;
}
};
template<typename T>
bool contains_var_decl_in_scope(const T &node)
{
if (node->identifier == AST_Node_Type::Var_Decl) {
return true;
}
const auto num = child_count(node);
for (size_t i = 0; i < num; ++i) {
const auto &child = child_at(node, i);
if (child->identifier != AST_Node_Type::Block
&& child->identifier != AST_Node_Type::For
&& contains_var_decl_in_scope(child)) {
return true;
}
}
return false;
}
struct Block {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Block)
{
if (!contains_var_decl_in_scope(node))
{
if (node->children.size() == 1) {
return node->children[0];
} else {
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text, node->location, node->children);
}
}
}
return node;
}
};
struct Dead_Code {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Block)
{
std::vector<size_t> keepers;
const auto num_children = node->children.size();
keepers.reserve(num_children);
for (size_t i = 0; i < num_children; ++i) {
auto child = node->children[i];
if ( (child->identifier != AST_Node_Type::Id
&& child->identifier != AST_Node_Type::Constant
&& child->identifier != AST_Node_Type::Noop)
|| i == num_children - 1) {
keepers.push_back(i);
}
}
if (keepers.size() == num_children) {
return node;
} else {
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
for (const auto x : keepers)
{
new_children.push_back(node->children[x]);
}
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Block_AST_Node<T>>(node->text, node->location, new_children);
}
} else {
return node;
}
}
};
struct Unused_Return {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if ((node->identifier == AST_Node_Type::Block
|| node->identifier == AST_Node_Type::Scopeless_Block)
&& !node->children.empty())
{
for (size_t i = 0; i < node->children.size()-1; ++i) {
auto child = node->children[i];
if (child->identifier == AST_Node_Type::Fun_Call) {
node->children[i] = chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(child->text, child->location, std::move(child->children));
}
}
} else if ((node->identifier == AST_Node_Type::For
|| node->identifier == AST_Node_Type::While)
&& child_count(node) > 0) {
auto child = child_at(node, child_count(node) - 1);
if (child->identifier == AST_Node_Type::Block
|| child->identifier == AST_Node_Type::Scopeless_Block)
{
auto num_sub_children = child_count(child);
for (size_t i = 0; i < num_sub_children; ++i) {
auto sub_child = child_at(child, i);
if (sub_child->identifier == AST_Node_Type::Fun_Call) {
child->children[i] = chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(sub_child->text, sub_child->location, std::move(sub_child->children));
}
}
}
}
return node;
}
};
struct If {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if ((node->identifier == AST_Node_Type::If)
&& node->children.size() >= 2
&& node->children[0]->identifier == AST_Node_Type::Constant)
{
const auto condition = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
if (boxed_cast<bool>(condition)) {
return node->children[1];
} else if (node->children.size() == 3) {
return node->children[2];
}
}
}
return node;
}
};
struct Partial_Fold {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
// Fold right side
if (node->identifier == AST_Node_Type::Binary
&& node->children.size() == 2
&& node->children[0]->identifier != AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper);
if (parsed != Operators::Opers::invalid) {
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
if (rhs.get_type_info().is_arithmetic()) {
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(node->text, node->location, node->children, rhs);
}
}
} catch (const std::exception &) {
//failure to fold, that's OK
}
}
return node;
}
};
struct Constant_Fold {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Prefix
&& node->children.size() == 1
&& node->children[0]->identifier == AST_Node_Type::Constant)
{
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper, true);
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
const auto match = oper + node->children[0]->text;
if (parsed != Operators::Opers::invalid && parsed != Operators::Opers::bitwise_and && lhs.get_type_info().is_arithmetic()) {
const auto val = Boxed_Number::do_oper(parsed, lhs);
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
} else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") {
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(!boxed_cast<bool>(lhs)));
}
} catch (const std::exception &) {
//failure to fold, that's OK
}
} else if ((node->identifier == AST_Node_Type::Logical_And || node->identifier == AST_Node_Type::Logical_Or)
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
try {
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && rhs.get_type_info().bare_equal_type_info(typeid(bool))) {
const auto match = node->children[0]->text + " " + node->text + " " + node->children[1]->text;
const auto val = [lhs_val = boxed_cast<bool>(lhs), rhs_val = boxed_cast<bool>(rhs), id = node->identifier] {
if (id == AST_Node_Type::Logical_And) { return Boxed_Value(lhs_val && rhs_val); }
else { return Boxed_Value(lhs_val || rhs_val); }
}();
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
}
} catch (const std::exception &) {
//failure to fold, that's OK
}
} else if (node->identifier == AST_Node_Type::Binary
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper);
if (parsed != Operators::Opers::invalid) {
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) {
const auto val = Boxed_Number::do_oper(parsed, lhs, rhs);
const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
}
}
} catch (const std::exception &) {
//failure to fold, that's OK
}
} else if (node->identifier == AST_Node_Type::Fun_Call
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Id
&& node->children[1]->identifier == AST_Node_Type::Arg_List
&& node->children[1]->children.size() == 1
&& node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
const auto arg = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1]->children[0])->m_value;
if (arg.get_type_info().is_arithmetic()) {
const auto &fun_name = node->children[0]->text;
const auto make_constant = [&node, &fun_name](auto val){
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")";
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(val));
};
if (fun_name == "double") {
return make_constant(Boxed_Number(arg).get_as<double>());
} else if (fun_name == "int") {
return make_constant(Boxed_Number(arg).get_as<int>());
} else if (fun_name == "float") {
return make_constant(Boxed_Number(arg).get_as<float>());
} else if (fun_name == "long") {
return make_constant(Boxed_Number(arg).get_as<long>());
} else if (fun_name == "size_t") {
return make_constant(Boxed_Number(arg).get_as<size_t>());
}
}
}
return node;
}
};
struct For_Loop {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &for_node) {
if (for_node->identifier != AST_Node_Type::For) {
return for_node;
}
const auto eq_node = child_at(for_node, 0);
const auto binary_node = child_at(for_node, 1);
const auto prefix_node = child_at(for_node, 2);
if (eq_node->identifier == AST_Node_Type::Equation
&& child_count(eq_node) == 2
&& child_at(eq_node, 0)->identifier == AST_Node_Type::Var_Decl
&& child_at(eq_node, 1)->identifier == AST_Node_Type::Constant
&& binary_node->identifier == AST_Node_Type::Binary
&& binary_node->text == "<"
&& child_count(binary_node) == 2
&& child_at(binary_node, 0)->identifier == AST_Node_Type::Id
&& child_at(binary_node, 0)->text == child_at(child_at(eq_node,0), 0)->text
&& child_at(binary_node, 1)->identifier == AST_Node_Type::Constant
&& prefix_node->identifier == AST_Node_Type::Prefix
&& prefix_node->text == "++"
&& child_count(prefix_node) == 1
&& child_at(prefix_node, 0)->identifier == AST_Node_Type::Id
&& child_at(prefix_node, 0)->text == child_at(child_at(eq_node,0), 0)->text)
{
const Boxed_Value &begin = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(eq_node, 1))->m_value;
const Boxed_Value &end = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(binary_node, 1))->m_value;
const std::string &id = child_at(prefix_node, 0)->text;
if (begin.get_type_info().bare_equal(user_type<int>())
&& end.get_type_info().bare_equal(user_type<int>())) {
const auto start_int = boxed_cast<int>(begin);
const auto end_int = boxed_cast<int>(end);
const auto body = child_at(for_node, 3);
return make_compiled_node(for_node, {body},
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children, const chaiscript::detail::Dispatch_State &t_ss) {
assert(children.size() == 1);
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
int i = start_int;
t_ss.add_object(id, var(&i));
try {
for (; i < end_int; ++i) {
try {
// Body of Loop
children[0]->eval(t_ss);
} catch (eval::detail::Continue_Loop &) {
// we got a continue exception, which means all of the remaining
// loop implementation is skipped and we just need to continue to
// the next iteration step
}
}
} catch (eval::detail::Break_Loop &) {
// loop broken
}
return void_var();
}
);
} else {
return for_node;
}
} else {
return for_node;
}
}
};
typedef Optimizer<optimizer::Partial_Fold, optimizer::Unused_Return, optimizer::Constant_Fold,
optimizer::If, optimizer::Return, optimizer::Dead_Code, optimizer::Block, optimizer::For_Loop> Optimizer_Default;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_POSIX_HPP_
#define CHAISCRIPT_POSIX_HPP_
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
struct DLModule
{
explicit DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{
if (m_data == nullptr)
{
throw chaiscript::exception::load_module_error(dlerror());
}
}
DLModule(DLModule &&) = default;
DLModule &operator=(DLModule &&) = default;
DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete;
~DLModule()
{
dlclose(m_data);
}
void *m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(dlerror());
}
}
static T cast_symbol(void *p)
{
union cast_union
{
T func_ptr;
void *in_ptr;
};
cast_union c;
c.in_ptr = p;
return c.func_ptr;
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
}
}
#endif

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and 2009-2017, Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_ #ifndef CHAISCRIPT_PRELUDE_HPP_
@ -9,7 +9,7 @@
namespace chaiscript { namespace chaiscript {
struct ChaiScript_Prelude { struct ChaiScript_Prelude {
static std::string chaiscript_prelude() { return R"chaiscript( static std::string chaiscript_prelude() { return R""(
def lt(l, r) { def lt(l, r) {
if (call_exists(`<`, l, r)) { if (call_exists(`<`, l, r)) {
@ -215,29 +215,6 @@ def for_each(container, func) : call_exists(range, container) {
} }
} }
def any_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (func(t_range.front())) {
return true;
}
t_range.pop_front();
}
false;
}
def all_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (!func(t_range.front())) {
return false;
}
t_range.pop_front();
}
true;
}
def back_inserter(container) { def back_inserter(container) {
bind(push_back, container, _); bind(push_back, container, _);
} }
@ -553,7 +530,7 @@ def find(container, value) {
} }
)chaiscript"; )"";
} }
}; };

View File

@ -505,7 +505,7 @@ class Function
/// \endcode /// \endcode
Vector get_contained_functions() const; Vector get_contained_functions() const;
/// \brief Returns a function guard as function /// \brief Returns a vector of the contained functions
/// ///
/// Example: /// Example:
/// \code /// \code

View File

@ -1,46 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_TRACER_HPP_
#define CHAISCRIPT_TRACER_HPP_
namespace chaiscript {
namespace eval {
struct Noop_Tracer_Detail
{
template<typename T>
void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
{
}
};
template<typename ... T>
struct Tracer : T...
{
Tracer() = default;
explicit Tracer(T ... t)
: T(std::move(t))...
{
}
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(void)std::initializer_list<int>{ (static_cast<T&>(*this).trace(ds, node), 0)... };
}
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
ds->get_parser().get_tracer<Tracer<T...>>().do_trace(ds, node);
}
};
typedef Tracer<Noop_Tracer_Detail> Noop_Tracer;
}
}
#endif

View File

@ -1,31 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UNKNOWN_HPP_
#define CHAISCRIPT_UNKNOWN_HPP_
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
Loadable_Module(const std::string &, const std::string &)
{
#ifdef CHAISCRIPT_NO_DYNLOAD
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
#else
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
#endif
}
ModulePtr m_moduleptr;
};
}
}
#endif

View File

@ -1,133 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_WINDOWS_HPP_
#define CHAISCRIPT_WINDOWS_HPP_
#include <string>
#ifdef CHAISCRIPT_WINDOWS
#define VC_EXTRA_LEAN
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
template<typename T>
static std::wstring to_wstring(const T &t_str)
{
return std::wstring(t_str.begin(), t_str.end());
}
template<typename T>
static std::string to_string(const T &t_str)
{
return std::string(t_str.begin(), t_str.end());
}
#if defined(_UNICODE) || defined(UNICODE)
template<typename T>
static std::wstring to_proper_string(const T &t_str)
{
return to_wstring(t_str);
}
#else
template<typename T>
static std::string to_proper_string(const T &t_str)
{
return to_string(t_str);
}
#endif
static std::string get_error_message(DWORD t_err)
{
typedef LPTSTR StringType;
#if defined(_UNICODE) || defined(UNICODE)
std::wstring retval = L"Unknown Error";
#else
std::string retval = "Unknown Error";
#endif
StringType lpMsgBuf = nullptr;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<StringType>(&lpMsgBuf),
0, nullptr ) != 0 && lpMsgBuf)
{
retval = lpMsgBuf;
LocalFree(lpMsgBuf);
}
return to_string(retval);
}
struct DLModule
{
explicit DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
{
if (!m_data)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
DLModule(DLModule &&) = default;
DLModule &operator=(DLModule &&) = default;
DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete;
~DLModule()
{
FreeLibrary(m_data);
}
HMODULE m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
}
}
#endif

View File

@ -1,50 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include <cstdint>
#include "../chaiscript_defines.hpp"
namespace chaiscript
{
namespace utility
{
static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193));
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
}
}
#endif

View File

@ -13,16 +13,18 @@
#include <cmath> #include <cmath>
#include <cctype> #include <cctype>
#include <string> #include <string>
#include <vector> #include <deque>
#include <map> #include <map>
#include <type_traits> #include <type_traits>
#include <initializer_list> #include <initializer_list>
#include <ostream> #include <ostream>
#include <iostream> #include <iostream>
#include "../chaiscript_defines.hpp"
namespace json { namespace json {
using std::map;
using std::deque;
using std::string;
using std::enable_if; using std::enable_if;
using std::initializer_list; using std::initializer_list;
using std::is_same; using std::is_same;
@ -30,11 +32,41 @@ using std::is_convertible;
using std::is_integral; using std::is_integral;
using std::is_floating_point; using std::is_floating_point;
namespace {
string json_escape( const string &str ) {
string output;
for( unsigned i = 0; i < str.length(); ++i )
switch( str[i] ) {
case '\"': output += "\\\""; break;
case '\\': output += "\\\\"; break;
case '\b': output += "\\b"; break;
case '\f': output += "\\f"; break;
case '\n': output += "\\n"; break;
case '\r': output += "\\r"; break;
case '\t': output += "\\t"; break;
default : output += str[i]; break;
}
return output;
}
}
class JSON class JSON
{ {
union BackingData {
BackingData( double d ) : Float( d ){}
BackingData( long l ) : Int( l ){}
BackingData( bool b ) : Bool( b ){}
BackingData( string s ) : String( new string( s ) ){}
BackingData() : Int( 0 ){}
deque<JSON> *List;
map<string,JSON> *Map;
string *String;
double Float;
long Int;
bool Bool;
} Internal;
public: public:
enum class Class { enum class Class {
Null, Null,
@ -46,169 +78,13 @@ class JSON
Boolean Boolean
}; };
private:
struct QuickFlatMap
{
auto find(const std::string &s) {
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
}
auto find(const std::string &s) const {
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
}
auto size() const {
return data.size();
}
auto begin() const {
return data.begin();
}
auto end() const {
return data.end();
}
auto begin() {
return data.begin();
}
auto end() {
return data.end();
}
JSON &operator[](const std::string &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
data.emplace_back(s, JSON());
return data.back().second;
}
}
JSON &at(const std::string &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
const JSON &at(const std::string &s) const {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
size_t count(const std::string &s) const {
return (find(s) != data.end())?1:0;
}
std::vector<std::pair<std::string, JSON>> data;
using iterator = decltype(data)::iterator;
using const_iterator = decltype(data)::const_iterator;
};
struct Internal {
template<typename T>
auto clone(const std::unique_ptr<T> &ptr) {
if (ptr != nullptr) {
return std::make_unique<T>(*ptr);
} else {
return std::unique_ptr<T>(nullptr);
}
}
Internal( double d ) : Float( d ), Type(Class::Floating) {}
Internal( long l ) : Int( l ), Type(Class::Integral) {}
Internal( bool b ) : Bool( b ), Type(Class::Boolean) {}
Internal( std::string s ) : String(std::make_unique<std::string>(std::move(s))), Type(Class::String) {}
Internal() : Type(Class::Null) {}
Internal(Class t_type) {
set_type(t_type);
}
Internal(const Internal &other)
: List(clone(other.List)),
Map(clone(other.Map)),
String(clone(other.String)),
Float(other.Float),
Int(other.Int),
Bool(other.Bool),
Type(other.Type)
{
}
Internal &operator=(const Internal &other)
{
List = clone(other.List);
Map = clone(other.Map);
String = clone(other.String);
Float = other.Float;
Int = other.Int;
Bool = other.Bool;
Type = other.Type;
return *this;
}
void set_type( Class type ) {
if( type == Type ) {
return;
}
Map.reset();
List.reset();
String.reset();
switch( type ) {
case Class::Object: Map = std::make_unique<QuickFlatMap>(); break;
case Class::Array: List = std::make_unique<std::vector<JSON>>(); break;
case Class::String: String = std::make_unique<std::string>(); break;
case Class::Floating: Float = 0.0; break;
case Class::Integral: Int = 0; break;
case Class::Boolean: Bool = false; break;
case Class::Null: break;
}
Type = type;
}
Internal(Internal &&) = default;
Internal &operator=(Internal &&) = default;
std::unique_ptr<std::vector<JSON>> List;
std::unique_ptr<QuickFlatMap> Map;
std::unique_ptr<std::string> String;
double Float = 0;
long Int = 0;
bool Bool = false;
Class Type = Class::Null;
};
Internal internal;
public:
template <typename Container> template <typename Container>
class JSONWrapper { class JSONWrapper {
Container *object = nullptr; Container *object;
public: public:
JSONWrapper( Container *val ) : object( val ) {} JSONWrapper( Container *val ) : object( val ) {}
JSONWrapper( std::nullptr_t ) {} JSONWrapper( std::nullptr_t ) : object( nullptr ) {}
typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); } typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); } typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
@ -218,180 +94,271 @@ class JSON
template <typename Container> template <typename Container>
class JSONConstWrapper { class JSONConstWrapper {
const Container *object = nullptr; const Container *object;
public: public:
JSONConstWrapper( const Container *val ) : object( val ) {} JSONConstWrapper( const Container *val ) : object( val ) {}
JSONConstWrapper( std::nullptr_t ) {} JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {}
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); } typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); } typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
}; };
JSON() = default; JSON() : Internal(), Type( Class::Null ){}
JSON( std::nullptr_t ) {}
explicit JSON(Class type) explicit JSON(Class type)
: internal(type) : Internal(), Type(Class::Null)
{ {
SetType( type );
} }
JSON( initializer_list<JSON> list ) JSON( initializer_list<JSON> list )
: internal(Class::Object) : Internal(), Type(Class::Null)
{ {
for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) { SetType( Class::Object );
operator[]( i->to_string() ) = *std::next( i ); for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i )
operator[]( i->ToString() ) = *std::next( i );
}
JSON( JSON&& other )
: Internal( other.Internal )
, Type( other.Type )
{ other.Type = Class::Null; other.Internal.Map = nullptr; }
JSON& operator=( JSON&& other ) {
Internal = other.Internal;
Type = other.Type;
other.Internal.Map = nullptr;
other.Type = Class::Null;
return *this;
}
JSON( const JSON &other ) {
switch( other.Type ) {
case Class::Object:
Internal.Map =
new map<string,JSON>( other.Internal.Map->begin(),
other.Internal.Map->end() );
break;
case Class::Array:
Internal.List =
new deque<JSON>( other.Internal.List->begin(),
other.Internal.List->end() );
break;
case Class::String:
Internal.String =
new string( *other.Internal.String );
break;
default:
Internal = other.Internal;
}
Type = other.Type;
}
JSON& operator=( const JSON &other ) {
if (&other == this) return *this;
switch( other.Type ) {
case Class::Object:
Internal.Map =
new map<string,JSON>( other.Internal.Map->begin(),
other.Internal.Map->end() );
break;
case Class::Array:
Internal.List =
new deque<JSON>( other.Internal.List->begin(),
other.Internal.List->end() );
break;
case Class::String:
Internal.String =
new string( *other.Internal.String );
break;
default:
Internal = other.Internal;
}
Type = other.Type;
return *this;
}
~JSON() {
switch( Type ) {
case Class::Array:
delete Internal.List;
break;
case Class::Object:
delete Internal.Map;
break;
case Class::String:
delete Internal.String;
break;
default:;
} }
} }
template <typename T> template <typename T>
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<bool>(b) ) {} JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){}
template <typename T> template <typename T>
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<long>(i) ) {} JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = 0 ) : Internal( long(i) ), Type( Class::Integral ){}
template <typename T> template <typename T>
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) : internal( static_cast<double>(f) ) {} JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = 0 ) : Internal( double(f) ), Type( Class::Floating ){}
template <typename T> template <typename T>
explicit JSON( T s, typename enable_if<is_convertible<T,std::string>::value>::type* = nullptr ) : internal( static_cast<std::string>(s) ) {} JSON( T s, typename enable_if<is_convertible<T,string>::value>::type* = 0 ) : Internal( string( s ) ), Type( Class::String ){}
JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){}
static JSON Make( Class type ) {
return JSON(type);
}
static JSON Load( const std::string & ); static JSON Load( const string & );
JSON& operator[]( const std::string &key ) { template <typename T>
internal.set_type( Class::Object ); void append( T arg ) {
return internal.Map->operator[]( key ); SetType( Class::Array ); Internal.List->emplace_back( arg );
}
template <typename T, typename... U>
void append( T arg, U... args ) {
append( arg ); append( args... );
}
template <typename T>
typename enable_if<is_same<T,bool>::value, JSON&>::type operator=( T b ) {
SetType( Class::Boolean ); Internal.Bool = b; return *this;
}
template <typename T>
typename enable_if<is_integral<T>::value && !is_same<T,bool>::value, JSON&>::type operator=( T i ) {
SetType( Class::Integral ); Internal.Int = i; return *this;
}
template <typename T>
typename enable_if<is_floating_point<T>::value, JSON&>::type operator=( T f ) {
SetType( Class::Floating ); Internal.Float = f; return *this;
}
template <typename T>
typename enable_if<is_convertible<T,string>::value, JSON&>::type operator=( T s ) {
SetType( Class::String ); *Internal.String = string( s ); return *this;
}
JSON& operator[]( const string &key ) {
SetType( Class::Object ); return Internal.Map->operator[]( key );
} }
JSON& operator[]( const size_t index ) { JSON& operator[]( const size_t index ) {
internal.set_type( Class::Array ); SetType( Class::Array );
if( index >= internal.List->size() ) { if( index >= Internal.List->size() ) Internal.List->resize( index + 1 );
internal.List->resize( index + 1 ); return Internal.List->operator[]( index );
} }
return internal.List->operator[]( index ); JSON &at( const string &key ) {
}
JSON &at( const std::string &key ) {
return operator[]( key ); return operator[]( key );
} }
const JSON &at( const std::string &key ) const { const JSON &at( const string &key ) const {
return internal.Map->at( key ); return Internal.Map->at( key );
} }
JSON &at( size_t index ) { JSON &at( unsigned index ) {
return operator[]( index ); return operator[]( index );
} }
const JSON &at( size_t index ) const { const JSON &at( unsigned index ) const {
return internal.List->at( index ); return Internal.List->at( index );
} }
int length() const {
long length() const { if( Type == Class::Array )
if( internal.Type == Class::Array ) { return static_cast<int>(Internal.List->size());
return static_cast<long>(internal.List->size()); else
} else {
return -1; return -1;
} }
}
bool has_key( const std::string &key ) const {
if( internal.Type == Class::Object ) {
return internal.Map->count(key) != 0;
}
bool hasKey( const string &key ) const {
if( Type == Class::Object )
return Internal.Map->find( key ) != Internal.Map->end();
return false; return false;
} }
int size() const { int size() const {
if( internal.Type == Class::Object ) { if( Type == Class::Object )
return static_cast<int>(internal.Map->size()); return static_cast<int>(Internal.Map->size());
} else if( internal.Type == Class::Array ) { else if( Type == Class::Array )
return static_cast<int>(internal.List->size()); return static_cast<int>(Internal.List->size());
} else { else
return -1; return -1;
} }
}
Class JSONType() const { return internal.Type; } Class JSONType() const { return Type; }
/// Functions for getting primitives from the JSON object. /// Functions for getting primitives from the JSON object.
bool is_null() const { return internal.Type == Class::Null; } bool IsNull() const { return Type == Class::Null; }
std::string to_string() const { bool b; return to_string( b ); } string ToString() const { bool b; return ToString( b ); }
std::string to_string( bool &ok ) const { string ToString( bool &ok ) const {
ok = (internal.Type == Class::String); ok = (Type == Class::String);
return ok ? *internal.String : std::string(""); return ok ? *Internal.String : string("");
} }
double to_float() const { bool b; return to_float( b ); } double ToFloat() const { bool b; return ToFloat( b ); }
double to_float( bool &ok ) const { double ToFloat( bool &ok ) const {
ok = (internal.Type == Class::Floating); ok = (Type == Class::Floating);
return ok ? internal.Float : 0.0; return ok ? Internal.Float : 0.0;
} }
long to_int() const { bool b; return to_int( b ); } long ToInt() const { bool b; return ToInt( b ); }
long to_int( bool &ok ) const { long ToInt( bool &ok ) const {
ok = (internal.Type == Class::Integral); ok = (Type == Class::Integral);
return ok ? internal.Int : 0; return ok ? Internal.Int : 0;
} }
bool to_bool() const { bool b; return to_bool( b ); } bool ToBool() const { bool b; return ToBool( b ); }
bool to_bool( bool &ok ) const { bool ToBool( bool &ok ) const {
ok = (internal.Type == Class::Boolean); ok = (Type == Class::Boolean);
return ok ? internal.Bool : false; return ok ? Internal.Bool : false;
} }
JSONWrapper<QuickFlatMap> object_range() { JSONWrapper<map<string,JSON>> ObjectRange() {
if( internal.Type == Class::Object ) { if( Type == Class::Object )
return JSONWrapper<QuickFlatMap>( internal.Map.get() ); return JSONWrapper<map<string,JSON>>( Internal.Map );
} else { return JSONWrapper<map<string,JSON>>( nullptr );
return JSONWrapper<QuickFlatMap>( nullptr );
}
} }
JSONWrapper<std::vector<JSON>> array_range() { JSONWrapper<deque<JSON>> ArrayRange() {
if( internal.Type == Class::Array ) { if( Type == Class::Array )
return JSONWrapper<std::vector<JSON>>( internal.List.get() ); return JSONWrapper<deque<JSON>>( Internal.List );
} else { return JSONWrapper<deque<JSON>>( nullptr );
return JSONWrapper<std::vector<JSON>>( nullptr );
}
} }
JSONConstWrapper<QuickFlatMap> object_range() const { JSONConstWrapper<map<string,JSON>> ObjectRange() const {
if( internal.Type == Class::Object ) { if( Type == Class::Object )
return JSONConstWrapper<QuickFlatMap>( internal.Map.get() ); return JSONConstWrapper<map<string,JSON>>( Internal.Map );
} else { return JSONConstWrapper<map<string,JSON>>( nullptr );
return JSONConstWrapper<QuickFlatMap>( nullptr );
}
} }
JSONConstWrapper<std::vector<JSON>> array_range() const { JSONConstWrapper<deque<JSON>> ArrayRange() const {
if( internal.Type == Class::Array ) { if( Type == Class::Array )
return JSONConstWrapper<std::vector<JSON>>( internal.List.get() ); return JSONConstWrapper<deque<JSON>>( Internal.List );
} else { return JSONConstWrapper<deque<JSON>>( nullptr );
return JSONConstWrapper<std::vector<JSON>>( nullptr );
}
} }
std::string dump( long depth = 1, std::string tab = " ") const { string dump( int depth = 1, string tab = " ") const {
switch( internal.Type ) { switch( Type ) {
case Class::Null: case Class::Null:
return "null"; return "null";
case Class::Object: { case Class::Object: {
std::string pad = ""; string pad = "";
for( long i = 0; i < depth; ++i, pad += tab ) { } for( int i = 0; i < depth; ++i, pad += tab );
std::string s = "{\n"; string s = "{\n";
bool skip = true; bool skip = true;
for( auto &p : *internal.Map ) { for( auto &p : *Internal.Map ) {
if( !skip ) { s += ",\n"; } if( !skip ) s += ",\n";
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) ); s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
skip = false; skip = false;
} }
@ -399,10 +366,10 @@ class JSON
return s; return s;
} }
case Class::Array: { case Class::Array: {
std::string s = "["; string s = "[";
bool skip = true; bool skip = true;
for( auto &p : *internal.List ) { for( auto &p : *Internal.List ) {
if( !skip ) { s += ", "; } if( !skip ) s += ", ";
s += p.dump( depth + 1, tab ); s += p.dump( depth + 1, tab );
skip = false; skip = false;
} }
@ -410,64 +377,79 @@ class JSON
return s; return s;
} }
case Class::String: case Class::String:
return "\"" + json_escape( *internal.String ) + "\""; return "\"" + json_escape( *Internal.String ) + "\"";
case Class::Floating: case Class::Floating:
return std::to_string( internal.Float ); return std::to_string( Internal.Float );
case Class::Integral: case Class::Integral:
return std::to_string( internal.Int ); return std::to_string( Internal.Int );
case Class::Boolean: case Class::Boolean:
return internal.Bool ? "true" : "false"; return Internal.Bool ? "true" : "false";
} }
throw std::runtime_error("Unhandled JSON type"); throw std::runtime_error("Unhandled JSON type");
} }
friend std::ostream& operator<<( std::ostream&, const JSON & );
private: private:
static std::string json_escape( const std::string &str ) { void SetType( Class type ) {
std::string output; if( type == Type )
for(char i : str) { return;
switch( i ) {
case '\"': output += "\\\""; break; switch( Type ) {
case '\\': output += "\\\\"; break; case Class::Object: delete Internal.Map; break;
case '\b': output += "\\b"; break; case Class::Array: delete Internal.List; break;
case '\f': output += "\\f"; break; case Class::String: delete Internal.String; break;
case '\n': output += "\\n"; break; default:;
case '\r': output += "\\r"; break;
case '\t': output += "\\t"; break;
default : output += i; break;
}
}
return output;
} }
switch( type ) {
case Class::Null: Internal.Map = nullptr; break;
case Class::Object: Internal.Map = new map<string,JSON>(); break;
case Class::Array: Internal.List = new deque<JSON>(); break;
case Class::String: Internal.String = new string(); break;
case Class::Floating: Internal.Float = 0.0; break;
case Class::Integral: Internal.Int = 0; break;
case Class::Boolean: Internal.Bool = false; break;
}
Type = type;
}
private: private:
Class Type;
}; };
inline JSON Array() {
return JSON::Make( JSON::Class::Array );
}
struct JSONParser { template <typename... T>
static bool isspace(const char c) inline JSON Array( T... args ) {
{ JSON arr = JSON::Make( JSON::Class::Array );
#ifdef CHAISCRIPT_MSVC arr.append( args... );
// MSVC warns on these line in some circumstances return arr;
#pragma warning(push) }
#pragma warning(disable : 6330)
#endif
return ::isspace(c) != 0;
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
inline JSON Object() {
return JSON::Make( JSON::Class::Object );
}
inline std::ostream& operator<<( std::ostream &os, const JSON &json ) {
os << json.dump();
return os;
}
namespace {
JSON parse_next( const string &, size_t & );
void consume_ws( const string &str, size_t &offset ) {
while( isspace( str[offset] ) ) ++offset;
} }
static void consume_ws( const std::string &str, size_t &offset ) { JSON parse_object( const string &str, size_t &offset ) {
while( isspace( str[offset] ) && offset <= str.size() ) { ++offset; } JSON Object = JSON::Make( JSON::Class::Object );
}
static JSON parse_object( const std::string &str, size_t &offset ) {
JSON Object( JSON::Class::Object );
++offset; ++offset;
consume_ws( str, offset ); consume_ws( str, offset );
@ -483,7 +465,7 @@ struct JSONParser {
} }
consume_ws( str, ++offset ); consume_ws( str, ++offset );
JSON Value = parse_next( str, offset ); JSON Value = parse_next( str, offset );
Object[Key.to_string()] = Value; Object[Key.ToString()] = Value;
consume_ws( str, offset ); consume_ws( str, offset );
if( str[offset] == ',' ) { if( str[offset] == ',' ) {
@ -500,9 +482,9 @@ struct JSONParser {
return Object; return Object;
} }
static JSON parse_array( const std::string &str, size_t &offset ) { JSON parse_array( const string &str, size_t &offset ) {
JSON Array( JSON::Class::Array ); JSON Array = JSON::Make( JSON::Class::Array );
size_t index = 0; unsigned index = 0;
++offset; ++offset;
consume_ws( str, offset ); consume_ws( str, offset );
@ -528,8 +510,8 @@ struct JSONParser {
return Array; return Array;
} }
static JSON parse_string( const std::string &str, size_t &offset ) { JSON parse_string( const string &str, size_t &offset ) {
std::string val; string val;
for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) { for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
if( c == '\\' ) { if( c == '\\' ) {
switch( str[ ++offset ] ) { switch( str[ ++offset ] ) {
@ -543,11 +525,11 @@ struct JSONParser {
case 't' : val += '\t'; break; case 't' : val += '\t'; break;
case 'u' : { case 'u' : {
val += "\\u" ; val += "\\u" ;
for( size_t i = 1; i <= 4; ++i ) { for( unsigned i = 1; i <= 4; ++i ) {
c = str[offset+i]; c = str[offset+i];
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) { if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
val += c; val += c;
} else { else {
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'"); throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
} }
} }
@ -555,87 +537,80 @@ struct JSONParser {
} break; } break;
default : val += '\\'; break; default : val += '\\'; break;
} }
} else {
val += c;
} }
else
val += c;
} }
++offset; ++offset;
return JSON(val); return JSON(val);
} }
static JSON parse_number( const std::string &str, size_t &offset ) { JSON parse_number( const string &str, size_t &offset ) {
std::string val, exp_str; JSON Number;
string val, exp_str;
char c = '\0'; char c = '\0';
bool isDouble = false; bool isDouble = false;
bool isNegative = false;
long exp = 0; long exp = 0;
if( offset < str.size() && str[offset] == '-' ) {
isNegative = true;
++offset;
}
for (; offset < str.size() ;) { for (; offset < str.size() ;) {
c = str[offset++]; c = str[offset++];
if( c >= '0' && c <= '9' ) { if( (c == '-') || (c >= '0' && c <= '9') )
val += c; val += c;
} else if( c == '.' && !isDouble ) { else if( c == '.' ) {
val += c; val += c;
isDouble = true; isDouble = true;
} else {
break;
} }
else
break;
} }
if( offset < str.size() && (c == 'E' || c == 'e' )) { if( offset < str.size() && (c == 'E' || c == 'e' )) {
c = str[ offset++ ]; c = str[ offset++ ];
if( c == '-' ) { if( c == '-' ) { exp_str += '-';}
exp_str += '-'; else if( c == '+' ) { }
} else if( c == '+' ) { else --offset;
// do nothing
} else {
--offset;
}
for (; offset < str.size() ;) { for (; offset < str.size() ;) {
c = str[ offset++ ]; c = str[ offset++ ];
if( c >= '0' && c <= '9' ) { if( c >= '0' && c <= '9' )
exp_str += c; exp_str += c;
} else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'"); throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
} }
else { else
break; break;
}
} }
exp = chaiscript::parse_num<long>( exp_str ); exp = std::stol( exp_str );
} }
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) { else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'"); throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
} }
--offset; --offset;
if( isDouble ) { if( isDouble )
return JSON((isNegative?-1:1) * chaiscript::parse_num<double>( val ) * std::pow( 10, exp )); Number = std::stod( val ) * std::pow( 10, exp );
} else { else {
if( !exp_str.empty() ) { if( !exp_str.empty() )
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<long>( val )) * std::pow( 10, exp )); Number = std::stol( val ) * std::pow( 10, exp );
} else { else
return JSON((isNegative?-1:1) * chaiscript::parse_num<long>( val )); Number = std::stol( val );
}
} }
return Number;
} }
static JSON parse_bool( const std::string &str, size_t &offset ) { JSON parse_bool( const string &str, size_t &offset ) {
JSON Bool;
if( str.substr( offset, 4 ) == "true" ) { if( str.substr( offset, 4 ) == "true" ) {
offset += 4; offset += 4;
return JSON(true); Bool = true;
} else if( str.substr( offset, 5 ) == "false" ) { } else if( str.substr( offset, 5 ) == "false" ) {
offset += 5; offset += 5;
return JSON(false); Bool = false;
} else { } else {
throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'"); throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'");
} }
return Bool;
} }
static JSON parse_null( const std::string &str, size_t &offset ) { JSON parse_null( const string &str, size_t &offset ) {
if( str.substr( offset, 4 ) != "null" ) { if( str.substr( offset, 4 ) != "null" ) {
throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'"); throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'");
} }
@ -643,7 +618,7 @@ struct JSONParser {
return JSON(); return JSON();
} }
static JSON parse_next( const std::string &str, size_t &offset ) { JSON parse_next( const string &str, size_t &offset ) {
char value; char value;
consume_ws( str, offset ); consume_ws( str, offset );
value = str[offset]; value = str[offset];
@ -654,18 +629,16 @@ struct JSONParser {
case 't' : case 't' :
case 'f' : return parse_bool( str, offset ); case 'f' : return parse_bool( str, offset );
case 'n' : return parse_null( str, offset ); case 'n' : return parse_null( str, offset );
default : if( ( value <= '9' && value >= '0' ) || value == '-' ) { default : if( ( value <= '9' && value >= '0' ) || value == '-' )
return parse_number( str, offset ); return parse_number( str, offset );
} }
}
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'"); throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
} }
}
}; inline JSON JSON::Load( const string &str ) {
inline JSON JSON::Load( const std::string &str ) {
size_t offset = 0; size_t offset = 0;
return JSONParser::parse_next( str, offset ); return parse_next( str, offset );
} }
} // End Namespace json } // End Namespace json

View File

@ -9,11 +9,11 @@ namespace chaiscript
{ {
public: public:
static Module& library(Module& m) static ModulePtr library(ModulePtr m = std::make_shared<Module>())
{ {
m.add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json"); m->add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
m.add(chaiscript::fun(&json_wrap::to_json), "to_json"); m->add(chaiscript::fun(&json_wrap::to_json), "to_json");
return m; return m;
@ -30,7 +30,7 @@ namespace chaiscript
{ {
std::map<std::string, Boxed_Value> m; std::map<std::string, Boxed_Value> m;
for (const auto &p : t_json.object_range()) for (const auto &p : t_json.ObjectRange())
{ {
m.insert(std::make_pair(p.first, from_json(p.second))); m.insert(std::make_pair(p.first, from_json(p.second)));
} }
@ -41,7 +41,7 @@ namespace chaiscript
{ {
std::vector<Boxed_Value> vec; std::vector<Boxed_Value> vec;
for (const auto &p : t_json.array_range()) for (const auto &p : t_json.ArrayRange())
{ {
vec.emplace_back(from_json(p)); vec.emplace_back(from_json(p));
} }
@ -49,13 +49,13 @@ namespace chaiscript
return Boxed_Value(vec); return Boxed_Value(vec);
} }
case json::JSON::Class::String: case json::JSON::Class::String:
return Boxed_Value(t_json.to_string()); return Boxed_Value(t_json.ToString());
case json::JSON::Class::Floating: case json::JSON::Class::Floating:
return Boxed_Value(t_json.to_float()); return Boxed_Value(t_json.ToFloat());
case json::JSON::Class::Integral: case json::JSON::Class::Integral:
return Boxed_Value(t_json.to_int()); return Boxed_Value(t_json.ToInt());
case json::JSON::Class::Boolean: case json::JSON::Class::Boolean:
return Boxed_Value(t_json.to_bool()); return Boxed_Value(t_json.ToBool());
} }
throw std::runtime_error("Unknown JSON type"); throw std::runtime_error("Unknown JSON type");
@ -102,24 +102,32 @@ namespace chaiscript
try { try {
Boxed_Number bn(t_bv); Boxed_Number bn(t_bv);
json::JSON obj;
if (Boxed_Number::is_floating_point(t_bv)) if (Boxed_Number::is_floating_point(t_bv))
{ {
return json::JSON(bn.get_as<double>()); obj = bn.get_as<double>();
} else { } else {
return json::JSON(bn.get_as<long>()); obj = bn.get_as<long>();
} }
return obj;
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
// not a number // not a number
} }
try { try {
return json::JSON(boxed_cast<bool>(t_bv)); bool b = boxed_cast<bool>(t_bv);
json::JSON obj;
obj = b;
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) { } catch (const chaiscript::exception::bad_boxed_cast &) {
// not a bool // not a bool
} }
try { try {
return json::JSON(boxed_cast<std::string>(t_bv)); std::string s = boxed_cast<std::string>(t_bv);
json::JSON obj;
obj = s;
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) { } catch (const chaiscript::exception::bad_boxed_cast &) {
// not a string // not a string
} }

View File

@ -1,37 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
namespace chaiscript
{
namespace utility
{
struct Static_String
{
template<size_t N>
constexpr Static_String(const char (&str)[N])
: m_size(N-1), data(&str[0])
{
}
constexpr size_t size() const {
return m_size;
}
constexpr const char *c_str() const {
return data;
}
const size_t m_size;
const char *data = nullptr;
};
}
}
#endif

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ #ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
#define CHAISCRIPT_UTILITY_UTILITY_HPP_ #define CHAISCRIPT_UTILITY_UTILITY_HPP_
@ -16,8 +12,9 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "../language/chaiscript_common.hpp" #include "../chaiscript.hpp"
#include "../dispatchkit/register_function.hpp" #include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp"
#include "../dispatchkit/operators.hpp" #include "../dispatchkit/operators.hpp"
@ -72,50 +69,27 @@ namespace chaiscript
typename std::enable_if<std::is_enum<Enum>::value, void>::type typename std::enable_if<std::is_enum<Enum>::value, void>::type
add_class(ModuleType &t_module, add_class(ModuleType &t_module,
const std::string &t_class_name, const std::string &t_class_name,
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants)
)
{ {
t_module.add(chaiscript::user_type<Enum>(), t_class_name); t_module.add(chaiscript::user_type<Enum>(), t_class_name);
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name); t_module.add(chaiscript::constructor<Enum ()>(), t_class_name);
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name); t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
t_module.add([](){
// add some comparison and assignment operators
using namespace chaiscript::bootstrap::operators; using namespace chaiscript::bootstrap::operators;
equal<Enum>(t_module); return assign<Enum>(not_equal<Enum>(equal<Enum>()));
not_equal<Enum>(t_module); }());
assign<Enum>(t_module);
t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "=="); t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type<Enum>::type &i) { return e == i; }), "==");
t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "=="); t_module.add(chaiscript::fun([](const typename std::underlying_type<Enum>::type &i, const Enum &e) { return i == e; }), "==");
for (const auto &constant : t_constants) for (const auto &constant : t_constants)
{ {
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
} }
} }
template<typename EnumClass, typename ModuleType>
typename std::enable_if<std::is_enum<EnumClass>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<EnumClass, std::string>> &t_constants
)
{
t_module.add(chaiscript::user_type<EnumClass>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass(const EnumClass &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<EnumClass>(t_module);
not_equal<EnumClass>(t_module);
assign<EnumClass>(t_module);
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second);
}
}
} }
} }

View File

@ -1,4 +1,4 @@
Copyright 2009-2016 Jason Turner Copyright 2009-2015 Jason Turner
Copyright 2009-2012 Jonathan Turner. Copyright 2009-2012 Jonathan Turner.
All Rights Reserved. All Rights Reserved.

View File

@ -1,20 +0,0 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
double f(const std::string &, double, bool) noexcept {
return .0;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&f), "f");
chai.eval(R"(
for (var i = 0; i < 100000; ++i) {
f("str", 1.2, false);
}
)");
}

View File

@ -1,20 +0,0 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
double f(const std::string &, double, bool) noexcept {
return .0;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&f), "f");
const auto f = chai.eval<std::function<void ()>>(R"(fun(){ f("str", 1.2, false); })");
for (int i = 0; i < 100000; ++i) {
f();
}
}

View File

@ -1,8 +1,3 @@
<a href="https://www.patreon.com/bePatron?u=2977989&redirect_uri=https%3A%2F%2Fwww.patreon.com%2Flefticus">
<img height="40" width="204" src="https://s3-us-west-1.amazonaws.com/widget-images/become-patron-widget-medium%402x.png">
</a>
Master Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=master)](http://codecov.io/github/ChaiScript/ChaiScript?branch=master) Master Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=master)](http://codecov.io/github/ChaiScript/ChaiScript?branch=master)
Develop Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=develop)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw/branch/develop?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript/branch/develop) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=develop)](http://codecov.io/github/ChaiScript/ChaiScript?branch=develop) Develop Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=develop)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw/branch/develop?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript/branch/develop) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=develop)](http://codecov.io/github/ChaiScript/ChaiScript?branch=develop)
@ -17,7 +12,7 @@ ChaiScript
http://www.chaiscript.com http://www.chaiscript.com
(c) 2009-2012 Jonathan Turner (c) 2009-2012 Jonathan Turner
(c) 2009-2017 Jason Turner (c) 2009-2015 Jason Turner
Release under the BSD license, see "license.txt" for details. Release under the BSD license, see "license.txt" for details.
@ -43,9 +38,10 @@ languages:
Requirements Requirements
============ ============
ChaiScript requires a C++14 compiler to build with support for variadic ChaiScript requires a C++11 compiler to build with support for variadic
templates. It has been tested with gcc 4.9 and clang 3.6 (with libcxx). templates. It has been tested with gcc 4.6 and clang 3.1 (with libcxx). MacOS
For more information see the build 10.8 (Mountain Lion) is also known to support the C++11 build with Apple's
clang 4.0. MSVC 2013 or newer is supports also. For more information see the build
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html). [dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
Usage Usage
@ -79,7 +75,7 @@ directory, and for more in-depth look at the language, the unit tests in the
"unittests" directory cover the most ground. "unittests" directory cover the most ground.
For examples of how to register parts of your C++ application, see For examples of how to register parts of your C++ application, see
"example.cpp" in the "samples" directory. Example.cpp is verbose and shows every "example.cpp" in the "src" directory. Example.cpp is verbose and shows every
possible way of working with the library. For further documentation generate possible way of working with the library. For further documentation generate
the doxygen documentation in the build folder or see the website the doxygen documentation in the build folder or see the website
http://www.chaiscript.com. http://www.chaiscript.com.
@ -87,21 +83,44 @@ http://www.chaiscript.com.
The shortest complete example possible follows: The shortest complete example possible follows:
```C++ /// main.cpp
/// main.cpp
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
double function(int i, double j) double function(int i, double j)
{ {
return i * j; return i * j;
} }
int main() int main()
{ {
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function"); chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);"); double d = chai.eval<double>("function(3, 4.75);");
} }
```
Or, if you want to compile the std lib into your code, which reduces
runtime requirements.
/// main.cpp
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
double function(int i, double j)
{
return i * j;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}

View File

@ -1,99 +1,6 @@
Notes: Notes:
======= =======
Current Version: 6.0.0 Current Version: 5.7.1
### Changes since 5.8.6
*6.0.0 is a massive rework compared to 5.x. It now requires a C++14 enabled compiler*
#### Compiler Requirements
* MSVC 2015 or greater
* g++ 4.9 or greater
* clang 3.6 or greater
#### Breaking Changes
* Instantiating a ChaiScript object now, by default, builds the stdlib in
* This was done to address the most common support issues of loading stdlib dynamically at runtime
* If you want the old behavior, use include/chaiscript/chaiscript_basic.hpp
* Headers have been reorganized to fully separate stdlib/parser/engine from each other (some faster builds)
* Bootstrap functions no longer return a reference to the module added to (compile time savings)
* It's now no longer possible modify AST_Nodes (compile time, runtime efficiency)
* Function annotations no longer exist (simplifies code, reduces compile time, compile size)
#### New Features Added
* Modular optimization system; this can be accessed via the ChaiScript_Basic interface
* Execution tracing capability; also accessed via ChaiScript_Basic interface
* range-based for loops `for( id : container ) { }` (much better performance than other loop types)
* If-init expressions (ala C++17)
* Support for passing r-value references to functions
* Support for containing unique_ptr
* Add helpers for exposing enum classes to ChaiScript
* Allow typed ChaiScript defined functions to perform conversions on call #303
#### Improvements
* Compile time improvements
* Compile size improvements
* Significant runtime improvements (see "Modular optimization system")
* Significant parser improvements, both with parse-time and parser initialization time (Thanks @niXman)
* Fix type conversion to bool in conditionals
#### Improvements Still Need To Be Made
* File location tracking has been rewritten; this currently means error location reporting is not as good as it was
* Tracing capability needs to be tested and vetted
### Changes since 5.8.5
* Optimize away `return` statements in lambdas also
* Allow conversions to bool in conditionals
* Don't allow `class` statements inside of scopes
* Properly error when a dynamic object non-function member is called
### Changes since 5.8.4
* Fix order of operations for prefix operators
* Make sure atomics are initialized properly
* Remove parsing of unused prefix `&` operator
### Changes since 5.8.3
* Fix case with some numeric conversions mixed with numerics that do not need conversion
### Changes since 5.8.2
* Add support for reference of pointer return types
### Changes since 5.8.1
* Allow casting to non-const & std::shared_ptr<T>
### Changes since 5.8.0
* Fix parsing of floats to be locale independent #250
* Various warning fixes on various platforms
### Changes since 5.7.1
* Make all parser iterator operations range checked
* Parse in-string eval statements once, not once for each execution
* Fix parsing of operators (ie 1<-1 now parses)
* Fix variable scoping for functors
* Exception reduction
* Various object lifetime fixes
* Add JSON support for load / save #207
* Numeric overload resolution fixes #209
* Fix long long #208
* Add octal escapes in strings #211
* Fixed sizing of binary literals #213
* Added support for != with bool values #217
* Various value assignment vector fixes
* Fixed broken hex escape sequences from @ChristianKaeser
* Multiply defined symbols fixes #232 @RaptorFactor
* Add add_class<Enum> helper #233 @vrennert
* Cheatsheet fixes #235 @mlamby
* Fix parsing of strings inside of in-string eval statements
* Allow lower-case global keyword
* Enable thread-local on MSVC (should be significant performance boost)
### Changes since 5.7.0 ### Changes since 5.7.0
* Build time reduction * Build time reduction

View File

@ -73,7 +73,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
//Create a new system object and share it with the chaiscript engine //Create a new system object and share it with the chaiscript engine
System system; System system;
chai.add_global(var(&system), "system"); chai.add(var(&system), "system");
//Add a bound callback method //Add a bound callback method
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound"); chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
@ -108,9 +108,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
// A shortcut to using eval is just to use the chai operator() // A shortcut to using eval is just to use the chai operator()
chai("log(\"Test Module\", \"Test Message\");"); chai("log(\"Test Module\", \"Test Message\");");
//Finally, it is possible to register a lambda as a system function, in this //Finally, it is possible to register any std::function as a system function, in this
//way, we can, for instance add a bound member function to the system //way, we can, for instance add a bound member function to the system
chai.add(fun([&system](){ return system.do_callbacks("Bound Test"); }), "do_callbacks"); chai.add(fun(&System::do_callbacks, std::ref(system), std::string("Bound Test")), "do_callbacks");
//Call bound version of do_callbacks //Call bound version of do_callbacks
chai("do_callbacks()"); chai("do_callbacks()");

View File

@ -1,4 +1,5 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
class Entity class Entity
{ {
@ -56,7 +57,7 @@ class Factory
int main() int main()
{ {
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&Entity::width), "width"); chai.add(chaiscript::fun(&Entity::width), "width");
chai.add(chaiscript::fun(&Entity::height), "height"); chai.add(chaiscript::fun(&Entity::height), "height");

View File

@ -1,13 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) // Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <regex> #include <regex>
@ -17,6 +13,7 @@
#endif #endif
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/readline.h> #include <readline/readline.h>
@ -68,7 +65,6 @@ std::vector<std::string> default_search_paths()
{ {
std::vector<std::string> paths; std::vector<std::string> paths;
#ifndef CHAISCRIPT_NO_DYNLOAD
#ifdef CHAISCRIPT_WINDOWS // force no unicode #ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096]; CHAR path[4096];
int size = GetModuleFileNameA(0, path, sizeof(path) - 1); int size = GetModuleFileNameA(0, path, sizeof(path) - 1);
@ -93,24 +89,24 @@ std::vector<std::string> default_search_paths()
std::vector<char> buf(2048); std::vector<char> buf(2048);
ssize_t size = -1; ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0) if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) != -1)
{ {
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), size);
} }
if (exepath.empty()) if (exepath.empty())
{ {
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0) if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) != -1)
{ {
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), size);
} }
} }
if (exepath.empty()) if (exepath.empty())
{ {
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0) if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) != -1)
{ {
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), size);
} }
} }
@ -138,7 +134,6 @@ std::vector<std::string> default_search_paths()
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/"); paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
} }
#endif #endif
#endif // ifndef CHAISCRIPT_NO_DYNLOAD
return paths; return paths;
} }
@ -296,7 +291,7 @@ int main(int argc, char *argv[])
} }
//chaiscript::ChaiScript chai(modulepaths, usepaths); //chaiscript::ChaiScript chai(modulepaths, usepaths);
chaiscript::ChaiScript chai(usepaths); chaiscript::ChaiScript chai(chaiscript::Std_Lib::library(), usepaths);
chai.add(chaiscript::fun(&myexit), "exit"); chai.add(chaiscript::fun(&myexit), "exit");
chai.add(chaiscript::fun(&myexit), "quit"); chai.add(chaiscript::fun(&myexit), "quit");

View File

@ -1,4 +1,5 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
class BaseClass class BaseClass
{ {
@ -43,14 +44,14 @@ class ChaiScriptDerived : public BaseClass
tie(t_funcs.at(1), m_validateValueImpl); tie(t_funcs.at(1), m_validateValueImpl);
} }
std::string doSomething(float f, double d) const override std::string doSomething(float f, double d) const CHAISCRIPT_OVERRIDE
{ {
assert(m_doSomethingImpl); assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d); return m_doSomethingImpl(*this, f, d);
} }
protected: protected:
bool validateValue(const std::string &t_val) override bool validateValue(const std::string &t_val) CHAISCRIPT_OVERRIDE
{ {
assert(m_validateValueImpl); assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val); return m_validateValueImpl(*this, t_val);
@ -69,7 +70,7 @@ class ChaiScriptDerived : public BaseClass
int main() int main()
{ {
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething"); chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue"); chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue"); chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");

View File

@ -1,6 +1,7 @@
#include <iostream> #include <iostream>
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/readline.h> #include <readline/readline.h>
@ -31,9 +32,16 @@ void function(void)
class test class test
{ {
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chaiscript::ChaiScript::State backupState = chai.get_state(); chaiscript::ChaiScript::State backupState;
public: public:
test()
: chai(chaiscript::Std_Lib::library())
{
backupState = chai.get_state();
}
~test(){}
void ResetState() void ResetState()
{ {
chai.set_state(backupState); chai.set_state(backupState);

View File

@ -1,14 +1,12 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp> #include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp> #include <chaiscript/dispatchkit/function_call.hpp>
int main( int /*argc*/ , char * /*argv*/[] ) int main( int /*argc*/ , char * /*argv*/[] )
{ {
chaiscript::ChaiScript ch; chaiscript::ChaiScript ch( chaiscript::Std_Lib::library( ) );
try
{
static const char script[ ] = static const char script[ ] =
R""( R""(
@ -21,7 +19,8 @@ int main( int /*argc*/ , char * /*argv*/[] )
)""; )"";
try
{
ch.eval( script ); ch.eval( script );
} }
catch ( const std::exception &e ) catch ( const std::exception &e )

Some files were not shown because too many files have changed in this diff Show More