Compare commits

..

No commits in common. "develop" and "release-4.x" have entirely different histories.

426 changed files with 10932 additions and 30662 deletions

View File

@ -1,53 +0,0 @@
compilers:
- name: "clang"
version: "3.6"
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.6"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "clang"
build_tag: AddressSanitizer
version: "3.6"
skip_packaging: true
cmake_extra_flags: -DRUN_FUZZY_TESTS:BOOL=TRUE -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
- name: "clang"
build_tag: ThreadSanitizer
version: "3.6"
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
- 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"
version: "4.9"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: "gcc"
version: "4.9"
skip_packaging: true
build_tag: "NoThreads"
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
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:unittests/catch.hpp" --force --suppress="unusedFunction:*"
- name: custom_check
commands:
- ./contrib/check_for_tabs.rb
- ./contrib/check_for_todos.rb

View File

@ -1,5 +0,0 @@
compilers:
- name: clang
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
build_package_generator: TBZ2

View File

@ -1,21 +0,0 @@
compilers:
- name: Visual Studio
version: 14
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
- name: Visual Studio
version: 14
architecture: Win64
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
- name: Visual Studio
version: 14
build_type: Debug
architecture: Win64
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,4 +0,0 @@
results_repository : ChaiScript/ChaiScript-BuildResults
results_path : _posts
results_base_url : https://chaiscript.github.io/ChaiScript-BuildResults
aging_pull_requests_notification: 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,73 +1,25 @@
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:
global:
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
- 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 - sudo apt-get install libboost-dev libboost-all-dev
- pip install --user cpp-coveralls - sudo pip install cpp-coveralls
script: script:
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS . - cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug .
- cmake --build . -- -j2 - make -j2
- 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 - mkdir gcov
- find CMakeFiles/ -name "*.gc*" -exec mv {} gcov/ \;
#after_script: - gcov -d -o gcov gcov/*.gcda
# - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi - coveralls -n -E ".*\.cpp"
after_script:
- contrib/codeanalysis/runcppcheck.sh
notifications: notifications:
email: email:
recipients: recipients:
- jason@emptycrate.com - jason@emptycrate.com
on_success: always on_success: always
on_failure: always on_failure: always
webhooks: env:
urls: global:
- https://webhooks.gitter.im/e/4be9a2720eaa1bb2a6c9 secure: LCUAKUCRtFp2ak81nVLR+jx0C9+Drwx1OR4VzuvH+HNGWFdUZmAIV3R84euDqFC5cUhYYipaeMbiSOJUHE4MNlL58eQZryED6KSL7k7SgxOLpFSspMvuMjIYZLlBWpBneCR/EMDilu+zXEnASfVUMPuLmtY1GAyfSoZboqFProc=
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false

View File

@ -1,94 +1,20 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
cmake_policy(SET CMP0054 NEW)
endif()
IF(BIICODE)
INIT_BIICODE_BLOCK()
ADD_BIICODE_TARGETS()
ELSE()
# Your regular CMakeLists configuration here
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, reflection)" 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(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) set(EXTRA_LINKER_FLAGS "")
if(USE_STD_MAKE_SHARED) if (CMAKE_COMPILER_IS_GNUCC)
add_definitions(-DCHAISCRIPT_USE_STD_MAKE_SHARED)
endif()
if(CMAKE_COMPILER_IS_GNUCC)
option(ENABLE_COVERAGE "Enable Coverage Reporting in GCC" FALSE) option(ENABLE_COVERAGE "Enable Coverage Reporting in GCC" FALSE)
if(ENABLE_COVERAGE) if (ENABLE_COVERAGE)
add_definitions(--coverage -O0) add_definitions(--coverage -O0)
set(LINKER_FLAGS "${LINKER_FLAGS} --coverage") SET(EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} "--coverage")
endif() endif()
endif()
if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(ENABLE_THREAD_SANITIZER "Enable thread sanitizer testing in gcc/clang" FALSE)
if(ENABLE_THREAD_SANITIZER)
add_definitions(-fsanitize=thread -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=thread")
endif()
option(ENABLE_ADDRESS_SANITIZER "Enable address sanitizer testing in gcc/clang" FALSE)
if(ENABLE_ADDRESS_SANITIZER)
add_definitions(-fsanitize=address -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
endif()
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
if(ENABLE_UNDEFINED_SANITIZER)
add_definitions(-fsanitize=undefined -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined")
endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if (ENABLE_LTO)
add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif()
option(GPROF_OUTPUT "Generate profile data" FALSE)
if (GPROF_OUTPUT)
add_definitions(-pg)
set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE)
add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif()
option(PROFILE_USE "Use profile data" FALSE)
if (PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
endif() endif()
@ -102,20 +28,21 @@ 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 4)
set(CPACK_PACKAGE_VERSION_MINOR 0) set(CPACK_PACKAGE_VERSION_MINOR 3)
set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_VERSION_PATCH 1)
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")
set(CPACK_PACKAGE_CONTACT "contact@chaiscript.com") set(CPACK_PACKAGE_CONTACT "contact@chaiscript.com")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "An embedded scripting language for C++") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "An embedded scripting language for C++")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-dev (>=1.36.0)")
set(CPACK_DEBIAN_PACKAGE_SECTION "devel") set(CPACK_DEBIAN_PACKAGE_SECTION "devel")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_RPM_PACKAGE_LICENSE "BSD") set(CPACK_RPM_PACKAGE_LICENSE "BSD")
set(CPACK_RPM_PACKAGE_GROUP "Programming") set(CPACK_RPM_PACKAGE_GROUP "Programming")
set(CPACK_RPM_PACKAGE_REQUIRES "boost-devel >= 1.36.0, boost-thread >= 1.36.0")
set(CHAI_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}) set(CHAI_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
@ -124,384 +51,228 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest) include(CTest)
include(CPack) include(CPack)
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()
if (UNIX AND NOT APPLE)
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
endif()
enable_testing() enable_testing()
message(STATUS "Detecting readline support") message(STATUS "Detecting readline support")
if(READLINE_LIBRARY) if (READLINE_LIBRARY)
message(STATUS "Found: ${READLINE_LIBRARY}") message(STATUS "Found: ${READLINE_LIBRARY}")
set(READLINE_LIB readline) set (READLINE_LIB readline)
add_definitions(/DREADLINE_AVAILABLE) add_definitions(/DREADLINE_AVAILABLE)
else() else(READLINE_LIBRARY)
message(STATUS "Not Found") message(STATUS "Not Found")
set(READLINE_LIB) set (READLINE_LIB )
set(READLINE_FLAG) set (READLINE_FLAG )
endif() endif(READLINE_LIBRARY)
if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_LESS 4.9)
set(CPP11_FLAG "-std=c++1y")
else()
set(CPP11_FLAG "-std=c++14")
endif()
else()
set(CPP11_FLAG "-std=c++14")
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(CMAKE_CL_64)
if (MSVC_VERSION STREQUAL "1800") add_definitions(/bigobj)
# VS2013 doesn't have magic statics endif()
add_definitions(/w44640)
else()
# enum warnings are too noisy on MSVC2013
add_definitions(/w34062)
endif()
add_definitions(/bigobj)
# Note on MSVC compiler flags.
# The code base selective disables warnings as necessary when the compiler is complaining too much
# about something that is perfectly valid, or there is simply no technical way around it
# This particular warning, C4503 is in regards to the decorated names that MSVC generates internally.
# The error did not come up until the move to C++11, but the compiler doesn't give enough information
# to determine where the error is coming from, and the internet provides no real information for
# how to workaround or fix the error. So I'm disabling it globally.
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 -pedantic)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if (APPLE)
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) # -Wno-missing-field-initializers is for boost on macos
else() add_definitions(-Wno-missing-field-initializers -Wno-sign-compare)
add_definitions(-Wnoexcept)
endif() endif()
if(APPLE)
add_definitions(-Wno-sign-compare)
endif()
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" TRUE)
if(USE_LIBCXX)
add_definitions(-stdlib=libc++)
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++")
else()
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
endif()
elseif(CMAKE_COMPILER_IS_GNUCC)
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
endif()
# limitations in MinGW require us to make an optimized build
# for the sake of object sizes or something
if(MINGW OR CYGWIN)
add_definitions(-O3)
endif() endif()
include_directories(include) include_directories(include)
set(Boost_ADDITIONAL_VERSIONS "1.44" "1.44.0" "1.43" "1.43.0" "1.42" "1.42.0" "1.41")
set(Boost_USE_MULTITHREADED ON)
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/dynamic_cast_conversion.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)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
if(NOT MULTITHREAD_SUPPORT_ENABLED) if (MULTITHREAD_SUPPORT_ENABLED)
find_package(Boost 1.36.0 COMPONENTS thread system)
if (Boost_FOUND)
link_directories( ${Boost_LIBRARY_DIRS} )
else()
message(FATAL_ERROR "Can not find Boost")
endif(Boost_FOUND)
if (CMAKE_HOST_UNIX)
add_definitions(-pthread)
list(APPEND LIBS "pthread")
endif()
else()
add_definitions(-DCHAISCRIPT_NO_THREADS) add_definitions(-DCHAISCRIPT_NO_THREADS)
endif() endif()
if(NOT DYNLOAD_ENABLED) if (CMAKE_HOST_UNIX AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
add_definitions(-DCHAISCRIPT_NO_DYNLOAD) list(APPEND LIBS "dl")
endif()
if(CMAKE_HOST_UNIX)
if(DYNLOAD_ENABLED)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
list(APPEND LIBS "dl")
endif()
endif()
if(MULTITHREAD_SUPPORT_ENABLED)
if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE GCC_FULL_VERSION)
if(GCC_FULL_VERSION MATCHES "4.8.1.*ubuntu")
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--no-as-needed -pthread")
else()
set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
endif()
else()
set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
endif()
add_definitions(-pthread)
endif()
endif() endif()
list(APPEND LIBS ${READLINE_LIB}) list(APPEND LIBS ${READLINE_LIB})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}") if (NOT MSVC)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}") # Boost on MSVC does automatic linking
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}") list(APPEND LIBS ${Boost_LIBRARIES})
endif()
add_library(stdlib STATIC static_libs/chaiscript_stdlib.cpp) if (CMAKE_COMPILER_2005)
add_library(parser STATIC static_libs/chaiscript_parser.cpp) # vs2005 is a bit too loud about possible loss of data warnings
# ADD_DEFINITIONS(/wd4244)
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp) endif()
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
set(CHAISCRIPT_LIBS stdlib parser)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIR})
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} ${EXTRA_LINKER_FLAGS})
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} ${EXTRA_LINKER_FLAGS})
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_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} ${EXTRA_LINKER_FLAGS})
add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(factory samples/factory.cpp)
target_link_libraries(factory ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(fun_call_performance samples/fun_call_performance.cpp)
target_link_libraries(fun_call_performance ${LIBS} ${CHAISCRIPT_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} ${EXTRA_LINKER_FLAGS})
set(MODULES stl_extra) add_library(reflection MODULE src/reflection.cpp)
target_link_libraries(reflection ${LIBS} ${EXTRA_LINKER_FLAGS})
set(MODULES stl_extra reflection)
endif() 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)
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)
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2016-06-29.tar.bz2
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
)
file(GLOB FUZZY_CRASH_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/id*)
list(SORT FUZZY_CRASH_TESTS)
file(GLOB FUZZY_EXCEPTION_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/id*)
list(SORT FUZZY_EXCEPTION_TESTS)
foreach(filename ${FUZZY_CRASH_TESTS})
message(STATUS "Adding test ${filename}")
add_test(${filename} chai "-e" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
endforeach()
set_property(TEST ${FUZZY_CRASH_TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_BINARY_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
foreach(filename ${FUZZY_EXCEPTION_TESTS})
message(STATUS "Adding test ${filename}")
add_test(${filename} chai "--exception" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
endforeach()
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
endif()
if(BUILD_TESTING) if(BUILD_TESTING)
# Add catch tests macro
macro(ADD_CATCH_TESTS executable)
if (MSVC)
file(TO_NATIVE_PATH "${QT_LIBRARY_DIR}" QT_LIB_PATH)
set(NEWPATH "${QT_LIB_PATH};$ENV{PATH}")
else()
set(NEWPATH $ENV{PATH})
endif()
get_target_property(target_files ${executable} SOURCES)
foreach(source ${target_files})
if(NOT "${source}" MATCHES "/moc_.*cxx")
string(REGEX MATCH .*cpp source "${source}")
if(source)
file(READ "${source}" contents)
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
foreach(hit ${found_tests})
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
add_test(compiled.${test_name} "${executable}" ${test_name})
set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
endforeach()
endif()
endif()
endforeach()
endmacro()
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE) option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }")
set_property(TEST version_check
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
add_test(version_check_2 chai --version )
set_property(TEST version_check_2
PROPERTY ENVIRONMENT
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
PROPERTY PASS_REGULAR_EXPRESSION "${CHAI_VERSION}"
)
add_test(help chai --help )
set_property(TEST help
PROPERTY ENVIRONMENT
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
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(filename)
endforeach()
if (RUN_PERFORMANCE_TESTS) set_property(TEST ${UNIT_TESTS}
foreach(filename ${PERFORMANCE_TESTS}) PROPERTY ENVIRONMENT
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
"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}/"
) )
if(NOT UNIT_TEST_LIGHT) if (NOT UNIT_TEST_LIGHT)
add_executable(compiled_tests unittests/compiled_tests.cpp) add_executable(utility_test unittests/utility_test.cpp)
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(utility_test ${LIBS} ${EXTRA_LINKER_FLAGS})
ADD_CATCH_TESTS(compiled_tests) add_test(NAME Utility_Test COMMAND utility_test)
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp) add_executable(dynamic_object_test unittests/dynamic_object_test.cpp)
target_link_libraries(static_chaiscript_test ${LIBS}) target_link_libraries(dynamic_object_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Static_ChaiScript_Test COMMAND static_chaiscript_test) add_test(NAME Dynamic_Object_Test COMMAND dynamic_object_test)
add_executable(functor_creation_test unittests/functor_creation_test.cpp)
target_link_libraries(functor_creation_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Functor_Creation_Test COMMAND functor_creation_test)
add_executable(functor_cast_test unittests/functor_cast_test.cpp)
target_link_libraries(functor_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Functor_Cast_Test COMMAND functor_cast_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} ${EXTRA_LINKER_FLAGS})
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test) add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
add_executable(object_lifetime_test unittests/object_lifetime_test.cpp)
target_link_libraries(object_lifetime_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Object_Lifetime_Test COMMAND object_lifetime_test)
add_executable(function_ordering_test unittests/function_ordering_test.cpp)
target_link_libraries(function_ordering_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Function_Ordering_Test COMMAND function_ordering_test)
add_executable(type_info_test unittests/type_info_test.cpp) add_executable(type_info_test unittests/type_info_test.cpp)
target_link_libraries(type_info_test ${LIBS}) target_link_libraries(type_info_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Type_Info_Test COMMAND type_info_test) add_test(NAME Type_Info_Test COMMAND type_info_test)
add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp)
target_link_libraries(eval_catch_exception_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)
add_executable(short_comparison_test unittests/short_comparison_test.cpp)
target_link_libraries(short_comparison_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Short_Comparison_Test COMMAND short_comparison_test)
add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp)
target_link_libraries(expected_eval_errors_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test)
add_executable(set_state_test unittests/set_state_test.cpp)
target_link_libraries(set_state_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Set_State_Test COMMAND set_state_test)
add_executable(simultaneous_chaiscript_test unittests/simultaneous_chaiscript_test.cpp)
target_link_libraries(simultaneous_chaiscript_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Simultaneous_Chaiscript_Test COMMAND simultaneous_chaiscript_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} ${EXTRA_LINKER_FLAGS})
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} ${EXTRA_LINKER_FLAGS})
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test) add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
if(MULTITHREAD_SUPPORT_ENABLED) add_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp)
target_link_libraries(arithmetic_conversions_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test)
if (MULTITHREAD_SUPPORT_ENABLED)
add_executable(multithreaded_test unittests/multithreaded_test.cpp) add_executable(multithreaded_test unittests/multithreaded_test.cpp)
target_link_libraries(multithreaded_test ${LIBS}) target_link_libraries(multithreaded_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Multithreaded_Test COMMAND multithreaded_test) add_test(NAME Multithreaded_Test COMMAND multithreaded_test)
set_property(TEST Multithreaded_Test set_property(TEST Multithreaded_Test
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}/"
) )
endif() endif()
add_executable(multifile_test add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp
unittests/multifile_test_main.cpp unittests/multifile_test_module.cpp)
unittests/multifile_test_chai.cpp target_link_libraries(multifile_test ${LIBS} ${EXTRA_LINKER_FLAGS})
unittests/multifile_test_module.cpp
)
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} ${EXTRA_LINKER_FLAGS})
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(BUILD_TESTING)
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript) install(TARGETS chai ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript )
install(DIRECTORY include/chaiscript DESTINATION include install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp" PATTERN "*.hpp"
PATTERN "*/.svn*" EXCLUDE PATTERN "*/.svn*" EXCLUDE
PATTERN "*/.git*" EXCLUDE PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE) PATTERN "*~" EXCLUDE)
install(DIRECTORY unittests DESTINATION share/chaiscript install(DIRECTORY unittests DESTINATION share/chaiscript
PATTERN "*.chai" PATTERN "*.chai"
PATTERN "*.inc" PATTERN "*.inc"
PATTERN "*/.svn*" EXCLUDE PATTERN "*/.svn*" EXCLUDE
PATTERN "*/.git*" EXCLUDE PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE) PATTERN "*~" EXCLUDE)
install(DIRECTORY samples DESTINATION share/chaiscript install(DIRECTORY samples DESTINATION share/chaiscript
PATTERN "*.chai" PATTERN "*.chai"
PATTERN "*/.svn*" EXCLUDE PATTERN "*/.svn*" EXCLUDE
PATTERN "*/.git*" EXCLUDE PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE) PATTERN "*~" EXCLUDE)
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY) configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc" install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
DESTINATION lib/pkgconfig) DESTINATION lib/pkgconfig)
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)

File diff suppressed because it is too large Load Diff

29
LICENSE
View File

@ -1,29 +0,0 @@
Copyright 2009-2016 Jason Turner
Copyright 2009-2012 Jonathan Turner.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Jason Turner nor Jonathan Turner nor the
name of contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

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

@ -1,5 +0,0 @@
[paths]
include
[parent]
ChaiScript/ChaiScript: 0

View File

@ -1,552 +0,0 @@
# ChaiScript Versioning
ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme. This basically means:
* Major Version Number: API changes / breaking changes
* Minor Version Number: New Features
* Patch Version Number: Minor changes / enhancements
# Initializing ChaiScript
```
chaiscript::ChaiScript chai; // loads stdlib from loadable module on file system
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
```
# Adding Things To The Engine
## Adding a Function / Method / Member
### General
```
chai.add(chaiscript::fun(&function_name), "function_name");
chai.add(chaiscript::fun(&Class::method_name), "method_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
#### Preferred
```
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
```
#### Alternative
```
chai.add(chaiscript::fun(std::static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
```
This overload technique is also used when exposing base member using derived type
```
struct Base
{
int data;
};
struct Derived : public Base
{};
chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
```
### Lambda
```
chai.add(
chaiscript::fun<std::string (bool)>(
[](bool type) {
if (type) { return "x"; }
else { return "y"; }
}), "function_name");
```
### Constructors
```
chai.add(chaiscript::constructor<MyType ()>(), "MyType");
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
```
## Adding Types
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
```
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
```
## Adding Type Conversions
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:
```
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>`
## Adding Objects
```
chai.add(chaiscript::var(somevar), "somevar"); // copied in
chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared between C++ and chai
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::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(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
```
# Using STL
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
```
typedef std::vector<std::pair<int, std::string>> data_list;
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
chai.add(chaiscript::bootstrap::standard_library::pair_type<data_list::value_type>("DataElement"));
chai.add(chaiscript::var(&my_list), "data_list");
chai.eval(R"_(
for(var i=0; i<data_list.size(); ++i)
{
print(to_string(data_list[i].first) + " " + data_list[i].second)
}
)_");
```
# Executing Script
## General
```
chai.eval("print(\"Hello World\")");
chai.eval(R"(print("Hello World"))");
```
## Unboxing Return Values
Returns values are of the type `Boxed_Value` which is meant to be opaque to the programmer. Use one of the unboxing methods to access the internal data.
### Prefered
```
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
```
### Alternative
```
auto v = chai.eval("5.3 + 2.1");
chai.boxed_cast<double>(v); // extracts double value from boxed_value and applies known conversions
chaiscript::boxed_cast<double>(v); // free function version, does not know about conversions
```
### Converting Between Algebraic Types
```
chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with any number type
// which is equivalent to, but much more automatic than:
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
```
double &d = chai.eval("var i = 5.2; i"); // d is now a reference to i in the script
std::shared_ptr<double> d = chai.eval("var i = 5.2; i"); // same result but reference counted
d = 3;
chai.eval("print(i)"); // prints 3
```
## Catching Eval Errors
```
try {
chai.eval("2.3 + \"String\"");
} catch (const chaiscript::exception::eval_error &e) {
std::cout << "Error\n" << e.pretty_print() << '\n';
}
```
## Catching Errors Thrown From Script
```
try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double e) {
} catch (int) {
} catch (float) {
} catch (const std::string &) {
} catch (const std::exception &e) {
// This is the one what will be called in the specific throw() above
}
```
## Sharing Functions
```
auto p = chai.eval<std::function<std::string (double)>>("to_string");
p(5); // calls chaiscript's 'to_string' function, returning std::string("5")
```
Note: backtick treats operators as normal functions
```
auto p = chai.eval<std::function<int (int, int)>>(`+`);
p(5, 6); // calls chaiscript's '+' function, returning 11
```
```
auto p = chai.eval<std::function<std::string (int, double)>>("fun(x,y) { to_string(x) + to_string(y); }");
p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
```
# Language Reference
## Variables
```
var i; // uninitialized variable, can take any value on first assignment;
auto j; // equiv to var
var k = 5; // initialized to 5 (integer)
var l := 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 = 2; // global 'g' now equals 2
global g2;
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
```
var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
var m = ["a":1, "b":2]; // map of string:value pairs
```
Floating point values default to `double` type and integers default to `int` type. All C++ suffixes
such as `f`, `ll`, `u` as well as scientific notation are supported
```
1.0 // double
1.0f // float
1.0l // long double
1 // int
1u // unsigned int
1ul // unsigned long
1ull // unsigned long long
```
Literals are automatically sized, just as in C++. For example: `10000000000` is > 32bits and the appropriate type is used to hold it
on your platform.
## Functions
Note that any type of ChaiScript function can be passed freely to C++ and automatically
converted into an `std::function` object.
### General
```
def myfun(x, y) { x + y; } // last statement in body is the return value
def myfun(x, y) { return x + y; } // equiv
```
### Optionally Typed
```
def myfun(x, int y) { x + y; } // requires y to be an int
```
### With Guards
```
def myfun(x, int y) : y > 5 { x - y; } // only called if y > 5
```
### Methods
Methods and functions are mostly equivalent
```
def string::add(int y) { this + to_string(y); }
def add(string s, int y) { s + to_string(y); } //equiv functionality
// calling new function/method
"a".add(1); // returns a1
add("a", 1); // returns a1, either calling syntax works with either def above
```
### Lambdas
```
var l = fun(x) { x * 15; }
l(2) // returns 30
var a = 13
var m = fun[a](x) { x * a; }
m(3); // a was captured (by reference), returns 39
var n = bind(fun(x,y) { x * y; }, _, 10);
n(2); // returns 20
```
## ChaiScript Defined Types
Define a type called "MyType" with one member value "a" and a getter
### Preferred
```
class MyType {
var value;
def MyType() { this.value = "a"; }
def get_value() { "Value Is: " + this.value; }
};
```
### Alternative
```
attr MyType::value;
def MyType::MyType() { this.value = "a"; }
def MyType::get_value() { "Value Is: " + this.value; }
```
### Using
```
var m = MyType(); // calls constructor
print(m.get_value()); // prints "Value Is: a"
print(get_value(m)); // prints "Value Is: a"
```
## Dynamic Objects
All ChaiScript defined types and generic Dynamic_Object support dynamic parameters
```
var o = Dynamic_Object();
o.f = fun(x) { print(x); }
o.f(3); // prints "3"
```
Implicit 'this' is allowed:
```
var o = Dynamic_Object();
o.x = 3;
o.f = fun(y) { print(this.x + y); }
o.f(10); // prints 13
```
### Option Explicit
If you want to disable dynamic parameter definitions, you can `set_explicit`.
```
class My_Class {
def My_Class() {
this.set_explicit(true);
this.x = 2; // this would fail with explicit set to true
}
};
```
## method_missing
A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate
method cannot be found
```
def method_missing(int i, string name, Vector v) {
print("method_missing(${i}, ${name}), ${v.size()} params");
}
5.bob(1,2,3); // prints "method_missing(5, bob, 3 params)"
```
`method_missing` signature can be either 2 parameters or 3 parameters. If the signature contains two parameters
it is treated as a property. If the property contains a function then additional parameters are passed to
the contained function.
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
## 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
```
eval("4 + 5") // dynamically eval script string and returns value of last statement
eval_file("filename") // evals file and returns value of last statement
use("filename") // evals file exactly once and returns value of last statement
// if the file had already been 'used' nothing happens and undefined is returned
```
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

@ -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

@ -50,7 +50,7 @@ function run_test
# Run multithreaded tests # Run multithreaded tests
echo "****Building multithreaded test" echo "****Building multithreaded test"
pushd src pushd src
g++ multithreaded.cpp -ldl -omultithreaded -I../include -O3 g++ multithreaded.cpp -lboost_thread-mt -ldl -omultithreaded -I../include -O3
echo "****Testing 1 thread runtime" echo "****Testing 1 thread runtime"
/usr/bin/time -p ./multithreaded 1 2> ../../r$1-1threadruntime.out /usr/bin/time -p ./multithreaded 1 2> ../../r$1-1threadruntime.out
echo "****Testing 2 thread runtime" echo "****Testing 2 thread runtime"

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

@ -0,0 +1,10 @@
var my_array=["1", 4, 6.6l, 10ul, "1000", 100, 10.9f ];
for (var j = 0; j < 10000; ++j)
{
for (var i = 0; i < 6; ++i)
{
to_string(my_array[i]);
}
}

View File

@ -22,5 +22,4 @@ def primes(n)
var N = 5000 var N = 5000
print("primes: " + primes(N).to_string()) print("primes: " + primes(N).to_string())

View File

@ -1,12 +1,12 @@
#!/bin/bash #!/bin/bash
pushd .. 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.64/cppcheck-1.64.tar.bz2
tar -xvf cppcheck-1.66.tar.bz2 tar -xvf cppcheck-1.64.tar.bz2
cd cppcheck-1.66 cd cppcheck-1.64
make -j2 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.64/cppcheck --enable=all --inconclusive -I include --inline-suppr --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
echo -n '{ "body": " ' > output.json echo -n '{ "body": " ' > output.json
echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json

View File

@ -38,7 +38,7 @@
************************************************************************************/ ************************************************************************************/
$language_data = array ( $language_data = array (
'LANG_NAME' => 'ChaiScript', 'LANG_NAME' => 'Chaiscript',
'COMMENT_SINGLE' => array(1 => '//'), 'COMMENT_SINGLE' => array(1 => '//'),
'COMMENT_MULTI' => array('/*' => '*/'), 'COMMENT_MULTI' => array('/*' => '*/'),
//Regular Expressions //Regular Expressions
@ -51,7 +51,7 @@ $language_data = array (
'break', 'else', 'else if', 'eval', 'for', 'if', 'return', 'while', 'try', 'catch', 'finally', 'case', 'switch', 'default', 'break', 'else', 'else if', 'eval', 'for', 'if', 'return', 'while', 'try', 'catch', 'finally', 'case', 'switch', 'default',
), ),
2 => array( 2 => array(
'def', 'false', 'fun', 'true', 'var', 'auto', 'attr', 'def', 'false', 'fun', 'true', 'var', 'attr',
), ),
3 => array( 3 => array(
// built in functions // built in functions

View File

@ -52,7 +52,7 @@ syn keyword chaiscriptExceptions try catch throw
syn keyword chaiscriptKeyword def true false attr syn keyword chaiscriptKeyword def true false attr
"Built in types "Built in types
syn keyword chaiscriptType fun var auto syn keyword chaiscriptType fun var
"Built in funcs, keep it simple "Built in funcs, keep it simple
syn keyword chaiscriptFunc eval throw syn keyword chaiscriptFunc eval throw

File diff suppressed because it is too large Load Diff

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,227 +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_DEFINES_HPP_
#define CHAISCRIPT_DEFINES_HPP_
#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_HAS_DECLSPEC
static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required");
#else
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
#endif
#include <vector>
#if defined( _LIBCPP_VERSION )
#define CHAISCRIPT_LIBCPP
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
#define CHAISCRIPT_WINDOWS
#endif
#if defined(_WIN32)
#if defined(__llvm__)
#define CHAISCRIPT_COMPILER_NAME "clang(windows)"
#elif defined(__GNUC__)
#define CHAISCRIPT_COMPILER_NAME "gcc(mingw)"
#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
#if defined(__llvm__)
#define CHAISCRIPT_CLANG
#endif
#ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
#define CHAISCRIPT_UTF16_UTF32
#endif
#ifdef _DEBUG
#define CHAISCRIPT_DEBUG true
#else
#define CHAISCRIPT_DEBUG false
#endif
#include <memory>
#include <string>
#include <cmath>
namespace chaiscript {
static const int version_major = 6;
static const int version_minor = 0;
static const int version_patch = 0;
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>
inline std::shared_ptr<B> make_shared(Arg && ... arg)
{
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_shared<D>(std::forward<Arg>(arg)...);
#else
return std::shared_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...)));
#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

View File

@ -1,71 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_STDLIB_HPP_
#define CHAISCRIPT_STDLIB_HPP_
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "chaiscript_defines.hpp"
#include "language/chaiscript_common.hpp"
#include "dispatchkit/function_call.hpp"
//#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/operators.hpp"
#include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp"
//#include "dispatchkit/boxed_value.hpp"
#include "language/chaiscript_prelude.hpp"
#include "dispatchkit/register_function.hpp"
#include "utility/json_wrap.hpp"
#ifndef CHAISCRIPT_NO_THREADS
#include <future>
#endif
/// @file
///
/// This file generates the standard library that normal ChaiScript usage requires.
namespace chaiscript
{
class Std_Lib
{
public:
static ModulePtr library()
{
auto lib = std::make_shared<Module>();
bootstrap::Bootstrap::bootstrap(*lib);
bootstrap::standard_library::vector_type<std::vector<Boxed_Value> >("Vector", *lib);
bootstrap::standard_library::string_type<std::string>("string", *lib);
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value> >("Map", *lib);
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair", *lib);
#ifndef CHAISCRIPT_NO_THREADS
bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
#endif
json_wrap::library(*lib);
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
return lib;
}
};
}
#endif

View File

@ -1,29 +1,26 @@
// 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-2014, 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_
#include <unordered_map>
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
#include <thread>
#include <mutex> #ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc++11-long-long"
#pragma clang diagnostic ignored "-Wshadow"
#endif
#include <boost/thread.hpp>
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#else #else
#ifndef CHAISCRIPT_NO_THREADS_WARNING
#pragma message ("ChaiScript is compiling without thread safety.") #pragma message ("ChaiScript is compiling without thread safety.")
#endif #endif
#endif
#include "chaiscript_defines.hpp"
/// \file /// \file
/// ///
@ -37,101 +34,56 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
/// If threading is enabled, then this namespace contains std thread classes. /// If threading is enabled, then this namespace contains boost::thread classes.
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided. /// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
/// This allows us to avoid \#ifdef code in the sections that need thread safety. /// This allows us to avoid \#ifdef code in the sections that need thread safety.
namespace threading namespace threading
{ {
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
using boost::unique_lock;
template<typename T> using boost::shared_lock;
using unique_lock = std::unique_lock<T>; using boost::lock_guard;
using boost::shared_mutex;
template<typename T> using boost::recursive_mutex;
using shared_lock = std::unique_lock<T>;
template<typename T>
using lock_guard = std::lock_guard<T>;
using shared_mutex = std::mutex; /// Typesafe thread specific storage. If threading is enabled, this class uses boost::thread_specific_ptr<T>. If
using std::mutex;
using std::recursive_mutex;
/// 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(Thread_Storage &&) = delete;
Thread_Storage &operator=(const Thread_Storage &) = delete;
Thread_Storage &operator=(Thread_Storage &&) = delete;
~Thread_Storage() ~Thread_Storage()
{ {
if (!destroyed) { m_thread_storage.reset();
t().erase(this); }
inline T *operator->() const
{
if (!m_thread_storage.get())
{
m_thread_storage.reset(new T());
} }
return m_thread_storage.get();
} }
inline const T *operator->() const inline T &operator*() const
{ {
return &(t()[const_cast<Thread_Storage *>(this)]); return *(this->operator->());
}
inline const T &operator*() const
{
return t()[const_cast<Thread_Storage *>(this)];
}
inline T *operator->()
{
return &(t()[this]);
}
inline T &operator*()
{
return t()[this];
} }
private: private:
struct Map_Holder { mutable boost::thread_specific_ptr<T> m_thread_storage;
std::unordered_map<Thread_Storage<T> *, T> map;
Map_Holder() = default;
Map_Holder(const Map_Holder &) = delete;
Map_Holder(Map_Holder &&) = delete;
Map_Holder& operator=(Map_Holder &&) = delete;
Map_Holder& operator=(const Map_Holder &&) = delete;
~Map_Holder() {
// here is the theory:
// * If the Map_Holder is destroyed before the Thread_Storage, a flag will get set
// * 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; }
}
};
static std::unordered_map<Thread_Storage<T> *, T> &t()
{
thread_local Map_Holder my_map;
return my_map.map;
}
bool destroyed{false};
}; };
#else // threading disabled #else
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 +92,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 +101,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,10 +113,6 @@ namespace chaiscript
class Thread_Storage class Thread_Storage
{ {
public: public:
explicit Thread_Storage(void *)
{
}
inline T *operator->() const inline T *operator->() const
{ {
return &obj; return &obj;

View File

@ -1,164 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_ANY_HPP_
#define CHAISCRIPT_ANY_HPP_
#include <utility>
namespace chaiscript {
namespace detail {
namespace exception
{
/// \brief Thrown in the event that an Any cannot be cast to the desired type
///
/// It is used internally during function dispatch.
///
/// \sa chaiscript::detail::Any
class bad_any_cast : public std::bad_cast
{
public:
bad_any_cast() = default;
bad_any_cast(const bad_any_cast &) = default;
~bad_any_cast() noexcept override = default;
/// \brief Description of what error occurred
const char * what() const noexcept override
{
return m_what.c_str();
}
private:
std::string m_what = "bad any cast";
};
}
class Any {
private:
struct Data
{
explicit Data(const std::type_info &t_type)
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete;
virtual ~Data() = default;
virtual void *data() = 0;
const std::type_info &type() const
{
return m_type;
}
virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type;
};
template<typename T>
struct Data_Impl : Data
{
explicit Data_Impl(T t_type)
: Data(typeid(T)),
m_data(std::move(t_type))
{
}
void *data() override
{
return &m_data;
}
std::unique_ptr<Data> clone() const override
{
return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
}
Data_Impl &operator=(const Data_Impl&) = delete;
T m_data;
};
std::unique_ptr<Data> m_data;
public:
// construct/copy/destruct
Any() = default;
Any(Any &&) = default;
Any &operator=(Any &&t_any) = default;
Any(const Any &t_any)
{
if (!t_any.empty())
{
m_data = t_any.m_data->clone();
} else {
m_data.reset();
}
}
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
explicit Any(ValueType &&t_value)
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
{
}
Any & operator=(const Any &t_any)
{
Any copy(t_any);
swap(copy);
return *this;
}
template<typename ToType>
ToType &cast() const
{
if (m_data && typeid(ToType) == m_data->type())
{
return *static_cast<ToType *>(m_data->data());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
// modifiers
Any & swap(Any &t_other)
{
std::swap(t_other.m_data, m_data);
return *this;
}
// queries
bool empty() const
{
return !bool(m_data);
}
const std::type_info & type() const
{
if (m_data) {
return m_data->type();
} else {
return typeid(void);
}
}
};
}
}
#endif

View File

@ -1,26 +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-2014, 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_
#include <string>
#include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript {
class Type_Info;
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace exception namespace exception
@ -33,33 +21,32 @@ namespace chaiscript
class bad_boxed_cast : public std::bad_cast class bad_boxed_cast : public std::bad_cast
{ {
public: public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to,
std::string t_what) noexcept const std::string &t_what) throw()
: from(t_from), to(&t_to), m_what(std::move(t_what)) : from(t_from), to(&t_to), m_what(t_what)
{ {
} }
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) throw()
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name()) : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
{ {
} }
explicit bad_boxed_cast(std::string t_what) noexcept bad_boxed_cast(const std::string &t_what) throw()
: m_what(std::move(t_what)) : to(0), m_what(t_what)
{ {
} }
bad_boxed_cast(const bad_boxed_cast &) = default; virtual ~bad_boxed_cast() throw() {}
~bad_boxed_cast() noexcept override = default;
/// \brief Description of what error occurred /// \brief Description of what error occured
const char * what() const noexcept override virtual const char * what() const throw()
{ {
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,85 +1,94 @@
// 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-2014, 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. #include <boost/preprocessor.hpp>
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include <boost/preprocessor/arithmetic/inc.hpp>
#define param(z,n,text) BOOST_PP_CAT(text, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef CHAISCRIPT_BIND_FIRST_HPP_ #ifndef CHAISCRIPT_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_ #define CHAISCRIPT_BIND_FIRST_HPP_
#include <functional> #include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#define BOOST_PP_ITERATION_LIMITS ( 0, 8 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/bind_first.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
# define m BOOST_PP_INC(n)
namespace chaiscript namespace chaiscript
{ {
namespace detail namespace detail
{ {
/// \brief Helper function for binding the first parameter of a class method pointer. Used in chaiscript::fun overloads
template<typename T> /// that take 1 or 2 parameters to pre-bind to the function.
T* get_pointer(T *t) ///
/// \param[in] f method pointer to bind
/// \param[in] o object to bind as first parameter
/// \returns a new boost::function object with one fewer parameters than the function passed in.
template<typename Ret, typename O, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>
bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)), const O &o)
{ {
return t; return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
} }
template<typename T> /// \brief Helper function for binding the first parameter of a const class method pointer. Used in chaiscript::fun overloads
T* get_pointer(const std::reference_wrapper<T> &t) /// that take 1 or 2 parameters to pre-bind to the function.
///
/// \param[in] f method pointer to bind
/// \param[in] o object to bind as first parameter
/// \returns a new boost::function object with one fewer parameters than the function passed in.
template<typename Ret, typename O, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>
bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)) const, const O &o)
{ {
return &t.get(); return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
} }
template<typename O, typename Ret, typename P1, typename ... Param> /// \brief Helper function for binding the first parameter of a function pointer. Used in chaiscript::fun overloads
auto bind_first(Ret (*f)(P1, Param...), O&& o) /// that take 1 or 2 parameters to pre-bind to the function.
///
/// \param[in] f method pointer to bind
/// \param[in] o object to bind as first parameter
/// \returns a new boost::function object with one fewer parameters than the function passed in.
template<typename Ret,typename O BOOST_PP_COMMA_IF(m) BOOST_PP_ENUM_PARAMS(m, typename Param) >
boost::function<Ret (BOOST_PP_ENUM(n, param, Param))>
bind_first(Ret (*f)(BOOST_PP_ENUM_PARAMS(m, Param)), const O &o)
{ {
return [f, o](Param...param) -> Ret { return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
return f(std::forward<O>(o), std::forward<Param>(param)...);
};
} }
template<typename O, typename Ret, typename Class, typename ... Param> /// \brief Helper function for binding the first parameter of a boost::function object. Used in chaiscript::fun overloads
auto bind_first(Ret (Class::*f)(Param...), O&& o) /// that take 1 or 2 parameters to pre-bind to the function.
///
/// \param[in] f method pointer to bind
/// \param[in] o object to bind as first parameter
/// \returns a new boost::function object with one fewer parameters than the function passed in.
template<typename Ret,typename O BOOST_PP_COMMA_IF(m) BOOST_PP_ENUM_PARAMS(m, typename Param) >
boost::function<Ret (BOOST_PP_ENUM(n, param, Param))>
bind_first(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(m, Param))> &f, const O &o)
{ {
return [f, o](Param...param) -> Ret { return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
}
template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(Ret (Class::*f)(Param...) const, O&& o)
{
return [f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
}
template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
{
return [f, o](Param...param) -> Ret {
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());
} }
} }
} }
#undef n
#undef m
#undef param
#endif #endif

View File

@ -1,75 +1,59 @@
// 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-2014, 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 "dispatchkit.hpp"
#include "dynamic_object.hpp"
#include "register_function.hpp" #include "register_function.hpp"
#include "operators.hpp"
#include "boxed_number.hpp"
#include <boost/function_types/result_type.hpp>
#include <sstream>
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
{ {
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type > namespace detail
void array(const std::string &type, Module& m) {
/// \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>
boost::shared_ptr<P1> construct_pod(Boxed_Number v)
{ {
typedef typename std::remove_extent<T>::type ReturnType; boost::shared_ptr<P1> p(new P1());
const auto extent = std::extent<T>::value; Boxed_Value bv(p);
m.add(user_type<T>(), type); Boxed_Number nb(bv);
m.add(fun( nb = v;
[extent](T& t, size_t index)->ReturnType &{ return p;
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
} else {
return t[index];
}
}
), "[]"
);
m.add(fun(
[extent](const T &t, size_t index)->const ReturnType &{
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
} else {
return t[index];
}
}
), "[]"
);
m.add(fun(
[extent](const T &) {
return extent;
}), "size");
} }
}
/// \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 = ModulePtr(new 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 = ModulePtr(new Module()))
{ {
operators::equal<T>(m); operators::equal<T>(m);
operators::greater_than<T>(m); operators::greater_than<T>(m);
@ -77,6 +61,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 +70,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 = ModulePtr(new 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,78 +86,91 @@ 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 = ModulePtr(new Module()))
{ {
m.add(fun([](const Boxed_Number &bn){ return bn.get_as<T>(); }), type); m->add(fun(&detail::construct_pod<T>), type);
return m;
} }
/// Internal function for converting from a string to a value /**
/// uses ostream operator >> to perform the conversion * to_string function for internal use. Uses ostream operator<<
*/
template<typename Input> template<typename Input>
auto parse_string(const std::string &i) std::string to_string(Input i)
-> typename std::enable_if< {
!std::is_same<Input, wchar_t>::value std::stringstream ss;
&& !std::is_same<Input, char16_t>::value ss << i;
&& !std::is_same<Input, char32_t>::value, return ss.str();
Input>::type }
{
std::stringstream ss(i);
Input t;
ss >> t;
return t;
}
/**
* Internal function for converting from a string to a value
* uses ostream operator >> to perform the conversion
*/
template<typename Input> template<typename Input>
auto parse_string(const std::string &) Input parse_string(const std::string &i)
-> typename std::enable_if< {
std::is_same<Input, wchar_t>::value std::stringstream ss(i);
|| std::is_same<Input, char16_t>::value Input t;
|| std::is_same<Input, char32_t>::value, ss >> t;
Input>::type return t;
{ }
throw std::runtime_error("Parsing of wide characters is not yet supported");
}
/// Add all common functions for a POD type. All operators, and
/// common conversions
/**
* Add all common functions for a POD type. All operators, and
* 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 = ModulePtr(new 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(&to_string<T>), "to_string");
m->add(fun(&parse_string<T>), "to_" + name);
return m;
} }
/// "clone" function for a shared_ptr type. This is used in the case /**
/// where you do not want to make a deep copy of an object during cloning * "clone" function for a shared_ptr type. This is used in the case
/// but want to instead maintain the shared_ptr. It is needed internally * where you do not want to make a deep copy of an object during cloning
/// for handling of Proxy_Function object (that is, * but want to instead maintain the shared_ptr. It is needed internally
/// function variables. * for handling of Proxy_Function object (that is,
* function variables.
*/
template<typename Type> template<typename Type>
auto shared_ptr_clone(const std::shared_ptr<Type> &p) boost::shared_ptr<Type> shared_ptr_clone(const boost::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) boost::shared_ptr<typename boost::remove_const<Type>::type>
shared_ptr_unconst_clone(const boost::shared_ptr<typename boost::add_const<Type>::type> &p)
{ {
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p); return boost::const_pointer_cast<typename boost::remove_const<Type>::type>(p);
} }
/// Assignment function for shared_ptr objects, does not perform a copy of the /**
/// object pointed to, instead maintains the shared_ptr concept. * Assignment function for shared_ptr objects, does not perform a copy of the
/// Similar to shared_ptr_clone. Used for Proxy_Function. * object pointed to, instead maintains the shared_ptr concept.
* Similar to shared_ptr_clone. Used for Proxy_Function.
*/
template<typename Type> template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) Boxed_Value ptr_assign(Boxed_Value lhs, const boost::shared_ptr<Type> &rhs)
{ {
if (lhs.is_undef() if (lhs.is_undef()
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get()))) || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
@ -183,12 +182,16 @@ namespace chaiscript
} }
} }
/// Class consisting of only static functions. All default bootstrapping occurs /**
/// from this class. * Class consisting of only static functions. All default bootstrapping occurs
* from this class.
*/
class Bootstrap class Bootstrap
{ {
private: private:
/// Function allowing for assignment of an unknown type to any other value /**
* Function allowing for assignment of an unknown type to any other value
*/
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs)
{ {
if (lhs.is_undef()) if (lhs.is_undef())
@ -201,268 +204,226 @@ namespace chaiscript
static void print(const std::string &s) static void print(const std::string &s)
{ {
fwrite(s.c_str(), 1, s.size(), stdout); std::cout << s;
} }
static void println(const std::string &s) static void println(const std::string &s)
{ {
puts(s.c_str()); std::cout << s << std::endl;
} }
/// Add all arithmetic operators for PODs /**
static void opers_arithmetic_pod(Module& m) * Add all arithmetic operators for PODs
*/
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new 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 /**
/// the remaining parameters are the args to bind into the result * Create a bound function object. The first param is the function to bind
* the remaining parameters are the args to bind into the
* result
*/
static Boxed_Value bind_function(const std::vector<Boxed_Value> &params) static Boxed_Value bind_function(const std::vector<Boxed_Value> &params)
{ {
if (params.empty()) { if (params.size() < 2)
throw exception::arity_error(0, 1); {
throw exception::arity_error(static_cast<int>(params.size()), 2);
} }
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]); Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f,
{
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
}
return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(std::move(f),
std::vector<Boxed_Value>(params.begin() + 1, params.end())))); std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
} }
static bool has_guard(const Const_Proxy_Function &t_pf) static bool has_guard(const Const_Proxy_Function &t_pf)
{ {
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf); boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> pf = boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->get_guard(); if (pf)
{
if (pf->get_guard()) {
return true;
} else {
return false;
}
} else {
return false;
}
} }
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
{ {
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf); boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> pf = boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_guard()) if (pf)
{ {
return pf->get_guard(); if (pf->get_guard())
{
return pf->get_guard();
} else {
throw std::runtime_error("Function does not have a guard");
}
} else { } else {
throw std::runtime_error("Function does not have a guard"); throw std::runtime_error("Function does not have a guard");
} }
} }
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)
{ {
auto v = (b->*f)(); typedef typename boost::function_types::result_type<FunctionType>::type Vector;
Vector v = (b->*f)();
std::vector<Boxed_Value> vbv; std::vector<Boxed_Value> vbv;
for (typename Vector::const_iterator itr = v.begin();
for (const auto &o: v) itr != v.end();
++itr)
{ {
vbv.push_back(const_var(o)); vbv.push_back(const_var(*itr));
} }
return vbv; return vbv;
} }
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->get_parse_tree();
}
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_parse_tree())
{
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
template<typename Function> template<typename Function>
static auto return_boxed_value_vector(const Function &f) static boost::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 boost::bind(&do_return_boxed_value_vector<Function>, f, _1);
return do_return_boxed_value_vector(f, b);
};
} }
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 = ModulePtr(new 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<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::runtime_error>(), "runtime_error");
m.add(user_type<std::logic_error>(), "logic_error"); m->add(chaiscript::base_class<std::exception, std::runtime_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::exception, std::out_of_range>());
m.add(user_type<std::runtime_error>(), "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(boost::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(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::get_attr), "get_attr");
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::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->eval("def Dynamic_Object::clone() { var new_o := Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");
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(&has_guard), "has_guard");
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(&get_guard), "get_guard");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]"); m->add(fun(&Boxed_Value::is_undef), "is_var_undef");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]"); 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_type), "is_type");
m.eval(R"chaiscript( m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
def Dynamic_Object::clone() { m->add(user_type<Type_Info>(), "Type_Info");
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; } );
new_o;
}
def `=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
{
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()
{
var rhs_attrs := rhs.get_attrs();
var lhs_attrs := lhs.get_attrs();
if (rhs_attrs.size() != lhs_attrs.size()) {
true;
} else {
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);
operators::assign<bool>(m); operators::assign<bool>(m);
operators::equal<bool>(m); operators::equal<bool>(m);
operators::not_equal<bool>(m);
m.add(fun([](const std::string &s) { return s; }), "to_string");
m.add(fun([](const bool b) { return std::string(b?"true":"false"); }), "to_string");
m.add(fun(&unknown_assign), "=");
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
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<const std::string &>), "internal_to_string");
m->add(fun(&Bootstrap::bool_to_string), "internal_to_string");
m->add(fun(&unknown_assign), "=");
m->add(fun(&throw_exception), "throw");
m->add(fun(&what), "what");
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);
@ -471,115 +432,35 @@ namespace chaiscript
bootstrap_pod_type<long>("long", m); bootstrap_pod_type<long>("long", m);
bootstrap_pod_type<unsigned int>("unsigned_int", m); bootstrap_pod_type<unsigned int>("unsigned_int", m);
bootstrap_pod_type<unsigned long>("unsigned_long", m); bootstrap_pod_type<unsigned long>("unsigned_long", m);
bootstrap_pod_type<long long>("long_long", m);
bootstrap_pod_type<unsigned long long>("unsigned_long_long", m);
bootstrap_pod_type<size_t>("size_t", m); bootstrap_pod_type<size_t>("size_t", m);
bootstrap_pod_type<char>("char", m); bootstrap_pod_type<char>("char", m);
bootstrap_pod_type<wchar_t>("wchar_t", m); bootstrap_pod_type<boost::int8_t>("int8_t", m);
bootstrap_pod_type<char16_t>("char16_t", m); bootstrap_pod_type<boost::int16_t>("int16_t", m);
bootstrap_pod_type<char32_t>("char32_t", m); bootstrap_pod_type<boost::int32_t>("int32_t", m);
bootstrap_pod_type<std::int8_t>("int8_t", m); bootstrap_pod_type<boost::int64_t>("int64_t", m);
bootstrap_pod_type<std::int16_t>("int16_t", m); bootstrap_pod_type<boost::uint8_t>("uint8_t", m);
bootstrap_pod_type<std::int32_t>("int32_t", m); bootstrap_pod_type<boost::uint16_t>("uint16_t", m);
bootstrap_pod_type<std::int64_t>("int64_t", m); bootstrap_pod_type<boost::uint32_t>("uint32_t", m);
bootstrap_pod_type<std::uint8_t>("uint8_t", m); bootstrap_pod_type<boost::uint64_t>("uint64_t", m);
bootstrap_pod_type<std::uint16_t>("uint16_t", m);
bootstrap_pod_type<std::uint32_t>("uint32_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(Proxy_Function(new dispatch::Dynamic_Proxy_Function(boost::bind(&bind_function, _1))),
"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<boost::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(fun(&ptr_assign<boost::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind"); m->add(fun(&type_match), "type_match");
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) {
t_lhs.assign(t_rhs);
}
), "="
);
m.add(fun(&Boxed_Value::type_match), "type_match");
m.add(chaiscript::fun(&has_parse_tree), "has_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::exception, chaiscript::exception::eval_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::exception, chaiscript::exception::arithmetic_error>());
// 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,
"eval_error",
{ },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
{fun([](const chaiscript::exception::eval_error &t_eval_error) {
std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
std::back_inserter(retval),
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
return retval;
}), "call_stack"} }
);
chaiscript::utility::add_class<chaiscript::File_Position>(m,
"File_Position",
{ constructor<File_Position()>(),
constructor<File_Position(int, int)>() },
{ {fun(&File_Position::line), "line"},
{fun(&File_Position::column), "column"} }
);
chaiscript::utility::add_class<AST_Node>(m,
"AST_Node",
{ },
{ {fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"},
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
const auto children = t_node.get_children();
std::transform(children.begin(), children.end(),
std::back_inserter(retval),
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
return retval;
}), "children"}
}
);
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-2014, 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.
@ -17,19 +13,8 @@
#ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_ #ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_ #define CHAISCRIPT_BOOTSTRAP_STL_HPP_
#include <functional>
#include <memory>
#include <stdexcept>
#include <typeinfo>
#include <vector>
#include "bootstrap.hpp"
#include "boxed_value.hpp"
#include "dispatchkit.hpp" #include "dispatchkit.hpp"
#include "operators.hpp"
#include "proxy_constructors.hpp"
#include "register_function.hpp" #include "register_function.hpp"
#include "type_info.hpp"
namespace chaiscript namespace chaiscript
{ {
@ -41,10 +26,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,38 +60,172 @@ 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 {
template<typename T>
int return_int_impl(const boost::function<typename T::size_type (const T *)> &t_func, const T *t_obj)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
template<typename T> template<typename T>
size_t count(const T &t_target, const typename T::key_type &t_key) boost::function<int (const T *)> return_int(size_t (T::*t_func)() const)
{
return boost::bind(&return_int_impl<T>, boost::function<size_t (const T *)>(boost::mem_fn(t_func)), _1);
}
template<typename T, typename P1>
int return_int_impl(const boost::function<typename T::size_type (const T *, P1)> &t_func, const T *t_obj, P1 p1)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj, p1);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
template<typename T, typename P1>
int return_int_impl_non_const(const boost::function<typename T::size_type (T *, P1)> &t_func, T *t_obj, P1 p1)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj, p1);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
template<typename T, typename P1>
boost::function<int (const T *, P1)> return_int(size_t (T::*t_func)(P1) const)
{
return boost::bind(&return_int_impl<T, P1>, boost::function<size_t (const T *, P1)>(boost::mem_fn(t_func)), _1, _2);
}
template<typename T, typename P1>
boost::function<int (T *, P1)> return_int(size_t (T::*t_func)(P1) )
{
return boost::bind(&return_int_impl_non_const<T, P1>, boost::function<size_t (T*, P1)>(boost::mem_fn(t_func)), _1, _2);
}
template<typename T, typename P1, typename P2>
int return_int_impl(const boost::function<typename T::size_type (const T *, P1, P2)> &t_func, const T *t_obj, P1 p1, P2 p2)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj, p1, p2);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
template<typename StringType, StringType (StringType::*Func)(typename StringType::size_type, typename StringType::size_type) const >
StringType substr_helper(const StringType &str, int begin, int end)
{ {
return t_target.count(t_key); return (str.*Func)(begin, end);
} }
template<typename T, typename P1, typename P2>
boost::function<int (const T *, P1, P2)> return_int(size_t (T::*t_func)(P1, P2) const)
{
return boost::bind(&return_int_impl<T, P1, P2>, boost::function<size_t (const T *, P1, P2)>(boost::mem_fn(t_func)), _1, _2, _3);
}
template<typename T> template<typename T>
void insert(T &t_target, const T &t_other) void insert(T &t_target, const T &t_other)
{ {
@ -120,21 +240,25 @@ 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 = ModulePtr(new 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");
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;
} }
@ -142,8 +266,8 @@ namespace chaiscript
template<typename Type> template<typename Type>
void insert_at(Type &container, int pos, const typename Type::value_type &v) void insert_at(Type &container, int pos, const typename Type::value_type &v)
{ {
auto itr = container.begin(); typename Type::iterator itr = container.begin();
auto end = container.end(); typename Type::iterator end = container.end();
if (pos < 0 || std::distance(itr, end) < pos) if (pos < 0 || std::distance(itr, end) < pos)
{ {
@ -159,8 +283,8 @@ namespace chaiscript
template<typename Type> template<typename Type>
void erase_at(Type &container, int pos) void erase_at(Type &container, int pos)
{ {
auto itr = container.begin(); typename Type::iterator itr = container.begin();
auto end = container.end(); typename Type::iterator end = container.end();
if (pos < 0 || std::distance(itr, end) < (pos-1)) if (pos < 0 || std::distance(itr, end) < (pos-1))
{ {
@ -170,19 +294,14 @@ namespace chaiscript
std::advance(itr, pos); std::advance(itr, pos);
container.erase(itr); container.erase(itr);
} }
} }
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 = ModulePtr(new 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 +309,31 @@ 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 = ModulePtr(new Module()))
{ {
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
typedef typename ContainerType::const_reference(ContainerType::*constindexoper)(size_t) const;
//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(boost::function<typename ContainerType::reference (ContainerType *, int)>
[](ContainerType &c, int index) -> typename ContainerType::reference { (boost::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions m->add(
/// during dispatch. reevaluate fun(boost::function<typename ContainerType::const_reference (const ContainerType *, int)>
return c.at(static_cast<typename ContainerType::size_type>(index)); (boost::mem_fn(static_cast<constindexoper>(&ContainerType::at)))), "[]");
}), "[]");
m.add(
fun(
[](const ContainerType &c, int index) -> typename ContainerType::const_reference {
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
/// 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 = ModulePtr(new Module()))
{ {
copy_constructor<ContainerType>(type, m); basic_constructors<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,102 +341,68 @@ 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 = ModulePtr(new Module()))
{ {
m.add(fun([](const ContainerType *a) { return a->size(); } ), "size"); boost::function<int (const ContainerType *)> f = detail::return_int(&ContainerType::size);
m.add(fun([](const ContainerType *a) { return a->empty(); } ), "empty"); m->add(fun(f), "size");
m.add(fun([](ContainerType *a) { a->clear(); } ), "clear"); m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty");
m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear");
return m;
} }
template <typename ContainerType>
ModulePtr container_type(const std::string& type)
{
auto m = std::make_shared<Module>();
container_type<ContainerType>(type, *m);
return m;
}
/// 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 = ModulePtr(new 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 = ModulePtr(new Module()))
{ {
m.add(fun(&detail::insert_at<ContainerType>), std::string insert_name;
[]()->std::string{ if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { {
return "insert_ref_at"; insert_name = "insert_ref_at";
} else { } else {
return "insert_at"; insert_name = "insert_at";
} }
}());
m->add(fun(&detail::insert_at<ContainerType>), insert_name);
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 = ModulePtr(new 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");
std::string push_back_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
push_back_name = "push_back_ref";
} else {
push_back_name = "push_back";
}
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &); typedef void (ContainerType::*pushback)(const typename ContainerType::value_type &);
m.add(fun(static_cast<push_back>(&ContainerType::push_back)), m->add(fun(static_cast<pushback>(&ContainerType::push_back)), push_back_name);
[&]()->std::string{ m->add(fun(&ContainerType::pop_back), "pop_back");
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
m.eval(
"# Pushes the second value onto the container while making a clone of the value\n"
"def push_back(" + type + " container, x)\n"
"{ \n"
" if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n"
" container.push_back_ref(x) \n"
" } else { \n"
" container.push_back_ref(clone(x)); \n"
" }\n"
"} \n"
);
return "push_back_ref";
} else {
return "push_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,44 +411,24 @@ 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 &, ModulePtr m = ModulePtr(new Module()))
{ {
typedef typename ContainerType::reference (ContainerType::*front_ptr)(); typedef typename ContainerType::reference (ContainerType::*frontptr)();
typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const; typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference);
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference); typedef void (ContainerType::*popptr)();
typedef void (ContainerType::*pop_ptr)();
m.add(fun(static_cast<front_ptr>(&ContainerType::front)), "front"); m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
m.add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front");
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)), std::string push_front_name;
[&]()->std::string{ if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { {
m.eval( push_front_name = "push_front_ref";
"# Pushes the second value onto the front of container while making a clone of the value\n" } else {
"def push_front(" + type + " container, x)\n" push_front_name = "push_front";
"{ \n" }
" if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n"
" container.push_front_ref(x) \n"
" } else { \n"
" container.push_front_ref(clone(x)); \n"
" }\n"
"} \n"
);
return "push_front_ref";
} else {
return "push_front";
}
}());
m.add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front"); m->add(fun(static_cast<pushptr>(&ContainerType::push_front)), push_front_name);
} m->add(fun(static_cast<popptr>(&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 +436,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 = ModulePtr(new 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 +459,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 = ModulePtr(new 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,30 +470,27 @@ 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 = ModulePtr(new Module()))
{ {
m.add(fun(detail::count<ContainerType>), "count"); m->add(fun(boost::function<int (const ContainerType *, const typename ContainerType::key_type &)>(detail::return_int(&ContainerType::count))), "count");
typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &);
m.add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase"); typedef size_t (ContainerType::*erase)(const typename ContainerType::key_type &);
erase eraseptr(&ContainerType::erase);
m.add(fun(&detail::insert<ContainerType>), "insert"); m->add(fun(boost::function<int (ContainerType *, const typename ContainerType::key_type &)>(detail::return_int(eraseptr))), "erase");
m.add(fun(&detail::insert_ref<ContainerType>), m->add(fun(&detail::insert<ContainerType>), "insert");
[]()->std::string{
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) { std::string insert_name;
return "insert_ref"; if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value))
} else { {
return "insert"; insert_name = "insert_ref";
} } else {
}()); insert_name = "insert";
} }
template<typename ContainerType>
ModulePtr unique_associative_container_type(const std::string &type) m->add(fun(&detail::insert_ref<ContainerType>), insert_name);
{
auto m = std::make_shared<Module>();
unique_associative_container_type<ContainerType>(type, *m);
return m; return m;
} }
@ -494,78 +498,39 @@ 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 = ModulePtr(new 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::*elemaccess)(const typename MapType::key_type &);
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<elemaccess>(&MapType::operator[])), "[]");
m.add(fun(static_cast<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>))
{
m.eval(R"(
def Map::`==`(Map rhs) {
if ( rhs.size() != this.size() ) {
return false;
} else {
auto r1 = range(this);
auto r2 = range(rhs);
while (!r1.empty())
{
if (!eq(r1.front().first, r2.front().first) || !eq(r1.front().second, r2.front().second))
{
return false;
}
r1.pop_front();
r2.pop_front();
}
true;
}
} )"
);
}
container_type<MapType>(type, m); container_type<MapType>(type, m);
default_constructible_type<MapType>(type, m);
assignable_type<MapType>(type, m); assignable_type<MapType>(type, m);
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 = ModulePtr(new 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 +538,17 @@ 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 = ModulePtr(new 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; 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");
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,42 +556,61 @@ namespace chaiscript
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{ {
m.eval(R"( m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \
def Vector::`==`(Vector rhs) { if ( rhs.size() != this.size() ) { \
if ( rhs.size() != this.size() ) { return false; \
return false; } else { \
} else { var r1 = range(this); \
auto r1 = range(this); var r2 = range(rhs); \
auto r2 = range(rhs); while (!r1.empty()) \
while (!r1.empty()) { \
{ if (!eq(r1.front(), r2.front())) \
if (!eq(r1.front(), r2.front())) { \
{ return false; \
return false; } \
} r1.pop_front(); \
r1.pop_front(); r2.pop_front(); \
r2.pop_front(); } \
} return true; \
true; } \
} }");
} )"
);
} }
}
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;
} }
namespace detail {
template<typename String>
struct apple_string_workarounds
{
/// The latest version of MacOS has a broken std::string implementation which will not allow
/// us to take pointers to the members. Code compiles, but does not link
/// \todo re-evaluate at some point
static size_t find(const String *s, const String &w, int pos) { return s->find(w, pos); }
static size_t rfind(const String *s, const String &w, size_t pos) { return s->rfind(w, pos); }
static size_t find_first_of(const String *s, const String &w, size_t pos) { return s->find_first_of(w, pos); }
static size_t find_last_of(const String *s, const String &w, size_t pos) { return s->find_last_of(w, pos); }
static size_t find_first_not_of(const String *s, const String &w, size_t pos) { return s->find_first_not_of(w, pos); }
static size_t find_last_not_of(const String *s, const String &w, size_t pos) { return s->find_last_not_of(w, pos); }
static void clear(String *s) { s->clear(); }
static bool empty(const String *s) { return s->empty(); }
static size_t size(const String *s) { return s->size(); }
static std::string substr(const String *s, size_t pos, size_t len) { return s->substr(pos,len); }
static const char *c_str(const String *s) { return s->c_str(); }
static const char *data(const String *s) { return s->data(); }
};
}
/// 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 = ModulePtr(new 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,57 +622,30 @@ 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), std::string push_back_name;
[]()->std::string{ if (typeid(typename String::value_type) == typeid(Boxed_Value))
if (typeid(typename String::value_type) == typeid(Boxed_Value)) { {
return "push_back_ref"; push_back_name = "push_back_ref";
} else { } else {
return "push_back"; push_back_name = "push_back";
} }
}()); m->add(fun(&String::push_back), push_back_name);
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find"); m->add(fun(&detail::apple_string_workarounds<String>::find), "find");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind"); m->add(fun(&detail::apple_string_workarounds<String>::rfind), "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(&detail::apple_string_workarounds<String>::find_first_of), "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(&detail::apple_string_workarounds<String>::find_last_of), "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(&detail::apple_string_workarounds<String>::find_first_not_of), "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(&detail::apple_string_workarounds<String>::find_last_not_of), "find_last_not_of");
m->add(fun(&detail::apple_string_workarounds<String>::clear), "clear");
m.add(fun([](String *s) { s->clear(); } ), "clear"); m->add(fun(&detail::apple_string_workarounds<String>::size), "size");
m.add(fun([](const String *s) { return s->empty(); } ), "empty"); m->add(fun(&detail::apple_string_workarounds<String>::empty), "empty");
m.add(fun([](const String *s) { return s->size(); } ), "size"); m->add(fun(&detail::apple_string_workarounds<String>::substr), "substr");
m->add(fun(&detail::apple_string_workarounds<String>::c_str), "c_str");
m.add(fun([](const String *s) { return s->c_str(); } ), "c_str"); m->add(fun(&detail::apple_string_workarounds<String>::data), "data");
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;
}
/// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html
template<typename FutureType>
void future_type(const std::string &type, Module& m)
{
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");
}
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;
} }
} }
@ -702,5 +654,3 @@ namespace chaiscript
#endif #endif

View File

@ -1,31 +1,26 @@
// 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-2014, 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_
#include "../chaiscript_defines.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "boxed_value.hpp"
#include "boxed_cast_helper.hpp"
#include "dynamic_cast_conversion.hpp"
namespace chaiscript { #include "../chaiscript_threading.hpp"
class Type_Conversions; #include <boost/shared_ptr.hpp>
namespace detail { #include <boost/any.hpp>
namespace exception { #include <boost/function.hpp>
class bad_any_cast; #include <boost/ref.hpp>
} // namespace exception #include <boost/cstdint.hpp>
} // namespace detail #include <boost/type_traits/add_const.hpp>
} // namespace chaiscript #include <boost/type_traits/is_polymorphic.hpp>
#include <boost/integer_traits.hpp>
namespace chaiscript namespace chaiscript
{ {
@ -36,73 +31,84 @@ namespace chaiscript
/// \returns Type equivalent to the requested type /// \returns Type equivalent to the requested type
/// \throws exception::bad_boxed_cast If the requested conversion is not possible /// \throws exception::bad_boxed_cast If the requested conversion is not possible
/// ///
/// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper, /// boxed_cast will attempt to make conversions between value, &, *, boost::shared_ptr, boost::reference_wrapper,
/// and std::function (const and non-const) where possible. boxed_cast is used internally during function /// and boost::function (const and non-const) where possible. boxed_cast is used internally during function
/// dispatch. This means that all of these conversions will be attempted automatically for you during /// dispatch. This means that all of these conversions will be attempted automatically for you during
/// ChaiScript function calls. /// ChaiScript function calls.
/// ///
/// \li non-const values can be extracted as const or non-const /// \li non-const values can be extracted as const or non-const
/// \li const values can be extracted only as const /// \li const values can be extracted only as const
/// \li Boxed_Value constructed from pointer or std::reference_wrapper can be extracted as reference, /// \li Boxed_Value constructed from pointer or boost::reference_wrapper can be extracted as reference,
/// pointer or value types /// pointer or value types
/// \li Boxed_Value constructed from std::shared_ptr or value types can be extracted as reference, /// \li Boxed_Value constructed from boost::shared_ptr or value types can be extracted as reference,
/// pointer, value, or std::shared_ptr types /// pointer, value, or boost::shared_ptr types
/// ///
/// Conversions to std::function objects are attempted as well /// Conversions to boost::function objects are attempted as well
/// ///
/// Example: /// Example:
/// \code /// \code
/// // All of the following should succeed /// // All of the following should succeed
/// chaiscript::Boxed_Value bv(1); /// chaiscript::Boxed_Value bv(1);
/// std::shared_ptr<int> spi = chaiscript::boxed_cast<std::shared_ptr<int> >(bv); /// boost::shared_ptr<int> spi = chaiscript::boxed_cast<boost::shared_ptr<int> >(bv);
/// int i = chaiscript::boxed_cast<int>(bv); /// int i = chaiscript::boxed_cast<int>(bv);
/// int *ip = chaiscript::boxed_cast<int *>(bv); /// int *ip = chaiscript::boxed_cast<int *>(bv);
/// int &ir = chaiscript::boxed_cast<int &>(bv); /// int &ir = chaiscript::boxed_cast<int &>(bv);
/// std::shared_ptr<const int> cspi = chaiscript::boxed_cast<std::shared_ptr<const int> >(bv); /// boost::shared_ptr<const int> cspi = chaiscript::boxed_cast<boost::shared_ptr<const int> >(bv);
/// const int ci = chaiscript::boxed_cast<const int>(bv); /// const int ci = chaiscript::boxed_cast<const int>(bv);
/// const int *cip = chaiscript::boxed_cast<const int *>(bv); /// const int *cip = chaiscript::boxed_cast<const int *>(bv);
/// const int &cir = chaiscript::boxed_cast<const int &>(bv); /// const int &cir = chaiscript::boxed_cast<const int &>(bv);
/// \endcode /// \endcode
/// ///
/// std::function conversion example /// boost::function conversion example
/// \code /// \code
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in /// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
/// std::function<int (int, int)> f = chaiscript::boxed_cast<std::function<int (int, int)> >(bv); /// boost::function<int (int, int)> f = chaiscript::boxed_cast<boost::function<int (int, int)> >(bv);
/// int i = f(2,3); /// int i = f(2,3);
/// 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 Dynamic_Cast_Conversions *t_conversions = 0)
{ {
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 boost::bad_any_cast &) {
} catch (const chaiscript::detail::exception::bad_any_cast &) {
}
}
#ifdef BOOST_MSVC
//Thank you MSVC, yes we know that a constant value is being used in the if
// statment in THIS VERSION of the template instantiation
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
if (t_conversions && (*t_conversions)->convertable_type<Type>()) if (boost::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value && t_conversions)
{ {
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
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
} catch (...) {
try { try {
// try going the other way // std::cout << "trying an up conversion " << typeid(Type).name() << std::endl;
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions)); // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
} catch (const chaiscript::detail::exception::bad_any_cast &) { // either way, we are not responsible if it doesn't work
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions);
} catch (...) {
try {
// std::cout << "trying a down conversion " << typeid(Type).name() << std::endl;
// try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_down_cast<Type>(bv), t_conversions);
} catch (const boost::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
} }
} else {
// If it's not polymorphic, just throw the error, don't waste the time on the
// attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
} else {
// If it's not convertable, just throw the error, don't waste the time on the
// attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
} }
} }

View File

@ -1,270 +1,216 @@
// 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-2014, 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_
#include <memory>
#include <type_traits>
#include "boxed_value.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "boxed_value.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/any.hpp>
#include <boost/ref.hpp>
#include <boost/type_traits/add_const.hpp>
namespace chaiscript namespace chaiscript
{ {
class Type_Conversions_State; class Dynamic_Cast_Conversions;
namespace detail namespace detail
{ {
// Cast_Helper_Inner helper classes // Cast_Helper_Inner helper classes
template<typename T> /**
T* throw_if_null(T *t) * Generic Cast_Helper_Inner, for casting to any type
{ */
if (t) { return t; }
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
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 boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{ {
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr())); if (ob.is_ref())
}
};
template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
{
};
/// Cast_Helper_Inner for casting to a const * type
template<typename Result>
struct Cast_Helper_Inner<const Result *>
{
static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
}
};
/// 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 static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
}
};
template<typename Result>
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
{
};
template<typename Result>
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *>
{
};
/// Cast_Helper_Inner for casting to a & type
template<typename Result>
struct Cast_Helper_Inner<const Result &>
{
static const Result & cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
}
};
/// 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 *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
}
};
/// 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
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> >
{
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob.get().cast<std::shared_ptr<Result> >();
}
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<const Result> >
{
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (!ob.get_type_info().is_const())
{ {
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >()); if (!ob.get_type_info().is_const())
{
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else { } else {
return ob.get().cast<std::shared_ptr<const Result> >(); if (!ob.get_type_info().is_const())
{
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
}
} }
} }
}; };
/// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
{
};
/**
* Cast_Helper_Inner for casting to a const & type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
{ {
}; };
/**
* Cast_Helper_Inner for casting to a const * type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<const Result *>
{ {
}; typedef const Result * Result_Type;
template<typename Result> static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
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> >(); if (ob.is_ref())
return ob.pointer_sentinel(res); {
if (!ob.get_type_info().is_const())
{
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
}
} else {
if (!ob.get_type_info().is_const())
{
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
} else {
return (boost::any_cast<boost::shared_ptr<const Result> >(ob.get())).get();
}
}
} }
}; };
/**
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type * Cast_Helper_Inner for casting to a * 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<Result *>
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (ob.is_ref())
{
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
}
}
};
/**
* Cast_Helper_Inner for casting to a & type
*/
template<typename Result>
struct Cast_Helper_Inner<Result &>
{
typedef typename boost::reference_wrapper<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (ob.is_ref())
{
return boost::any_cast<boost::reference_wrapper<Result> >(ob.get());
} else {
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
}
};
/**
* Cast_Helper_Inner for casting to a boost::shared_ptr<> type
*/
template<typename Result>
struct Cast_Helper_Inner<typename boost::shared_ptr<Result> >
{
typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
/**
* Cast_Helper_Inner for casting to a boost::shared_ptr<const> type
*/
template<typename Result>
struct Cast_Helper_Inner<typename boost::shared_ptr<const Result> >
{
typedef typename boost::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (!ob.get_type_info().is_const())
{
return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
} else {
return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
}
}
};
/**
* Cast_Helper_Inner for casting to a const boost::shared_ptr<> & type
*/
template<typename Result>
struct Cast_Helper_Inner<const boost::shared_ptr<Result> > : Cast_Helper_Inner<boost::shared_ptr<Result> >
{ {
}; };
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 boost::shared_ptr<Result> &> : Cast_Helper_Inner<boost::shared_ptr<Result> >
{ {
}; };
/// Cast_Helper_Inner for casting to a Boxed_Value type /**
* Cast_Helper_Inner for casting to a const boost::shared_ptr<const> & type
*/
template<typename Result>
struct Cast_Helper_Inner<const boost::shared_ptr<const Result> > : Cast_Helper_Inner<boost::shared_ptr<const Result> >
{
};
template<typename Result>
struct Cast_Helper_Inner<const boost::shared_ptr<const Result> &> : Cast_Helper_Inner<boost::shared_ptr<const Result> >
{
};
/**
* Cast_Helper_Inner for casting to a Boxed_Value type
*/
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 const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{ {
return ob; return ob;
} }
}; };
/// Cast_Helper_Inner for casting to a Boxed_Value & type /**
template<> * Cast_Helper_Inner for casting to a const Boxed_Value & type
struct Cast_Helper_Inner<Boxed_Value &> */
{
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::ref(const_cast<Boxed_Value &>(ob));
}
};
/// Cast_Helper_Inner for casting to a const Boxed_Value & type
template<> template<>
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value>
{ {
@ -276,44 +222,50 @@ namespace chaiscript
}; };
/// Cast_Helper_Inner for casting to a std::reference_wrapper type /**
* Cast_Helper_Inner for casting to a boost::reference_wrapper type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<boost::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{ {
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<const boost::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{ {
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<const boost::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &>
{ {
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &> struct Cast_Helper_Inner<boost::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
{ {
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &> struct Cast_Helper_Inner<const boost::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
{ {
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &> struct Cast_Helper_Inner<const boost::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &>
{ {
}; };
/// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner /**
* The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
*/
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 Dynamic_Cast_Conversions *t_conversions)
{ {
return(Cast_Helper_Inner<T>::cast(ob, t_conversions)); return Cast_Helper_Inner<T>::cast(ob, t_conversions);
} }
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,39 @@
// 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-2014, 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_
#include <map>
#include <memory>
#include <type_traits>
#include "../chaiscript_defines.hpp"
#include "any.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "../chaiscript_threading.hpp"
#include <map>
#include <boost/shared_ptr.hpp>
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
#include <boost/make_shared.hpp>
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#include <boost/any.hpp>
#include <boost/function.hpp>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
#include <boost/cstdint.hpp>
#include <boost/type_traits/add_const.hpp>
#include <boost/integer_traits.hpp>
namespace chaiscript namespace chaiscript
{ {
@ -27,23 +42,25 @@ namespace chaiscript
class Boxed_Value class Boxed_Value
{ {
public: public:
/// used for explicitly creating a "void" object /**
* used for explicitly creating a "void" object
*/
struct Void_Type struct Void_Type
{ {
}; };
private: private:
/// structure which holds the internal state of a Boxed_Value /**
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process * structure which holds the internal state of a Boxed_Value
*/
struct Data struct Data
{ {
Data(const Type_Info &ti, Data(const Type_Info &ti,
chaiscript::detail::Any to, const boost::any &to,
bool is_ref, bool tr,
const void *t_void_ptr, const void *t_void_ptr)
bool t_return_value) : m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?0: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(tr)
m_is_ref(is_ref), m_return_value(t_return_value)
{ {
} }
@ -54,339 +71,215 @@ namespace chaiscript
m_is_ref = rhs.m_is_ref; m_is_ref = rhs.m_is_ref;
m_data_ptr = rhs.m_data_ptr; m_data_ptr = rhs.m_data_ptr;
m_const_data_ptr = rhs.m_const_data_ptr; m_const_data_ptr = rhs.m_const_data_ptr;
m_return_value = rhs.m_return_value;
if (rhs.m_attrs)
{
m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
}
return *this; return *this;
} }
Data(const Data &) = delete; ~Data()
{
Data(Data &&) = default; }
Data &operator=(Data &&rhs) = default;
Type_Info m_type_info; Type_Info m_type_info;
chaiscript::detail::Any m_obj; boost::any m_obj;
void *m_data_ptr; void *m_data_ptr;
const void *m_const_data_ptr; const void *m_const_data_ptr;
std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>> m_attrs;
bool m_is_ref; bool m_is_ref;
bool m_return_value;
}; };
struct Object_Data struct Object_Data
{ {
static auto get(Boxed_Value::Void_Type, bool t_return_value) static boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
{ {
return std::make_shared<Data>( return boost::make_shared<Data>(
detail::Get_Type_Info<void>::get(), detail::Get_Type_Info<void>::get(),
chaiscript::detail::Any(), boost::any(),
false, false,
nullptr, static_cast<void *>(0));
t_return_value)
;
} }
template<typename T> template<typename T>
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) static boost::shared_ptr<Data> get(const boost::shared_ptr<T> *obj)
{ {
return get(*obj, t_return_value); return get(*obj);
} }
template<typename T> template<typename T>
static auto get(const std::shared_ptr<T> &obj, bool t_return_value) static boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{ {
return std::make_shared<Data>( return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj), boost::any(obj),
false, false,
obj.get(), obj.get());
t_return_value
);
} }
template<typename T> template<typename T>
static auto get(std::shared_ptr<T> &&obj, bool t_return_value) static boost::shared_ptr<Data> get(T *t)
{ {
auto ptr = obj.get(); return get(boost::ref(*t));
return std::make_shared<Data>( }
template<typename T>
static boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
{
return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)), boost::any(obj),
false,
ptr,
t_return_value
);
}
template<typename T>
static auto get(T *t, bool t_return_value)
{
return get(std::ref(*t), t_return_value);
}
template<typename T>
static auto get(const T *t, bool t_return_value)
{
return get(std::cref(*t), t_return_value);
}
template<typename T>
static auto get(std::reference_wrapper<T> obj, bool t_return_value)
{
auto p = &obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
true, true,
p, obj.get_pointer());
t_return_value
);
} }
template<typename T> template<typename T>
static auto get(std::unique_ptr<T> &&obj, bool t_return_value) static boost::shared_ptr<Data> get(const T& t)
{ {
auto ptr = obj.get(); boost::shared_ptr<T> p(new T(t));
return std::make_shared<Data>( return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))), boost::any(p),
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 ptr = p.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(p)),
false, false,
ptr, p.get());
t_return_value
);
} }
static std::shared_ptr<Data> get() static boost::shared_ptr<Data> get()
{ {
return std::make_shared<Data>( return boost::make_shared<Data>(
Type_Info(), Type_Info(),
chaiscript::detail::Any(), boost::any(),
false, false,
nullptr, static_cast<void *>(0));
false
);
} }
}; };
public: public:
/// Basic Boxed_Value constructor /**
template<typename T, * Basic Boxed_Value constructor
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type> */
explicit Boxed_Value(T &&t, bool t_return_value = false) template<typename T>
: m_data(Object_Data::get(std::forward<T>(t), t_return_value)) explicit Boxed_Value(T t)
: m_data(Object_Data::get(t))
{ {
} }
/// Unknown-type constructor /**
Boxed_Value() = default; * Copy constructor - each copy shares the same data pointer
*/
Boxed_Value(const Boxed_Value &t_so)
: m_data(t_so.m_data)
{
}
Boxed_Value(Boxed_Value&&) = default; /**
Boxed_Value& operator=(Boxed_Value&&) = default; * Unknown-type constructor
Boxed_Value(const Boxed_Value&) = default; */
Boxed_Value& operator=(const Boxed_Value&) = default; Boxed_Value()
: m_data(Object_Data::get())
{
}
~Boxed_Value()
{
}
void swap(Boxed_Value &rhs) void swap(Boxed_Value &rhs)
{ {
std::swap(m_data, rhs.m_data); std::swap(m_data, rhs.m_data);
} }
/// Copy the values stored in rhs.m_data to m_data. /**
/// m_data pointers are not shared in this case * copy the values stored in rhs.m_data to m_data
* m_data pointers are not shared in this case
*/
Boxed_Value assign(const Boxed_Value &rhs) Boxed_Value assign(const Boxed_Value &rhs)
{ {
(*m_data) = (*rhs.m_data); (*m_data) = (*rhs.m_data);
return *this; return *this;
} }
const Type_Info &get_type_info() const noexcept /**
* shared data assignment, same as copy construction
*/
Boxed_Value &operator=(const Boxed_Value &rhs)
{
Boxed_Value temp(rhs);
swap(temp);
return *this;
}
const Type_Info &get_type_info() const
{ {
return m_data->m_type_info; return m_data->m_type_info;
} }
/// return true if the object is uninitialized /**
bool is_undef() const noexcept * return true if the object is uninitialized
*/
bool is_undef() const
{ {
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
{ {
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
{ {
return m_data->m_type_info.bare_equal(ti); return m_data->m_type_info.bare_equal(ti);
} }
bool is_null() const
template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const
{ {
struct Sentinel { return (m_data->m_data_ptr == 0 && m_data->m_const_data_ptr == 0);
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 const boost::any & get() const
{
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
}
const chaiscript::detail::Any & get() const noexcept
{ {
return m_data->m_obj; return m_data->m_obj;
} }
bool is_ref() const noexcept bool is_ref() const
{ {
return m_data->m_is_ref; return m_data->m_is_ref;
} }
bool is_return_value() const noexcept bool is_pointer() const
{
return m_data->m_return_value;
}
void reset_return_value() const noexcept
{
m_data->m_return_value = false;
}
bool is_pointer() const noexcept
{ {
return !is_ref(); return !is_ref();
} }
void *get_ptr() const noexcept void *get_ptr() const
{ {
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
{ {
return m_data->m_const_data_ptr; return m_data->m_const_data_ptr;
} }
Boxed_Value get_attr(const std::string &t_name)
{
if (!m_data->m_attrs)
{
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
}
auto &attr = (*m_data->m_attrs)[t_name];
if (attr) {
return Boxed_Value(attr, Internal_Construction());
} else {
Boxed_Value bv; //default construct a new one
attr = bv.m_data;
return bv;
}
}
Boxed_Value &copy_attrs(const Boxed_Value &t_obj)
{
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);
}
return *this;
}
Boxed_Value &clone_attrs(const Boxed_Value &t_obj)
{
copy_attrs(t_obj);
reset_return_value();
return *this;
}
/// \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
{
return l.get_type_info() == r.get_type_info();
}
private: private:
// necessary to avoid hitting the templated && constructor of Boxed_Value boost::shared_ptr<Data> m_data;
struct Internal_Construction{};
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
: m_data(std::move(t_data)) {
}
std::shared_ptr<Data> m_data = Object_Data::get();
}; };
/// @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, boost::shared_ptr, or boost::reference_type
/// a copy is not made. /// a copy is not made.
/// @param t The value to box /// \param t The value to box
/// ///
/// Example: /// Example:
/// /// \code
/// ~~~{.cpp}
/// int i; /// int i;
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::var(i), "i"); /// chai.add(chaiscript::var(i), "i");
/// chai.add(chaiscript::var(&i), "ip"); /// chai.add(chaiscript::var(&i), "ip");
/// ~~~ /// \endcode
/// ///
/// @sa @ref adding_objects /// \sa \ref addingobjects
template<typename T> template<typename T>
Boxed_Value var(T &&t) Boxed_Value var(T t)
{ {
return Boxed_Value(std::forward<T>(t)); return Boxed_Value(t);
} }
namespace detail { namespace detail {
@ -397,7 +290,7 @@ namespace chaiscript
template<typename T> template<typename T>
Boxed_Value const_var_impl(const T &t) Boxed_Value const_var_impl(const T &t)
{ {
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t)); return Boxed_Value(boost::shared_ptr<typename boost::add_const<T>::type >(new T(t)));
} }
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
@ -408,33 +301,33 @@ namespace chaiscript
template<typename T> template<typename T>
Boxed_Value const_var_impl(T *t) Boxed_Value const_var_impl(T *t)
{ {
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) ); return Boxed_Value( const_cast<typename boost::add_const<T>::type *>(t) );
} }
/// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// \brief Takes a boost::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
/// Does not copy the pointed to value. /// Does not copy the pointed to value.
/// \param[in] t Pointer to make immutable /// \param[in] t Pointer to make immutable
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(const std::shared_ptr<T> &t) Boxed_Value const_var_impl(const boost::shared_ptr<T> &t)
{ {
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) ); return Boxed_Value( boost::const_pointer_cast<typename boost::add_const<T>::type>(t) );
} }
/// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value. /// \brief Takes a boost::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
/// Does not copy the referenced value. /// Does not copy the referenced value.
/// \param[in] t Reference object to make immutable /// \param[in] t Reference object to make immutable
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t) Boxed_Value const_var_impl(const boost::reference_wrapper<T> &t)
{ {
return Boxed_Value( std::cref(t.get()) ); return Boxed_Value( boost::cref(t.get()) );
} }
} }
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type /// \brief Takes an object and returns an immutable Boxed_Value. If the object is a boost::reference or pointer type
/// the value is not copied. If it is an object type, it is copied. /// the value is not copied. If it is an object type, it is copied.
/// \param[in] t Object to make immutable /// \param[in] t Object to make immutable
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
@ -455,30 +348,20 @@ namespace chaiscript
/// chai.add(chaiscript::const_var(Green), "Green"); /// chai.add(chaiscript::const_var(Green), "Green");
/// \endcode /// \endcode
/// ///
/// \todo support C++11 strongly typed enums /// \sa \ref addingobjects
/// \sa \ref adding_objects
template<typename T> template<typename T>
Boxed_Value const_var(const T &t) Boxed_Value const_var(const T &t)
{ {
return detail::const_var_impl(t); return detail::const_var_impl(t);
} }
inline Boxed_Value void_var() {
static const auto v = Boxed_Value(Boxed_Value::Void_Type());
return v; /// \returns true if the two Boxed_Values share the same internal type
static bool type_match(Boxed_Value l, Boxed_Value r)
{
return l.get_type_info() == r.get_type_info();
} }
inline Boxed_Value const_var(bool b) {
static const auto t = detail::const_var_impl(true);
static const auto f = detail::const_var_impl(false);
if (b) {
return t;
} else {
return f;
}
}
} }
#endif #endif

View File

@ -1,107 +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_CALLABLE_TRAITS_HPP_
#define CHAISCRIPT_CALLABLE_TRAITS_HPP_
#include <memory>
namespace chaiscript {
namespace dispatch {
namespace detail {
template<typename Class, typename ... Param>
struct Constructor
{
template<typename ... Inner>
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
return std::make_shared<Class>(std::forward<Inner>(inner)...);
}
};
template<typename Ret, typename Class, typename ... Param>
struct Const_Caller
{
explicit Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
template<typename ... Inner>
Ret operator()(const Class &o, Inner&& ... inner) const {
return (o.*m_func)(std::forward<Inner>(inner)...);
}
Ret (Class::*m_func)(Param...) const;
};
template<typename Ret, typename ... Param>
struct Fun_Caller
{
explicit Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
template<typename ... Inner>
Ret operator()(Inner&& ... inner) const {
return (m_func)(std::forward<Inner>(inner)...);
}
Ret(*m_func)(Param...);
};
template<typename Ret, typename Class, typename ... Param>
struct Caller
{
explicit Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
template<typename ... Inner>
Ret operator()(Class &o, Inner&& ... inner) const {
return (o.*m_func)(std::forward<Inner>(inner)...);
}
Ret (Class::*m_func)(Param...);
};
template<typename T>
struct Arity
{
};
template<typename Ret, typename ... Params>
struct Arity<Ret (Params...)>
{
static const size_t arity = sizeof...(Params);
};
template<typename T>
struct Function_Signature
{
};
template<typename Ret, typename ... Params>
struct Function_Signature<Ret (Params...)>
{
typedef Ret Return_Type;
typedef Ret (Signature)(Params...);
};
template<typename Ret, typename T, typename ... Params>
struct Function_Signature<Ret (T::*)(Params...) const>
{
typedef Ret Return_Type;
typedef Ret (Signature)(Params...);
};
template<typename T>
struct Callable_Traits
{
typedef typename Function_Signature<decltype(&T::operator())>::Signature Signature;
typedef typename Function_Signature<decltype(&T::operator())>::Return_Type Return_Type;
};
}
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,289 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include "type_info.hpp"
#include "boxed_value.hpp"
#include "boxed_cast_helper.hpp"
#include "bad_boxed_cast.hpp"
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_polymorphic.hpp>
#include <boost/type_traits/is_base_of.hpp>
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) throw()
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) throw()
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_dynamic_cast(const std::string &w) throw()
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_dynamic_cast() throw() {}
};
}
namespace detail
{
class Dynamic_Conversion
{
public:
virtual Boxed_Value convert(const Boxed_Value &derived) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &base) const = 0;
const Type_Info &base() const
{
return m_base;
}
const Type_Info &derived() const
{
return m_derived;
}
protected:
Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived)
: m_base(t_base), m_derived(t_derived)
{
}
virtual ~Dynamic_Conversion() {}
private:
Type_Info m_base;
Type_Info m_derived;
};
template<typename From, typename To>
class Dynamic_Caster
{
public:
static Boxed_Value cast(const Boxed_Value &t_from)
{
if (t_from.get_type_info().bare_equal(user_type<From>()))
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
boost::shared_ptr<const To> data
= boost::dynamic_pointer_cast<const To>(detail::Cast_Helper<boost::shared_ptr<const From> >::cast(t_from, 0));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
} else {
boost::shared_ptr<To> data
= boost::dynamic_pointer_cast<To>(detail::Cast_Helper<boost::shared_ptr<From> >::cast(t_from, 0));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, 0);
const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(boost::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, 0);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(boost::ref(data));
}
}
} else {
throw exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Dynamic_Conversion
{
public:
Dynamic_Conversion_Impl()
: Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
{
}
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const
{
return Dynamic_Caster<Derived, Base>::cast(t_derived);
}
};
}
class Dynamic_Cast_Conversions
{
public:
Dynamic_Cast_Conversions()
{
}
Dynamic_Cast_Conversions(const Dynamic_Cast_Conversions &t_other)
: m_conversions(t_other.get_conversions())
{
}
void add_conversion(const boost::shared_ptr<detail::Dynamic_Conversion> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion);
}
template<typename Base, typename Derived>
bool dynamic_cast_converts() const
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
{
return has_conversion(base, derived) || has_conversion(derived, base);
}
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const
{
try {
return get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
}
}
template<typename Derived>
Boxed_Value boxed_dynamic_down_cast(const Boxed_Value &base) const
{
try {
return get_conversion(base.get_type_info(), user_type<Derived>())->convert_down(base);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "Unable to perform dynamic_cast operation");
}
}
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(base, derived) != m_conversions.end();
}
boost::shared_ptr<detail::Dynamic_Conversion> get_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
std::set<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator itr =
find(base, derived);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name());
}
}
private:
std::set<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator find(
const Type_Info &base, const Type_Info &derived) const
{
for (std::set<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
{
return itr;
}
}
return m_conversions.end();
}
std::set<boost::shared_ptr<detail::Dynamic_Conversion> > get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<boost::shared_ptr<detail::Dynamic_Conversion> > m_conversions;
};
typedef boost::shared_ptr<chaiscript::detail::Dynamic_Conversion> Dynamic_Cast_Conversion;
/// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new base class registration for applying to a module or to the chaiscript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the base type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
Dynamic_Cast_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
BOOST_STATIC_ASSERT((boost::is_base_of<Base,Derived>::value));
BOOST_STATIC_ASSERT(boost::is_polymorphic<Base>::value);
BOOST_STATIC_ASSERT(boost::is_polymorphic<Derived>::value);
return boost::shared_ptr<detail::Dynamic_Conversion>(new detail::Dynamic_Conversion_Impl<Base, Derived>());
}
}
#endif

View File

@ -1,130 +1,269 @@
// 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-2014, 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_
#include <map> #include <boost/optional.hpp>
#include <string>
#include <utility>
#include "boxed_value.hpp"
namespace chaiscript {
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace dispatch namespace dispatch
{ {
struct option_explicit_set : std::runtime_error {
explicit option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
{
}
option_explicit_set(const option_explicit_set &) = default;
~option_explicit_set() noexcept override = default;
};
class Dynamic_Object class Dynamic_Object
{ {
public: public:
explicit Dynamic_Object(std::string t_type_name) Dynamic_Object(const std::string &t_type_name)
: m_type_name(std::move(t_type_name)), m_option_explicit(false) : m_type_name(t_type_name)
{ {
} }
Dynamic_Object() = default;
bool is_explicit() const
{
return m_option_explicit;
}
void set_explicit(const bool t_explicit)
{
m_option_explicit = t_explicit;
}
std::string get_type_name() const std::string get_type_name() const
{ {
return m_type_name; return m_type_name;
} }
const Boxed_Value &operator[](const std::string &t_attr_name) const Boxed_Value get_attr(const std::string &t_attr_name)
{
return get_attr(t_attr_name);
}
Boxed_Value &operator[](const std::string &t_attr_name)
{
return get_attr(t_attr_name);
}
const Boxed_Value &get_attr(const std::string &t_attr_name) const
{
auto a = m_attrs.find(t_attr_name);
if (a != m_attrs.end()) {
return a->second;
} else {
throw std::range_error("Attr not found '" + t_attr_name + "' and cannot be added to const obj");
}
}
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)
{ {
return m_attrs[t_attr_name]; return m_attrs[t_attr_name];
} }
Boxed_Value &method_missing(const std::string &t_method_name)
{
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name);
}
return get_attr(t_method_name);
}
const Boxed_Value &method_missing(const std::string &t_method_name) const
{
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(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;
std::map<std::string, Boxed_Value> m_attrs; std::map<std::string, Boxed_Value> m_attrs;
}; };
namespace detail
{
/**
* A Proxy_Function implementation designed for calling a function
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
const std::string &t_type_name,
const Proxy_Function &t_func,
const boost::optional<Type_Info> &t_ti = boost::optional<Type_Info>())
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)),
m_type_name(t_type_name), m_func(t_func), m_ti(t_ti)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
virtual ~Dynamic_Object_Function() {}
virtual bool operator==(const Proxy_Function_Base &f) const
{
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f);
if (df)
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{
return m_func->call_match(vals, t_conversions);
} else {
return false;
}
}
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
{
std::vector<Const_Proxy_Function> fs;
fs.push_back(m_func);
return fs;
}
virtual int get_arity() const
{
return m_func->get_arity();
}
virtual std::string annotation() const
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{
return (*m_func)(params, t_conversions);
} else {
throw exception::guard_error();
}
}
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const
{
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
}
private:
static std::vector<Type_Info> build_param_types(
const std::vector<Type_Info> &t_inner_types, boost::optional<Type_Info> t_objectti)
{
if (t_objectti)
{
std::vector<Type_Info> types(t_inner_types);
assert(types.size() > 1);
assert(types[1].bare_equal(user_type<Boxed_Value>()));
types[1] = *t_objectti;
return types;
} else {
return t_inner_types;
}
}
static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const boost::optional<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions)
{
static Type_Info doti = user_type<Dynamic_Object>();
if (bv.get_type_info().bare_equal(doti))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
if (ti)
{
return bv.get_type_info().bare_equal(*ti);
} else {
return false;
}
}
}
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const boost::optional<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions)
{
if (bvs.size() > 0)
{
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
boost::optional<Type_Info> m_ti;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
const std::string &t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types())),
m_type_name(t_type_name), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
std::vector<Type_Info>::const_iterator begin = tl.begin();
std::vector<Type_Info>::const_iterator end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const
{
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
if (dc)
{
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
std::vector<Boxed_Value> new_vals;
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions);
}
virtual int get_arity() const
{
// "this" is not considered part of the arity
return m_func->get_arity() - 1;
}
virtual std::string annotation() const
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
std::vector<Boxed_Value> new_params;
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
new_params.push_back(bv);
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params, t_conversions);
return bv;
}
private:
std::string m_type_name;
Proxy_Function m_func;
};
}
} }
} }
#endif #endif

View File

@ -1,237 +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_DYNAMIC_OBJECT_DETAIL_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
#include <cassert>
#include <map>
#include <memory>
#include <string>
#include <typeinfo>
#include <utility>
#include <vector>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "proxy_functions.hpp"
#include "type_info.hpp"
#include "dynamic_object.hpp"
namespace chaiscript {
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/// A Proxy_Function implementation designed for calling a function
/// that is automatically guarded based on the first param based on the
/// param's type name
class Dynamic_Object_Function final : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func,
bool t_is_attribute = false)
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>()),
m_is_attribute(t_is_attribute)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func,
const Type_Info &t_ti,
bool t_is_attribute = false)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(t_ti.is_undef()?nullptr:new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>()),
m_is_attribute(t_is_attribute)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
bool operator==(const Proxy_Function_Base &f) const override
{
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else {
return false;
}
}
bool is_attribute_function() const override { return m_is_attribute; }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{
return m_func->call_match(vals, t_conversions);
} else {
return false;
}
}
std::vector<Const_Proxy_Function> get_contained_functions() const override
{
return {m_func};
}
protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{
return (*m_func)(params, t_conversions);
} else {
throw exception::guard_error();
}
}
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override
{
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
}
private:
static std::vector<Type_Info> build_param_types(
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
{
std::vector<Type_Info> types(t_inner_types);
assert(types.size() > 1);
//assert(types[1].bare_equal(user_type<Boxed_Value>()));
types[1] = t_objectti;
return types;
}
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
{
if (bv.get_type_info().bare_equal(m_doti))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
if (ti)
{
return bv.get_type_info().bare_equal(*ti);
} else {
return false;
}
}
}
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
{
if (!bvs.empty())
{
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti;
const bool m_is_attribute;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor final : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
m_type_name(std::move(t_type_name)), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
auto begin = tl.begin();
auto end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
bool operator==(const Proxy_Function_Base &f) const override
{
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);
}
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
{
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions);
}
protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
std::vector<Boxed_Value> new_params{bv};
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params, t_conversions);
return bv;
}
private:
const std::string m_type_name;
const Proxy_Function m_func;
};
}
}
}
#endif

View File

@ -1,28 +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-2014, 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_
#include <memory>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
namespace chaiscript {
class Boxed_Value;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace detail namespace detail
@ -31,22 +17,75 @@ namespace chaiscript
{ {
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 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)
{ {
(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)
{
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)
{
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)
{
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)
{
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);
} }
}; };
} }
@ -101,14 +140,46 @@ namespace chaiscript
/// ///
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects /// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
/// \sa \ref exceptions /// \sa \ref exceptions
typedef std::shared_ptr<detail::Exception_Handler_Base> Exception_Handler; typedef boost::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
/// \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,127 +1,131 @@
// 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-2014, 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_
#include <functional> #include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
#include "boxed_cast.hpp"
#include "function_call_detail.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "callable_traits.hpp" #include "function_call_detail.hpp"
namespace chaiscript {
class Boxed_Value; #include <iostream>
class Type_Conversions_State;
namespace detail {
template <typename T> struct Cast_Helper;
} // namespace detail
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace dispatch namespace dispatch
{ {
/// Build a function caller that knows how to dispatch on a set of functions /**
/// example: * Build a function caller that knows how to dispatch on a set of functions
/// std::function<void (int)> f = * example:
/// build_function_caller(dispatchkit.get_function("print")); * boost::function<void (int)> f =
/// \returns A std::function object for dispatching * build_function_caller(dispatchkit.get_function("print"));
/// \param[in] funcs the set of functions to dispatch on. * \returns A boost::function object for dispatching
* \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) boost::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions)
{ {
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), FunctionType *p=0;
[](const Const_Proxy_Function &f) {
return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
});
if (!has_arity_match) {
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
}
FunctionType *p=nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions); return detail::build_function_caller_helper(p, funcs, t_conversions);
} }
/// Build a function caller for a particular Proxy_Function object /**
/// useful in the case that a function is being pass out from scripting back * Build a function caller for a particular Proxy_Function object
/// into code * useful in the case that a function is being pass out from scripting back
/// example: * into code
/// void my_function(Proxy_Function f) * example:
/// { * void my_function(Proxy_Function f)
/// std::function<void (int)> local_f = * {
/// build_function_caller(f); * boost::function<void (int)> local_f =
/// } * build_function_caller(f);
/// \returns A std::function object for dispatching * }
/// \param[in] func A function to execute. * \returns A boost::function object for dispatching
* \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) boost::function<FunctionType>
functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions)
{ {
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions); std::vector<Const_Proxy_Function> funcs;
funcs.push_back(func);
return functor<FunctionType>(funcs, t_conversions);
} }
/// Helper for automatically unboxing a Boxed_Value that contains a function object /**
/// and creating a typesafe C++ function caller from it. * Helper for automatically unboxing a Boxed_Value that contains a function object
* 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) boost::function<FunctionType>
functor(const Boxed_Value &bv, const Dynamic_Cast_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);
} }
} }
namespace detail{ namespace detail{
/// Cast helper to handle automatic casting to const std::function & /**
* Cast helper to handle automatic casting to const boost::function &
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> &> struct Cast_Helper<const boost::function<Signature> &>
{ {
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) typedef boost::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_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>()))
{ {
return dispatch::functor<Signature>(ob, t_conversions); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions); return Cast_Helper_Inner<const boost::function<Signature> &>::cast(ob, t_conversions);
} }
} }
}; };
/// Cast helper to handle automatic casting to std::function /**
* Cast helper to handle automatic casting to boost::function
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<std::function<Signature> > struct Cast_Helper<boost::function<Signature> >
{ {
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) typedef boost::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_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>()))
{ {
return dispatch::functor<Signature>(ob, t_conversions); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions); return Cast_Helper_Inner<boost::function<Signature> >::cast(ob, t_conversions);
} }
} }
}; };
/// Cast helper to handle automatic casting to const std::function /**
* Cast helper to handle automatic casting to const boost::function
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> > struct Cast_Helper<const boost::function<Signature> >
{ {
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) typedef boost::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_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>()))
{ {
return dispatch::functor<Signature>(ob, t_conversions); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions); return Cast_Helper_Inner<const boost::function<Signature> >::cast(ob, t_conversions);
} }
} }
}; };

View File

@ -1,26 +1,24 @@
// 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-2014, 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. #include <boost/preprocessor.hpp>
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#define addparam(z,n,text) params.push_back((boost::is_reference<Param ## n>::value&&!(boost::is_same<chaiscript::Boxed_Value, typename boost::remove_const<typename boost::remove_reference<Param ## n>::type>::type>::value))?Boxed_Value(boost::ref(BOOST_PP_CAT(p, n))):Boxed_Value(BOOST_PP_CAT(p, n) ));
#define curry(z,n,text) BOOST_PP_CAT(_, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#include <functional> #include <boost/shared_ptr.hpp>
#include <memory> #include <boost/bind.hpp>
#include <boost/function.hpp>
#include <string> #include <string>
#include <type_traits>
#include <vector> #include <vector>
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
namespace chaiscript namespace chaiscript
@ -29,21 +27,17 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
/// Internal helper class for handling the return /**
/// value of a build_function_caller * Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret, bool is_arithmetic> template<typename Ret, bool is_arithmetic>
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 Dynamic_Cast_Conversions &t_conversions)
{ {
if (t_conversions != nullptr) { return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, 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 +48,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 Dynamic_Cast_Conversions &t_conversions)
{ {
if (t_conversions != nullptr) { return Boxed_Number(dispatch::dispatch(t_funcs, params, t_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,83 +62,56 @@ 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 Dynamic_Cast_Conversions &t_conversions)
{ {
if (t_conversions != nullptr) { dispatch::dispatch(t_funcs, params, t_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);
}
} }
}; };
}
}
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 9 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/function_call_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions &t_conversions
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
std::vector<Boxed_Value> params;
BOOST_PP_REPEAT(n, addparam, ~);
return Function_Caller_Ret<Ret, boost::is_arithmetic<Ret>::value>::call(funcs, params, t_conversions);
}
/** /**
* used internally for unwrapping a function call's types * used internally for unwrapping a function call's types
*/ */
template<typename Ret, typename ... Param> template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
struct Build_Function_Caller_Helper boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<Const_Proxy_Function> &funcs,
const Dynamic_Cast_Conversions *t_conversions)
{ {
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
: m_funcs(std::move(t_funcs)),
m_conversions(t_conversions)
{
}
template<typename ... P>
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, {
box<P>(std::forward<P>(param))...
}, &state
);
} 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
);
}
}
template<typename P, typename Q>
static auto box(Q&& q) -> typename std::enable_if<std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
{
return Boxed_Value(std::ref(std::forward<Q>(q)));
}
template<typename P, typename Q>
static auto box(Q&& q) -> typename std::enable_if<!std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
{
return Boxed_Value(std::forward<Q>(q));
}
template<typename P>
static Boxed_Value box(Boxed_Value bv)
{
return bv;
}
std::vector<Const_Proxy_Function> m_funcs;
const Type_Conversions *m_conversions;
};
/// \todo what happens if t_conversions is deleted out from under us?!
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)
{
/*
if (funcs.size() == 1) if (funcs.size() == 1)
{ {
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi = boost::shared_ptr<const Proxy_Function_Impl<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> > pfi =
std::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (Params...)> > boost::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> >
(funcs[0]); (funcs[0]);
if (pfi) if (pfi)
{ {
@ -159,13 +120,16 @@ namespace chaiscript
// looks like this either wasn't a Proxy_Function_Impl or the types didn't match // looks like this either wasn't a Proxy_Function_Impl or the types didn't match
// we cannot make any other guesses or assumptions really, so continuing // we cannot make any other guesses or assumptions really, so continuing
} }
*/
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?t_conversions->get():nullptr)); return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs, (t_conversions?*t_conversions:Dynamic_Cast_Conversions())
BOOST_PP_ENUM_TRAILING(n, curry, ~));
} }
} }
} }
} }
#undef n
#undef addparam
#undef curry
#endif #endif

View File

@ -1,122 +1,36 @@
// 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-2014, 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_
#include <functional>
#include <memory>
#include <type_traits>
#include "boxed_number.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "boxed_number.hpp"
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
namespace chaiscript { #include <stdexcept>
class Boxed_Number; #include <vector>
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace dispatch namespace dispatch
{ {
template<class T, class U> class Proxy_Function_Callable_Impl;
template<class T> class Assignable_Proxy_Function_Impl;
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
{ {
template<typename T, static Boxed_Value handle(const Ret &r)
typename = typename std::enable_if<std::is_pod<typename std::decay<T>::type>::value>::type>
static Boxed_Value handle(T r)
{ {
return Boxed_Value(std::move(r), true); return const_var(r);
}
template<typename T,
typename = typename std::enable_if<!std::is_pod<typename std::decay<T>::type>::value>::type>
static Boxed_Value handle(T &&r)
{
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
}
};
template<typename Ret>
struct Handle_Return<const 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>
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &>
{
};
template<typename 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>
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>>
{
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>>
{
};
template<typename Ret>
struct Handle_Return<std::function<Ret> &>
{
static Boxed_Value handle(std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(f),
std::shared_ptr<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>
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);
} }
}; };
@ -125,77 +39,67 @@ namespace chaiscript
{ {
static Boxed_Value handle(Ret *p) static Boxed_Value handle(Ret *p)
{ {
return Boxed_Value(p, true); return Boxed_Value(p);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret *> struct Handle_Return<boost::shared_ptr<Ret> &>
{ {
static Boxed_Value handle(const Ret *p) static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
{ {
return Boxed_Value(p, true); return Boxed_Value(r);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<boost::shared_ptr<Ret> >
{ {
static Boxed_Value handle(const std::shared_ptr<Ret> &r) static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
{ {
return Boxed_Value(r, true); return Boxed_Value(r);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<const boost::shared_ptr<Ret> &>
{ {
}; static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &>
{
};
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); return Boxed_Value(r);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret &> struct Handle_Return<const Ret &>
{ {
static Boxed_Value handle(const Ret &r) static Boxed_Value handle(const Ret &r)
{ {
return Boxed_Value(std::cref(r), true); return Boxed_Value(boost::cref(r));
} }
}; };
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 &>
{ {
static Boxed_Value handle(Ret &r) static Boxed_Value handle(Ret &r)
{ {
return Boxed_Value(std::ref(r)); return Boxed_Value(boost::ref(r));
}
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(boost::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 +109,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 +157,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 +178,7 @@ namespace chaiscript
{ {
static Boxed_Value handle() static Boxed_Value handle()
{ {
return void_var(); return Boxed_Value(Boxed_Value::Void_Type());
} }
}; };
} }

View File

@ -1,221 +1,455 @@
// 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-2014, 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_
#include "../chaiscript_defines.hpp"
#include "register_function.hpp"
namespace chaiscript namespace chaiscript
{ {
namespace bootstrap namespace bootstrap
{ {
namespace operators namespace operators
{ {
template<typename T> template<typename Ret, typename L, typename R>
void assign(Module& m) Ret assign(L l, R r)
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "="); return (l = r);
}
template<typename Ret, typename L, typename R>
Ret assign_bitwise_and(L l, R r)
{
return (l &= r);
}
template<typename Ret, typename L, typename R>
Ret assign_xor(L l, R r)
{
return (l ^= r);
}
template<typename Ret, typename L, typename R>
Ret assign_bitwise_or(L l, R r)
{
return (l |= r);
}
template<typename Ret, typename L, typename R>
Ret assign_difference(L l, R r)
{
return (l -= r);
}
template<typename Ret, typename L, typename R>
Ret assign_left_shift(L l, R r)
{
return (l <<= r);
}
template<typename Ret, typename L, typename R>
Ret assign_product(L l, R r)
{
return (l *= r);
}
template<typename Ret, typename L, typename R>
Ret assign_quotient(L l, R r)
{
return (l /= r);
}
template<typename Ret, typename L, typename R>
Ret assign_remainder(L l, R r)
{
return (l %= r);
}
template<typename Ret, typename L, typename R>
Ret assign_right_shift(L l, R r)
{
return (l >>= r);
}
template<typename Ret, typename L, typename R>
Ret assign_sum(L l, R r)
{
return (l += r);
}
template<typename Ret, typename L>
Ret prefix_decrement(L l)
{
return (--l);
}
template<typename Ret, typename L>
Ret prefix_increment(L l)
{
return (++l);
}
template<typename Ret, typename L, typename R>
Ret equal(L l, R r)
{
return (l == r);
}
template<typename Ret, typename L, typename R>
Ret greater_than(L l, R r)
{
return (l > r);
}
template<typename Ret, typename L, typename R>
Ret greater_than_equal(L l, R r)
{
return (l >= r);
}
template<typename Ret, typename L, typename R>
Ret less_than(L l, R r)
{
return (l < r);
}
template<typename Ret, typename L, typename R>
Ret less_than_equal(L l, R r)
{
return (l <= r);
}
template<typename Ret, typename L>
Ret logical_compliment(L l)
{
return (!l);
}
template<typename Ret, typename L, typename R>
Ret not_equal(L l, R r)
{
return (l != r);
}
template<typename Ret, typename L, typename R>
Ret addition(L l, R r)
{
return (l + r);
}
template<typename Ret, typename L>
Ret unary_plus(L l)
{
return (+l);
}
template<typename Ret, typename L, typename R>
Ret subtraction(L l, R r)
{
return (l - r);
}
template<typename Ret, typename L>
Ret unary_minus(L l)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4146)
return (-l);
#pragma warning(pop)
#else
return (-l);
#endif
}
template<typename Ret, typename L, typename R>
Ret bitwise_and(L l, R r)
{
return (l & r);
}
template<typename Ret, typename L>
Ret bitwise_compliment(L l)
{
return (~l);
}
template<typename Ret, typename L, typename R>
Ret bitwise_xor(L l, R r)
{
return (l ^ r);
}
template<typename Ret, typename L, typename R>
Ret bitwise_or(L l, R r)
{
return (l | r);
}
template<typename Ret, typename L, typename R>
Ret division(L l, R r)
{
return (l / r);
}
template<typename Ret, typename L, typename R>
Ret left_shift(L l, R r)
{
return l << r;
}
template<typename Ret, typename L, typename R>
Ret multiplication(L l, R r)
{
return l * r;
}
template<typename Ret, typename L, typename R>
Ret remainder(L l, R r)
{
return (l % r);
}
template<typename Ret, typename L, typename R>
Ret right_shift(L l, R r)
{
return (l >> r);
}
template<typename T>
ModulePtr assign(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign<T &, T &, const T&>), "=");
return m;
} }
template<typename T> template<typename T>
void assign_bitwise_and(Module& m) ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&="); m->add(fun(&assign_bitwise_and<T &, T &, const T&>), "&=");
return m;
} }
template<typename T> template<typename T>
void assign_xor(Module& m) ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^="); m->add(fun(&assign_xor<T &, T &, const T&>), "^=");
return m;
} }
template<typename T> template<typename T>
void assign_bitwise_or(Module& m) ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|="); m->add(fun(&assign_bitwise_or<T &, T &, const T&>), "|=");
return m;
} }
template<typename T> template<typename T>
void assign_difference(Module& m) ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-="); m->add(fun(&assign_difference<T &, T &, const T&>), "-=");
return m;
} }
template<typename T> template<typename T>
void assign_left_shift(Module& m) ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<="); m->add(fun(&assign_left_shift<T &, T &, const T&>), "<<=");
return m;
} }
template<typename T> template<typename T>
void assign_product(Module& m) ModulePtr assign_product(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*="); m->add(fun(&assign_product<T &, T &, const T&>), "*=");
return m;
} }
template<typename T> template<typename T>
void assign_quotient(Module& m) ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/="); m->add(fun(&assign_quotient<T &, T &, const T&>), "/=");
return m;
} }
template<typename T> template<typename T>
void assign_remainder(Module& m) ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%="); m->add(fun(&assign_remainder<T &, T &, const T&>), "%=");
return m;
} }
template<typename T> template<typename T>
void assign_right_shift(Module& m) ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>="); m->add(fun(&assign_right_shift<T &, T &, const T&>), ">>=");
return m;
} }
template<typename T> template<typename T>
void assign_sum(Module& m) ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+="); m->add(fun(&assign_sum<T &, T &, const T&>), "+=");
return m;
} }
template<typename T> template<typename T>
void prefix_decrement(Module& m) ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--"); m->add(fun(&prefix_decrement<T &, T &>), "--");
return m;
} }
template<typename T> template<typename T>
void prefix_increment(Module& m) ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++"); m->add(fun(&prefix_increment<T &, T &>), "++");
return m;
} }
template<typename T> template<typename T>
void equal(Module& m) ModulePtr equal(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "=="); m->add(fun(&equal<bool, const T&, const T&>), "==");
return m;
} }
template<typename T> template<typename T>
void greater_than(Module& m) ModulePtr greater_than(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">"); m->add(fun(&greater_than<bool, const T&, const T&>), ">");
return m;
} }
template<typename T> template<typename T>
void greater_than_equal(Module& m) ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">="); m->add(fun(&greater_than_equal<bool, const T&, const T&>), ">=");
return m;
} }
template<typename T> template<typename T>
void less_than(Module& m) ModulePtr less_than(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<"); m->add(fun(&less_than<bool, const T&, const T&>), "<");
return m;
} }
template<typename T> template<typename T>
void less_than_equal(Module& m) ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<="); m->add(fun(&less_than_equal<bool, const T&, const T&>), "<=");
return m;
} }
template<typename T> template<typename T>
void logical_compliment(Module& m) ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!"); m->add(fun(&logical_compliment<bool, const T &>), "!");
return m;
} }
template<typename T> template<typename T>
void not_equal(Module& m) ModulePtr not_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!="); m->add(fun(&not_equal<bool, const T &, const T &>), "!=");
return m;
} }
template<typename T> template<typename T>
void addition(Module& m) ModulePtr addition(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+"); m->add(fun(&addition<T, const T &, const T &>), "+");
return m;
} }
template<typename T> template<typename T>
void unary_plus(Module& m) ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+"); m->add(fun(&unary_plus<T, const T &>), "+");
return m;
} }
template<typename T> template<typename T>
void subtraction(Module& m) ModulePtr subtraction(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-"); m->add(fun(&subtraction<T, const T &, const T &>), "-");
return m;
} }
template<typename T> template<typename T>
void unary_minus(Module& m) ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-"); m->add(fun(&unary_minus<T, const T &>), "-");
return m;
} }
template<typename T> template<typename T>
void bitwise_and(Module& m) ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&"); m->add(fun(&bitwise_and<T, const T &, const T &>), "&");
return m;
} }
template<typename T> template<typename T>
void bitwise_compliment(Module& m) ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~"); m->add(fun(&bitwise_compliment<T, const T &>), "~");
return m;
} }
template<typename T> template<typename T>
void bitwise_xor(Module& m) ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^"); m->add(fun(&bitwise_xor<T, const T &, const T &>), "^");
return m;
} }
template<typename T> template<typename T>
void bitwise_or(Module& m) ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|"); m->add(fun(&bitwise_or<T, const T &, const T &>), "|");
return m;
} }
template<typename T> template<typename T>
void division(Module& m) ModulePtr division(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/"); m->add(fun(&division<T, const T &, const T &>), "/");
return m;
} }
template<typename T> template<typename T>
void left_shift(Module& m) ModulePtr left_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<"); m->add(fun(&left_shift<T, const T &, const T &>), "<<");
return m;
} }
template<typename T> template<typename T>
void multiplication(Module& m) ModulePtr multiplication(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*"); m->add(fun(&multiplication<T, const T &, const T &>), "*");
return m;
} }
template<typename T> template<typename T>
void remainder(Module& m) ModulePtr remainder(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%"); m->add(fun(&remainder<T, const T &, const T &>), "%");
return m;
} }
template<typename T> template<typename T>
void right_shift(Module& m) ModulePtr right_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>"); m->add(fun(&right_shift<T, const T &, const T &>), ">>");
return m;
} }
} }
} }

View File

@ -1,37 +1,27 @@
// 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-2014, 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. #include <boost/preprocessor.hpp>
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef BOOST_PP_IS_ITERATING
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include "proxy_functions.hpp" #include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_constructors.hpp>
#include BOOST_PP_ITERATE()
# endif
namespace chaiscript namespace chaiscript
{ {
namespace dispatch
{
namespace detail
{
template<typename Class, typename ... Params >
Proxy_Function build_constructor_(Class (*)(Params...))
{
auto call = dispatch::detail::Constructor<Class, Params...>();
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
}
}
}
/// \brief Generates a constructor function for use with ChaiScript /// \brief Generates a constructor function for use with ChaiScript
/// ///
/// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...) /// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
@ -46,11 +36,46 @@ namespace chaiscript
template<typename T> template<typename T>
Proxy_Function constructor() Proxy_Function constructor()
{ {
T *f = nullptr; T *f = 0;
return (dispatch::detail::build_constructor_(f)); return (dispatch::detail::build_constructor_(f));
} }
} }
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/**
* A constructor function, used for creating a new object
* of a given type with a given set of params
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::shared_ptr<Class> constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, p) ));
}
/**
* Helper function for build a constructor function
* example:
* dispatchengine.register_function(build_constructor<MyClass, int, const std::string&>, "MyClass");
* \todo See if it is possible to make this not be a variadic function
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
typedef boost::shared_ptr<Class> (sig)(BOOST_PP_ENUM_PARAMS(n, Param));
return Proxy_Function(new Proxy_Function_Impl<sig>(boost::function<sig>(&(constructor_<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>))));
}
}
}
}
#undef n
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +1,29 @@
// 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-2014, 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. #include <boost/preprocessor.hpp>
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#define gettypeinfo(z,n,text) ti.push_back(chaiscript::detail::Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) BOOST_PP_COMMA_IF(n) chaiscript::boxed_cast< Param ## n >(params[n], &t_conversions)
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n], &t_conversions);
#ifndef BOOST_PP_IS_ITERATING
#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 "boxed_value.hpp"
#include "boxed_cast.hpp"
#include "type_info.hpp"
#include "handle_return.hpp"
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <array>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_value.hpp"
#include "handle_return.hpp"
#include "type_info.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Type_Conversions_State;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
@ -46,15 +41,26 @@ namespace chaiscript
{ {
} }
arity_error(const arity_error &) = default; virtual ~arity_error() throw() {}
~arity_error() noexcept override = default;
int got; int got;
int expected; int expected;
}; };
} }
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_functions_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace dispatch namespace dispatch
{ {
namespace detail namespace detail
@ -63,77 +69,135 @@ namespace chaiscript
* Used by Proxy_Function_Impl to return a list of all param types * Used by Proxy_Function_Impl to return a list of all param types
* it contains. * it contains.
*/ */
template<typename Ret, typename ... Params> template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) std::vector<Type_Info> build_param_type_list(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{ {
/// \note somehow this is responsible for a large part of the code generation std::vector<Type_Info> ti;
return { user_type<Ret>(), user_type<Params>()... }; ti.push_back(chaiscript::detail::Get_Type_Info<Ret>::get());
BOOST_PP_REPEAT(n, gettypeinfo, ~)
return ti;
} }
/** /**
* Used by Proxy_Function_Impl to determine if it is equivalent to another * Used by Proxy_Function_Impl to perform typesafe execution of a function.
* Proxy_Function_Impl object. This function is primarily used to prevent * The function attempts to unbox each paramter to the expected type.
* registration of two functions with the exact same signatures * if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/ */
template<typename Ret, typename ... Params> #ifdef BOOST_MSVC
bool compare_types_cast(Ret (*)(Params...), #pragma warning(push)
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) #pragma warning(disable : 4100)
#endif
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Ret call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions & BOOST_PP_IF(n, t_conversions, BOOST_PP_EMPTY))
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
{ {
try { if (params.size() != n)
std::vector<Boxed_Value>::size_type i = 0; {
(void)i; throw exception::arity_error(static_cast<int>(params.size()), n);
(void)params; (void)t_conversions; } else {
// this is ok because the order of evaluation of initializer lists is well defined return f(BOOST_PP_REPEAT(n, casthelper, ~));
(void)std::initializer_list<int>{(boxed_cast<Params>(params[i++], &t_conversions), 0)...};
return true;
} catch (const exception::bad_boxed_cast &) {
return false;
} }
} }
#ifdef BOOST_MSVC
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &,
std::index_sequence<I...>, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
(void)params; (void)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.
/// 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>
Boxed_Value 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)
{
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, 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
// MSVC is reporting that this is unreachable code - and it's wrong.
return Handle_Return<void>::handle();
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop) #pragma warning(pop)
#endif #endif
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent
* registration of two functions with the exact same signatures
*/
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4100)
#endif
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types_cast(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
const std::vector<Boxed_Value> & BOOST_PP_IF(n, params, BOOST_PP_EMPTY), const Dynamic_Cast_Conversions &t_conversions)
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
{
try {
(void)t_conversions;
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const exception::bad_boxed_cast &) {
return false;
}
return true;
} }
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
} }
} }
} }
#undef n
#undef gettypeinfo
#undef casthelper
#undef trycast
#endif
#ifndef BOOST_PP_IS_ITERATING
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
template<typename Ret>
struct Do_Call
{
template<typename Fun>
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
}
};
template<>
struct Do_Call<void>
{
template<typename Fun>
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
call_func(fun, params, t_conversions);
return Handle_Return<void>::handle();
}
};
}
}
}
#endif #endif

View File

@ -1,23 +1,86 @@
// 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-2014, 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_
#include <type_traits> #include "dispatchkit.hpp"
#include "bind_first.hpp" #include "bind_first.hpp"
#include "proxy_functions.hpp" #include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/function_types/components.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/is_member_object_pointer.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
namespace chaiscript namespace chaiscript
{ {
namespace dispatch
{
namespace detail
{
template<bool Object, bool MemFn>
struct Fun_Helper
{
template<typename T>
static Proxy_Function go(T t)
{
return Proxy_Function(
new Proxy_Function_Impl<
typename boost::function_types::function_type<boost::function_types::components<T> >::type> (
boost::function<
typename boost::function_types::function_type<boost::function_types::components<T> >::type
>(t)));
}
};
template<>
struct Fun_Helper<false, true>
{
template<typename T>
static Proxy_Function go(T t)
{
return Proxy_Function(
new Proxy_Function_Impl<
typename boost::function_types::function_type<boost::function_types::components<T> >::type> (
boost::function<
typename boost::function_types::function_type<boost::function_types::components<T> >::type
>(boost::mem_fn(t))));
}
};
template<>
struct Fun_Helper<true, false>
{
template<typename T, typename Class>
static Proxy_Function go(T Class::* m)
{
return Proxy_Function(new Attribute_Access<T, Class>(m));
}
};
}
}
/// \brief Creates a new Proxy_Function object from a boost::function object
/// \param[in] f boost::function to expose to ChaiScript
///
/// \b Example:
/// \code
/// boost::function<int (char, float, std::string)> f = get_some_function();
/// chaiscript::ChaiScript chai;
/// chai.add(fun(f), "some_function");
/// \endcode
///
/// \sa \ref addingfunctions
template<typename T>
Proxy_Function fun(const boost::function<T> &f)
{
return Proxy_Function(new dispatch::Proxy_Function_Impl<T>(f));
}
/// \brief Creates a new Proxy_Function object from a free function, member function or data member /// \brief Creates a new Proxy_Function object from a free function, member function or data member
/// \param[in] t Function / member to expose /// \param[in] t Function / member to expose
@ -38,55 +101,13 @@ namespace chaiscript
/// chai.add(fun(&MyClass::memberdata), "memberdata"); /// chai.add(fun(&MyClass::memberdata), "memberdata");
/// \endcode /// \endcode
/// ///
/// \sa \ref adding_functions /// \sa \ref addingfunctions
template<typename T> template<typename T>
Proxy_Function fun(const T &t) Proxy_Function fun(T t)
{ {
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature; return dispatch::detail::Fun_Helper<boost::function_types::is_member_object_pointer<T>::value, boost::function_types::is_member_function_pointer<T>::value>::go(t);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
} }
template<typename Ret, typename ... Param>
Proxy_Function fun(Ret (*func)(Param...))
{
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...) const)
{
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...))
{
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
}
template<typename T, typename Class /*, typename = typename std::enable_if<std::is_member_object_pointer<T>::value>::type*/>
Proxy_Function fun(T Class::* m /*, typename std::enable_if<std::is_member_object_pointer<T>::value>::type* = 0*/ )
{
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<T, Class>>(m));
}
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it /// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
/// \param[in] t Function / member to expose /// \param[in] t Function / member to expose
/// \param[in] q Value to bind to first parameter /// \param[in] q Value to bind to first parameter
@ -101,16 +122,41 @@ namespace chaiscript
/// MyClass obj; /// MyClass obj;
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// // Add function taking only one argument, an int, and permanently bound to "obj" /// // Add function taking only one argument, an int, and permanently bound to "obj"
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction"); /// chai.add(fun(&MyClass::memberfunction, boost::ref(obj)), "memberfunction");
/// \endcode /// \endcode
/// ///
/// \sa \ref adding_functions /// \sa \ref addingfunctions
template<typename T, typename Q> template<typename T, typename Q>
Proxy_Function fun(T &&t, const Q &q) Proxy_Function fun(T t, const Q &q)
{ {
return fun(detail::bind_first(std::forward<T>(t), q)); return fun(detail::bind_first(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, boost::ref(obj), 1), "memberfunction");
/// \endcode
///
/// \sa \ref addingfunctions
template<typename T, typename Q, typename R>
Proxy_Function fun(T t, const Q &q, const R &r)
{
return fun(detail::bind_first(detail::bind_first(t, q), 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,649 +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
// 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_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <atomic>
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
: 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_cast(t_from, t_to)
{
}
explicit bad_boxed_dynamic_cast(const std::string &w) noexcept
: bad_boxed_cast(w)
{
}
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
~bad_boxed_dynamic_cast() noexcept override = default;
};
class bad_boxed_type_cast : public bad_boxed_cast
{
public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
: 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_cast(t_from, t_to)
{
}
explicit bad_boxed_type_cast(const std::string &w) noexcept
: bad_boxed_cast(w)
{
}
bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
~bad_boxed_type_cast() noexcept override = default;
};
}
namespace detail
{
class Type_Conversion_Base
{
public:
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
const Type_Info &to() const
{
return m_to;
}
const Type_Info &from() const
{
return m_from;
}
virtual bool bidir() const
{
return true;
}
virtual ~Type_Conversion_Base() = default;
protected:
Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
: m_to(std::move(t_to)), m_from(std::move(t_from))
{
}
private:
const Type_Info m_to;
const Type_Info m_from;
};
template<typename From, typename To>
class Static_Caster
{
public:
static Boxed_Value cast(const Boxed_Value &t_from)
{
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
return Boxed_Value(
[&](){
if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
{
return data;
} else {
throw std::bad_cast();
}
}()
);
} else {
return Boxed_Value(
[&](){
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
{
return data;
} else {
throw std::bad_cast();
}
}()
);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = static_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = static_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename From, typename To>
class Dynamic_Caster
{
public:
static Boxed_Value cast(const Boxed_Value &t_from)
{
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
return Boxed_Value(
[&](){
if (auto data = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
{
return data;
} else {
throw std::bad_cast();
}
}()
);
} else {
return Boxed_Value(
[&](){
if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
{
return data;
} else {
#ifdef CHAISCRIPT_LIBCPP
/// \todo fix this someday after libc++ is fixed.
if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) {
auto from = detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr);
if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) {
return std::static_pointer_cast<To>(from);
}
}
#endif
throw std::bad_cast();
}
}()
);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Type_Conversion_Base
{
public:
Dynamic_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
{
}
Boxed_Value convert_down(const Boxed_Value &t_base) const override
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
Boxed_Value convert(const Boxed_Value &t_derived) const override
{
return Static_Caster<Derived, Base>::cast(t_derived);
}
};
template<typename Base, typename Derived>
class Static_Conversion_Impl : public Type_Conversion_Base
{
public:
Static_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
{
}
Boxed_Value convert_down(const Boxed_Value &t_base) const override
{
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived),
"Unable to cast down inheritance hierarchy with non-polymorphic types");
}
bool bidir() const override
{
return false;
}
Boxed_Value convert(const Boxed_Value &t_derived) const override
{
return Static_Caster<Derived, Base>::cast(t_derived);
}
};
template<typename Callable>
class Type_Conversion_Impl : public Type_Conversion_Base
{
public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(t_to, t_from),
m_func(std::move(t_func))
{
}
Boxed_Value convert_down(const Boxed_Value &) const override
{
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
}
Boxed_Value convert(const Boxed_Value &t_from) const override
{
/// \todo better handling of errors from the conversion function
return m_func(t_from);
}
bool bidir() const override
{
return false;
}
private:
Callable m_func;
};
}
class Type_Conversions
{
public:
struct Conversion_Saves
{
bool enabled = false;
std::vector<Boxed_Value> saves;
};
struct Less_Than
{
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
{
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
}
};
Type_Conversions()
: m_mutex(),
m_conversions(),
m_convertableTypes(),
m_num_types(0)
{
}
Type_Conversions(const Type_Conversions &t_other) = delete;
Type_Conversions(Type_Conversions &&) = default;
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
{
auto &cache = *m_thread_cache;
if (cache.size() != m_num_types)
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
cache = m_convertableTypes;
}
return cache;
}
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
/// \todo error if a conversion already exists
m_conversions.insert(conversion);
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
m_num_types = m_convertableTypes.size();
}
template<typename T>
bool convertable_type() const
{
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
}
template<typename To, typename From>
bool converts() const
{
return converts(user_type<To>(), user_type<From>());
}
bool converts(const Type_Info &to, const Type_Info &from) const
{
const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
{
return has_conversion(to, from);
} else {
return false;
}
}
template<typename To>
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
{
return boxed_type_conversion(user_type<To>(), t_saves, from);
}
template<typename From>
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, 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 {
Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
} 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");
}
}
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const
{
try {
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)
{
t_saves.enabled = t_val;
}
std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves)
{
std::vector<Boxed_Value> ret;
std::swap(ret, t_saves.saves);
return ret;
}
bool has_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find_bidir(to, from) != m_conversions.end();
}
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto itr = find(to, from);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
}
}
Conversion_Saves &conversion_saves() const {
return *m_conversion_saves;
}
private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir(
const Type_Info &to, const Type_Info &from) const
{
return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool
{
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
}
);
}
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
const Type_Info &to, const Type_Info &from) const
{
return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
}
);
}
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
std::set<const std::type_info *, Less_Than> m_convertableTypes;
std::atomic_size_t m_num_types;
mutable chaiscript::detail::threading::Thread_Storage<std::set<const std::type_info *, Less_Than>> m_thread_cache;
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;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new to class registration for applying to a module or to the ChaiScript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::to_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
Type_Conversion base_class(typename std::enable_if<std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value>::type* = nullptr)
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
}
template<typename Base, typename Derived>
Type_Conversion base_class(typename std::enable_if<!std::is_polymorphic<Base>::value || !std::is_polymorphic<Derived>::value>::type* = nullptr)
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
}
template<typename Callable>
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to,
const Callable &t_func)
{
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
}
template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function)
{
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
template<typename From, typename To>
Type_Conversion type_conversion()
{
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr)));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
template<typename To>
Type_Conversion vector_conversion()
{
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
To vec;
vec.reserve(from_vec.size());
for (const Boxed_Value &bv : from_vec) {
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
}
return Boxed_Value(std::move(vec));
};
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);
}
}
#endif

View File

@ -1,20 +1,25 @@
// 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-2014, 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_
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <string> #include <string>
#include <typeinfo>
#include <boost/shared_ptr.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/is_void.hpp>
#include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/ref.hpp>
namespace chaiscript namespace chaiscript
{ {
@ -24,75 +29,92 @@ namespace chaiscript
template<typename T> template<typename T>
struct Bare_Type struct Bare_Type
{ {
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type; typedef typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type type;
}; };
} }
/// \brief Compile time deduced information about a type /// \brief Compile time deduced information about a type
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, 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_bareti)
: m_type_info(t_ti), m_bare_type_info(t_bare_ti), : m_type_info(t_ti), m_bare_type_info(t_bareti),
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag) m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag) m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag) m_is_undef(false)
+ (static_cast<unsigned int>(t_is_void) << is_void_flag)
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag))
{ {
} }
constexpr Type_Info() = default; Type_Info()
: m_type_info(0), m_bare_type_info(0),
m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_is_arithmetic(false),
m_is_undef(true)
{
}
constexpr bool operator<(const Type_Info &ti) const noexcept Type_Info(const Type_Info &ti)
: m_type_info(ti.m_type_info),
m_bare_type_info(ti.m_bare_type_info),
m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
m_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_is_arithmetic(ti.m_is_arithmetic),
m_is_undef(ti.m_is_undef)
{
}
Type_Info &operator=(const Type_Info &ti)
{
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_const = ti.m_is_const;
m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_is_arithmetic = ti.m_is_arithmetic;
m_is_undef = ti.m_is_undef;
return *this;
}
bool operator<(const Type_Info &ti) const
{ {
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 bool operator==(const Type_Info &ti) const
{
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 bool operator==(const std::type_info &ti) const
{ {
return !is_undef() && (*m_type_info) == ti; return m_type_info != 0 && (*m_type_info) == ti;
} }
constexpr bool bare_equal(const Type_Info &ti) const noexcept bool bare_equal(const Type_Info &ti) const
{ {
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 bool bare_equal_type_info(const std::type_info &ti) const
{ {
return !is_undef() && (*m_bare_type_info) == ti; return m_bare_type_info != 0
&& (*m_bare_type_info) == ti;
} }
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; } bool is_const() const { return m_is_const; }
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; } bool is_reference() const { return m_is_reference; }
constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; } bool is_void() const { return m_is_void; }
constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_flag)) != 0; } bool is_arithmetic() const { return m_is_arithmetic; }
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; } bool is_undef() const { return m_is_undef || m_bare_type_info == 0; }
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; } bool is_pointer() const { return m_is_pointer; }
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 +124,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,102 +132,102 @@ namespace chaiscript
} }
} }
constexpr const std::type_info *bare_type_info() const
{
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); bool m_is_const;
const std::type_info *m_bare_type_info = &typeid(Unknown_Type); bool m_is_reference;
static const int is_const_flag = 0; bool m_is_pointer;
static const int is_reference_flag = 1; bool m_is_void;
static const int is_pointer_flag = 2; bool m_is_arithmetic;
static const int is_void_flag = 3; bool m_is_undef;
static const int is_arithmetic_flag = 4;
static const int is_undef_flag = 5;
unsigned int m_flags = (1 << is_undef_flag);
}; };
namespace detail namespace detail
{ {
/// Helper used to create a Type_Info object /**
* Helper used to create a Type_Info object
*/
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(boost::is_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
std::is_reference<T>::value, std::is_pointer<T>::value, boost::is_void<T>::value,
std::is_void<T>::value, boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(T), &typeid(T),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<std::shared_ptr<T> > struct Get_Type_Info<boost::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(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
std::is_void<T>::value, boost::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(std::shared_ptr<T> ), &typeid(boost::shared_ptr<T> ),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>> struct Get_Type_Info<const boost::shared_ptr<T> &>
{ {
}; typedef T type;
template<typename T> static Type_Info get()
struct Get_Type_Info<const std::shared_ptr<T> &>
{
static constexpr Type_Info get()
{ {
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
std::is_void<T>::value, boost::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(const std::shared_ptr<T> &), &typeid(const boost::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> > struct Get_Type_Info<boost::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(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
std::is_void<T>::value, boost::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(std::reference_wrapper<T> ), &typeid(boost::reference_wrapper<T> ),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &> struct Get_Type_Info<const boost::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(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
std::is_void<T>::value, boost::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &), &typeid(const boost::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T>
struct Stripped_Type
{
typedef typename Bare_Type<typename detail::Get_Type_Info<T>::type>::type type;
};
} }
/// \brief Creates a Type_Info object representing the type passed in /// \brief Creates a Type_Info object representing the type passed in
@ -218,7 +240,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 +255,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,20 @@
// 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-2014, 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 <chaiscript/dispatchkit/dispatchkit.hpp>
#include <boost/enable_shared_from_this.hpp>
#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 +32,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,57 +47,85 @@ 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
} }
}; };
} }
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */ #endif /* _CHAISCRIPT_ALGEBRAIC_HPP */

View File

@ -1,89 +1,44 @@
// 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-2014, 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_
#include <algorithm> #include <chaiscript/dispatchkit/dispatchkit.hpp>
#include <memory> #include <boost/enable_shared_from_this.hpp>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "../chaiscript_defines.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp"
namespace chaiscript {
struct AST_Node;
} // namespace chaiscript
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, Inplace_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, Switch, Case, Default, Ternary_Cond, Noop
};
}; };
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", "Inplace_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", "Switch", "Case", "Default", "Ternary Condition", "Noop"};
return ast_node_types[ast_node_type];
} }
} }
@ -98,135 +53,78 @@ namespace chaiscript
File_Position() : line(0), column(0) { } File_Position() : line(0), column(0) { }
}; };
struct Parse_Location {
Parse_Location(std::string t_fname="", const int t_start_line=0, const int t_start_col=0,
const int t_end_line=0, const int t_end_col=0)
: start(t_start_line, t_start_col),
end(t_end_line, t_end_col),
filename(std::make_shared<std::string>(std::move(t_fname)))
{
}
Parse_Location(std::shared_ptr<std::string> t_fname, const int t_start_line=0, const int t_start_col=0,
const int t_end_line=0, const int t_end_col=0)
: start(t_start_line, t_start_col),
end(t_end_line, t_end_col),
filename(std::move(t_fname))
{
}
File_Position start;
File_Position end;
std::shared_ptr<std::string> filename;
};
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
typedef std::shared_ptr<AST_Node> AST_NodePtr; typedef boost::shared_ptr<AST_Node> AST_NodePtr;
typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const;
/// \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 : public std::runtime_error {
std::string reason; std::string reason;
File_Position start_position; File_Position start_position;
File_Position end_position;
std::string filename; std::string filename;
std::string detail; std::string detail;
std::vector<AST_NodePtr_Const> call_stack; std::vector<AST_NodePtr> call_stack;
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) :
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), end_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
{} {}
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) :
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) :
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), end_position(t_where), filename(t_fname)
{} {}
explicit eval_error(const std::string &t_why) noexcept eval_error(const std::string &t_why) throw()
: std::runtime_error("Error: \"" + t_why + "\" "), : std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why) reason(t_why)
{} {}
eval_error(const eval_error &) = default;
std::string pretty_print() const std::string pretty_print() const
{ {
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]) << ")" << std::endl;
ss << '\n' << detail << '\n'; ss << std::endl << detail << std::endl;
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]) << "'";
for (size_t j = 1; j < call_stack.size(); ++j) { for (size_t j = 1; j < call_stack.size(); ++j) {
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File) && id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{ {
ss << '\n'; ss << std::endl;
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'"; ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
} }
} }
} }
ss << '\n'; ss << std::endl;
return ss.str(); return ss.str();
} }
~eval_error() noexcept override = default; virtual ~eval_error() throw() {}
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;
} }
@ -238,16 +136,16 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static const std::string &fname(const T& t) static std::string fname(const T& t)
{ {
return t->filename(); return *t->filename;
} }
template<typename T> template<typename T>
static std::string startpos(const T& t) static std::string startpos(const T& t)
{ {
std::ostringstream oss; std::ostringstream oss;
oss << t->start().line << ", " << t->start().column; oss << t->start.line << ", " << t->start.column;
return oss.str(); return oss.str();
} }
@ -305,8 +203,8 @@ namespace chaiscript
} }
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func); = boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
if (dynfun) if (dynfun)
{ {
@ -314,7 +212,8 @@ namespace chaiscript
if (f) if (f)
{ {
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f); boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfunguard
= boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
if (dynfunguard) if (dynfunguard)
{ {
retval += " : " + format_guard(dynfunguard->get_parse_tree()); retval += " : " + format_guard(dynfunguard->get_parse_tree());
@ -336,13 +235,10 @@ namespace chaiscript
template<typename T> template<typename T>
static std::string format_location(const T &t) static std::string format_location(const T &t)
{ {
if (t) { std::ostringstream oss;
std::ostringstream oss; oss << "(" << *t->filename << " " << t->start.line << ", " << t->start.column << ")";
oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")";
return oss.str(); return oss.str();
} else {
return "(internal)";
}
} }
@ -353,13 +249,15 @@ namespace chaiscript
std::stringstream ss; std::stringstream ss;
if (t_functions.size() == 1) if (t_functions.size() == 1)
{ {
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n'; ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl;
} else { } else {
ss << " " << t_functions.size() << " overloads available:\n"; ss << " " << t_functions.size() << " overloads available:" << std::endl;
for (const auto & t_function : t_functions) for (std::vector<chaiscript::Const_Proxy_Function>::const_iterator itr = t_functions.begin();
itr != t_functions.end();
++itr)
{ {
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n'; ss << " " << format_types((*itr), t_dot_notation, t_ss) << std::endl;
} }
} }
@ -379,7 +277,7 @@ namespace chaiscript
{ {
std::string paramstr; std::string paramstr;
for (auto itr = t_parameters.begin(); for (std::vector<Boxed_Value>::const_iterator itr = t_parameters.begin();
itr != t_parameters.end(); itr != t_parameters.end();
++itr) ++itr)
{ {
@ -479,228 +377,200 @@ 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 : public std::runtime_error {
explicit file_not_found_error(const std::string &t_filename) noexcept file_not_found_error(const std::string &t_filename) throw()
: 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; virtual ~file_not_found_error() throw() {}
~file_not_found_error() noexcept override = default;
}; };
} }
/// \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 : boost::enable_shared_from_this<AST_Node> {
public: public:
const AST_Node_Type identifier;
const std::string text; const std::string text;
Parse_Location location; const int identifier;
boost::shared_ptr<const std::string> filename;
File_Position start, end;
std::vector<AST_NodePtr> children;
AST_NodePtr annotation;
const std::string &filename() const { virtual std::string pretty_print() const
return *location.filename;
}
const File_Position &start() const {
return location.start;
}
const File_Position &end() const {
return location.end;
}
std::string pretty_print() const
{ {
std::ostringstream oss; std::ostringstream oss;
oss << text; oss << text;
for (auto & elem : this->get_children()) { for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << elem->pretty_print() << ' '; oss << this->children[j]->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(std::string t_prepend = "") {
std::ostringstream oss; std::ostringstream oss;
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->start.line << ", " << this->start.column << std::endl;
for (auto & elem : this->get_children()) { for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << elem->to_string(t_prepend + " "); oss << this->children[j]->to_string(t_prepend + " ");
} }
return oss.str(); return oss.str();
} }
std::string internal_to_string() {
return to_string();
}
static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) { Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e)
{
try { try {
return t_ss->boxed_cast<bool>(t_bv); return eval_internal(t_e);
} } catch (exception::eval_error &ee) {
catch (const exception::bad_boxed_cast &) { ee.call_stack.push_back(shared_from_this());
throw exception::eval_error("Condition not boolean"); throw;
} }
} }
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);
AST_Node(const AST_Node &) = delete; }
AST_Node& operator=(const AST_Node &) = delete;
protected: protected:
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc) AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname,
: identifier(t_id), text(std::move(t_ast_node_text)), int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
location(std::move(t_loc)) text(t_ast_node_text), identifier(t_id), filename(t_fname),
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
{ {
} }
AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname) :
text(t_ast_node_text), identifier(t_id), filename(t_fname) {}
virtual ~AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &)
{
throw std::runtime_error("Undispatched ast_node (internal error)");
}
private:
// Copy and assignment explicitly unimplemented
AST_Node(const AST_Node &);
AST_Node& operator=(const AST_Node &);
}; };
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
{ {
namespace detail namespace detail
{ {
/// Special type for returned values /// Special type for returned values
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(const Boxed_Value &t_return_value) : retval(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(chaiscript::detail::Dispatch_Engine &t_de)
Scope_Push_Pop& operator=(Scope_Push_Pop &&) = default; : m_de(t_de)
Scope_Push_Pop(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)
: m_ds(t_ds)
{ {
m_ds->new_scope(m_ds.stack_holder()); m_de.new_scope();
} }
~Scope_Push_Pop() ~Scope_Push_Pop()
{ {
m_ds->pop_scope(m_ds.stack_holder()); m_de.pop_scope();
} }
private: private:
const chaiscript::detail::Dispatch_State &m_ds; // explicitly unimplemented copy and assignment
Scope_Push_Pop(const Scope_Push_Pop &);
Scope_Push_Pop& operator=(const Scope_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de;
}; };
/// Creates a new function call and pops it on destruction /// Creates a new functon call and pops it on destruction
struct Function_Push_Pop struct Function_Push_Pop
{ {
Function_Push_Pop(Function_Push_Pop &&) = default; Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
Function_Push_Pop& operator=(Function_Push_Pop &&) = default; : m_de(t_de)
Function_Push_Pop(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)
: m_ds(t_ds)
{ {
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); m_de.new_function_call();
} }
~Function_Push_Pop() ~Function_Push_Pop()
{ {
m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); m_de.pop_function_call();
} }
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_de.save_function_params(t_params);
}
void save_params(std::initializer_list<Boxed_Value> t_params)
{
m_ds->save_function_params(t_params);
} }
private: private:
const chaiscript::detail::Dispatch_State &m_ds; // explicitly unimplemented copy and assignment
Function_Push_Pop(const Function_Push_Pop &);
Function_Push_Pop& operator=(const Function_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de;
}; };
/// 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(chaiscript::detail::Dispatch_Engine &t_de)
Stack_Push_Pop& operator=(Stack_Push_Pop &&) = default; : m_de(t_de)
Stack_Push_Pop(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)
: m_ds(t_ds)
{ {
m_ds->new_stack(m_ds.stack_holder()); m_de.new_stack();
} }
~Stack_Push_Pop() ~Stack_Push_Pop()
{ {
m_ds->pop_stack(m_ds.stack_holder()); m_de.pop_stack();
} }
private: private:
const chaiscript::detail::Dispatch_State &m_ds; // explicitly unimplemented copy and assignment
Stack_Push_Pop(const Stack_Push_Pop &);
Stack_Push_Pop& operator=(const Stack_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de;
}; };
} }
} }
} }
#endif /* _CHAISCRIPT_COMMON_HPP */ #endif /* _CHAISCRIPT_COMMON_HPP */

View File

@ -1,69 +1,242 @@
// 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-2014, 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_
#include <cassert>
#include <exception> #include <exception>
#include <fstream> #include <fstream>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <stdexcept>
#include <vector>
#include <cstring>
#include "../chaiscript_defines.hpp"
#include "../chaiscript_threading.hpp"
#include "../dispatchkit/boxed_cast_helper.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "chaiscript_common.hpp" #include "chaiscript_common.hpp"
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) #ifdef _POSIX_VERSION
#include <unistd.h>
#endif
#if !defined(CHAISCRIPT_NO_DYNLOAD) && 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 BOOST_WINDOWS
#define VC_EXTRA_LEAN
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
#endif #endif
#include "chaiscript_prelude.hpp"
#include "chaiscript_parser.hpp"
#include "../dispatchkit/exception_specification.hpp" #include "../dispatchkit/exception_specification.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) throw()
: std::runtime_error(t_reason)
{
}
virtual ~load_module_error() throw()
{
}
};
}
namespace detail namespace detail
{ {
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr; #ifdef _POSIX_VERSION
struct Loadable_Module
{
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{
if (!m_data)
{
throw 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 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 towstring(const T &t_str)
{
return std::wstring(t_str.begin(), t_str.end());
}
template<typename T>
static std::string tostring(const T &t_str)
{
return std::string(t_str.begin(), t_str.end());
}
#ifdef _UNICODE
template<typename T>
static std::wstring toproperstring(const T &t_str)
{
return towstring(t_str);
}
#else
template<typename T>
static std::string toproperstring(const T &t_str)
{
return tostring(t_str);
}
#endif
static std::string GetErrorMessage(DWORD t_err)
{
#ifdef _UNICODE
typedef LPWSTR StringType;
std::wstring retval = L"Unknown Error";
#else
typedef LPSTR StringType;
std::string retval = "Unknown Error";
#endif
StringType lpMsgBuf = 0;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(StringType)&lpMsgBuf,
0, NULL );
if (lpMsgBuf)
{
retval = lpMsgBuf;
}
LocalFree(lpMsgBuf);
return tostring(retval);
}
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(LoadLibrary(toproperstring(t_filename).c_str()))
{
if (!m_data)
{
throw exception::load_module_error(GetErrorMessage(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 exception::load_module_error(GetErrorMessage(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 exception::load_module_error("Loadable module support not available for your platform");
}
ModulePtr m_moduleptr;
};
#endif
#endif
typedef boost::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;
@ -72,44 +245,39 @@ namespace chaiscript
std::map<std::string, detail::Loadable_Module_Ptr> m_loaded_modules; std::map<std::string, detail::Loadable_Module_Ptr> m_loaded_modules;
std::set<std::string> m_active_loaded_modules; std::set<std::string> m_active_loaded_modules;
std::vector<std::string> m_module_paths; std::vector<std::string> m_modulepaths;
std::vector<std::string> m_use_paths; std::vector<std::string> m_usepaths;
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.ast()->eval(m_engine);
} else {
return Boxed_Value();
}
} }
catch (chaiscript::eval::detail::Return_Value &rv) { catch (const chaiscript::eval::detail::Return_Value &rv) {
return rv.retval; return rv.retval;
} }
} }
/// Evaluates the given file and looks in the 'use' paths const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast)
const Boxed_Value internal_eval_file(const std::string &t_filename) { {
for (const auto &path : m_use_paths) try {
{ return t_ast->eval(m_engine);
try { } catch (const exception::eval_error &t_ee) {
const auto appendedpath = path + t_filename; throw Boxed_Value(t_ee);
return do_eval(load_file(appendedpath), appendedpath, true);
} catch (const exception::file_not_found_error &) {
// failed to load, try the next path
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
} }
// failed to load by any name
throw exception::file_not_found_error(t_filename);
} }
@ -123,90 +291,83 @@ namespace chaiscript
} }
} }
/// Returns the current evaluation m_engine /// Returns the current evaluation m_engine
chaiscript::detail::Dispatch_Engine &get_eval_engine() { chaiscript::detail::Dispatch_Engine &get_eval_engine() {
return m_engine; return m_engine;
} }
/// 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() {
if (t_lib) using namespace bootstrap;
{ m_engine.add_reserved_word("auto");
add(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(":=");
m_engine.add_reserved_word("var");
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("_");
m_engine.add(fun([this](){ m_engine.dump_system(); }), "dump_system"); add(Bootstrap::bootstrap());
m_engine.add(fun([this](const Boxed_Value &t_bv){ m_engine.dump_object(t_bv); }), "dump_object");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type){ return m_engine.is_type(t_bv, t_type); }), "is_type");
m_engine.add(fun([this](const Boxed_Value &t_bv){ return m_engine.type_name(t_bv); }), "type_name");
m_engine.add(fun([this](const std::string &t_f){ return m_engine.function_exists(t_f); }), "function_exists");
m_engine.add(fun([this](){ return m_engine.get_function_objects(); }), "get_functions");
m_engine.add(fun([this](){ return m_engine.get_scripting_objects(); }), "get_objects");
m_engine.add( m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_system, boost::ref(m_engine)), "dump_system");
dispatch::make_dynamic_proxy_function( m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_object, boost::ref(m_engine)), "dump_object");
[this](const std::vector<Boxed_Value> &t_params) { m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, boost::ref(m_engine)), "is_type");
return m_engine.call_exists(t_params); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, boost::ref(m_engine)), "type_name");
}) m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, boost::ref(m_engine)), "function_exists");
, "call_exists"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, boost::ref(m_engine)), "get_functions");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, boost::ref(m_engine)), "get_objects");
m_engine.add(fun( m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(boost::bind(&chaiscript::detail::Dispatch_Engine::call_exists, boost::ref(m_engine), _1))),
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value { "call_exists");
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves()); m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(boost::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), _1, _2, boost::ref(m_engine.conversions()))), "call");
return t_fun(t_params, s);
}), "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 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){ return m_engine.get_type(t_type_name, true); }), "type");
m_engine.add(fun(
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
}
), "add_type_conversion");
if (std::find(t_opts.begin(), t_opts.end(), Options::No_Load_Modules) == t_opts.end() m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name");
&& 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){ 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 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 AST_NodePtr &t_ast){ return eval(t_ast); }), "eval");
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([this](const std::string &t_str){ return parse(t_str); }), "parse");
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"); typedef void (ChaiScript::*load_mod_1)(const std::string&);
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
m_engine.add(fun(static_cast<load_mod_1>(&ChaiScript::load_module), this), "load_module");
m_engine.add(fun(static_cast<load_mod_2>(&ChaiScript::load_module), this), "load_module");
add(standard_library::vector_type<std::vector<Boxed_Value> >("Vector"));
add(standard_library::string_type<std::string>("string"));
add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
m_engine.add(fun(&ChaiScript::use, this), "use");
m_engine.add(fun(&ChaiScript::internal_eval, this), "eval");
m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval");
do_eval(chaiscript_prelude, "standard prelude");
} }
/// Helper function for loading a file /// Helper function for loading a file
static std::string load_file(const std::string &t_filename) { std::string load_file(const std::string &t_filename) {
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary ); std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary );
if (!infile.is_open()) { if (!infile.is_open()) {
throw chaiscript::exception::file_not_found_error(t_filename); throw exception::file_not_found_error(t_filename);
} }
const auto size = infile.tellg(); std::streampos size = infile.tellg();
infile.seekg(0, std::ios::beg); infile.seekg(0, std::ios::beg);
assert(size >= 0); assert(size >= 0);
@ -215,186 +376,75 @@ namespace chaiscript
{ {
return std::string(); return std::string();
} else { } else {
std::vector<char> v(static_cast<size_t>(size)); std::vector<char> v(static_cast<unsigned int>(size));
infile.read(&v[0], size); infile.read(&v[0], size);
return std::string(v.begin(), v.end()); return std::string(v.begin(), v.end());
} }
} }
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_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 std::vector<std::string> &t_modulepaths = std::vector<std::string>(),
std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser, const std::vector<std::string> &t_usepaths = std::vector<std::string>())
std::vector<std::string> t_module_paths = {}, : m_modulepaths(t_modulepaths), m_usepaths(t_usepaths)
std::vector<std::string> t_use_paths = {},
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_modulepaths.empty())
// If on Unix, add the path of the current executable to the module search path
// as windows would do
union cast_union
{ {
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&); m_modulepaths.push_back("");
void *out_ptr;
};
Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) );
cast_union u;
u.in_ptr = &ChaiScript_Basic::use;
if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) {
std::string dllpath(rInfo.dli_fname);
const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos)
{
dllpath.erase(lastslash);
}
// Let's see if this is a link that we should expand
std::vector<char> buf(2048);
const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size())
{
dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen));
}
m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
} }
#endif
build_eval_system(t_lib, t_opts);
}
#ifndef CHAISCRIPT_NO_DYNLOAD if (m_usepaths.empty())
/// \brief Constructor for ChaiScript. {
/// m_usepaths.push_back("");
/// 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
load_module("chaiscript_stdlib-" + Build_Info::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;
} }
build_eval_system();
} }
#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()
{
return *m_parser;
}
const Boxed_Value eval(const AST_NodePtr &t_ast)
{
try {
return t_ast->eval(chaiscript::detail::Dispatch_State(m_engine));
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
}
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false)
{
const auto ast = m_parser->parse(t_input, "PARSE");
if (t_debug_print) {
m_parser->debug_print(ast);
}
return ast;
}
std::string get_type_name(const Type_Info &ti) const
{
return m_engine.get_type_name(ti);
}
template<typename T>
std::string get_type_name() const
{
return get_type_name(user_type<T>());
}
/// \brief Loads and parses a file. If the file is already, it is not reloaded /// \brief Loads and parses a file. If the file is already, it is not reloaded
/// The use paths specified at ChaiScript construction time are searched for the /// The use paths specified at ChaiScript construction time are searched for the
/// requested file. /// requested file.
/// ///
/// \param[in] t_filename Filename to load and evaluate /// \param[in] t_filename Filename to load and evaluate
Boxed_Value use(const std::string &t_filename) void use(const std::string &t_filename)
{ {
for (const auto &path : m_use_paths) for (size_t i = 0; i < m_usepaths.size(); ++i)
{ {
try { try {
const auto appendedpath = path + t_filename; const std::string appendedpath = m_usepaths[i] + t_filename;
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
Boxed_Value retval;
if (m_used_files.count(appendedpath) == 0) if (m_used_files.count(appendedpath) == 0)
{ {
l2.unlock(); l2.unlock();
retval = eval_file(appendedpath); eval_file(appendedpath);
l2.lock(); l2.lock();
m_used_files.insert(appendedpath); m_used_files.insert(appendedpath);
}
return; // return, we loaded it, or it was already loaded
} catch (const exception::file_not_found_error &) {
if (i == m_usepaths.size() - 1)
{
throw exception::file_not_found_error(t_filename);
} }
return retval; // return, we loaded it, or it was already loaded
} catch (const exception::file_not_found_error &) {
// failed to load, try the next path // failed to load, try the next path
} }
} }
// failed to load by any name
throw exception::file_not_found_error(t_filename);
} }
/// \brief Adds a constant object that is available in all contexts and to all threads /// \brief Adds a constant object that is available in all contexts and to all threads
/// \param[in] t_bv Boxed_Value to add as a global /// \param[in] t_bv Boxed_Value to add as a global
/// \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 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,23 +454,13 @@ 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
/// are left out due to performance considerations involved in tracking the state
/// \sa ChaiScript::get_state /// \sa ChaiScript::get_state
/// \sa ChaiScript::set_state /// \sa ChaiScript::set_state
struct State struct State
@ -443,7 +483,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state /// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state
/// \endcode /// \endcode
State get_state() const State get_state()
{ {
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@ -509,11 +549,10 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// chai.add(chaiscript::var(&obj), "obj"); // Add a pointer to a locally defined object /// chai.add(chaiscript::var(&obj), "obj"); // Add a pointer to a locally defined object
/// \endcode /// \endcode
/// ///
/// \sa \ref adding_items /// \sa \ref addingitems
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 +566,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 Dynamic_Cast_Conversion &d)
{ {
m_engine.add(d); m_engine.add(d);
return *this; return *this;
@ -536,7 +575,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;
@ -547,53 +586,59 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \param[in] t_module_name Name of the module to load /// \param[in] t_module_name Name of the module to load
/// ///
/// The module is searched for in the registered module path folders (chaiscript::ChaiScript::ChaiScript) /// The module is searched for in the registered module path folders (chaiscript::ChaiScript::ChaiScript)
/// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|".bundle"|""). /// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|"").
/// ///
/// Once the file is located, the system looks for the symbol "create_chaiscript_module_\<t_module_name\>". /// Once the file is located, the system looks for the symbol "create_chaiscript_module_\<t_module_name\>".
/// If no file can be found matching the search criteria and containing the appropriate entry point /// If no file can be found matching the search criteria and containing the appropriate entry point
/// (the symbol mentioned above), an exception is thrown. /// (the symbol mentioned above), an exception is thrown.
/// ///
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found. /// \throw exception::load_module_error In the event that no matching module can be found.
std::string load_module(const std::string &t_module_name) void 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;
size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
if (version_pos != std::string::npos)
{
version_stripped_name.erase(version_pos);
}
std::vector<std::string> prefixes{"lib", "cyg", ""}; std::vector<std::string> prefixes;
prefixes.push_back("lib");
prefixes.push_back("");
std::vector<std::string> postfixes{".dll", ".so", ".bundle", ""}; std::vector<std::string> postfixes;
postfixes.push_back(".dll");
postfixes.push_back(".so");
postfixes.push_back("");
for (auto & elem : m_module_paths) for (size_t i = 0; i < m_modulepaths.size(); ++i)
{
for (auto & prefix : prefixes)
{ {
for (auto & postfix : postfixes) for (size_t j = 0; j < prefixes.size(); ++j)
{ {
try { for (size_t k = 0; k < postfixes.size(); ++k)
const auto name = elem + prefix + t_module_name + postfix; {
// std::cerr << "trying location: " << name << '\n'; try {
load_module(version_stripped_name, name); std::string name = m_modulepaths[i] + prefixes[j] + t_module_name + postfixes[k];
return name; load_module(t_module_name, name);
} catch (const chaiscript::exception::load_module_error &e) { return;
// std::cerr << "error: " << e.what() << '\n'; } catch (const exception::load_module_error &e) {
errors.push_back(e); errors.push_back(e);
// Try next set // Try next set
}
}
} }
}
} }
std::string errstring;
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(t_module_name, errors); throw exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring);
#endif
} }
/// \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
@ -627,10 +672,17 @@ 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 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.
@ -643,20 +695,27 @@ 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 exception::eval_error In the case that evaluation fails.
/// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted /// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// to the requested type. /// to the requested type.
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);
} }
@ -664,7 +723,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// ///
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_filename Optional filename to report to the user for where the error occurred. Useful /// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful
/// in special cases where you are loading a file internally instead of using eval_file /// in special cases where you are loading a file internally instead of using eval_file
/// ///
/// \return result of the script execution /// \return result of the script execution
@ -686,22 +745,36 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \param[in] t_filename File to load and parse. /// \param[in] t_filename File to load and parse.
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \return result of the script execution /// \return result of the script execution
/// \throw chaiscript::exception::eval_error In the case that evaluation fails. /// \throw 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 typesafe result.
/// \tparam T Type to extract from the result value of the script execution /// \tparam T Type to extract from the result value of the script execution
/// \param[in] t_filename File to load and parse. /// \param[in] t_filename File to load and parse.
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \return result of the script execution /// \return result of the script execution
/// \throw chaiscript::exception::eval_error In the case that evaluation fails. /// \throw exception::eval_error In the case that evaluation fails.
/// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted /// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// 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,562 +1,329 @@
// 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) // Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_ #ifndef CHAISCRIPT_PRELUDE_HPP_
#define CHAISCRIPT_PRELUDE_HPP_ #define CHAISCRIPT_PRELUDE_HPP_
namespace chaiscript { //Note, the expression "[x,y]" in "collate" is parsed as two separate expressions
struct ChaiScript_Prelude { //by C++, so CODE_STRING, takes two expressions and adds in the missing comma
static std::string chaiscript_prelude() { return R"chaiscript( #define CODE_STRING(x, y) #x ", " #y
def lt(l, r) { #define chaiscript_prelude CODE_STRING(\
if (call_exists(`<`, l, r)) { def lt(l, r) { if (call_exists(`<`, l, r)) { l < r } else { type_name(l) < type_name(r) } } \n\
l < r def gt(l, r) { if (call_exists(`>`, l, r)) { l > r } else { type_name(l) > type_name(r) } } \n\
} else { def eq(l, r) { if (call_exists(`==`, l, r)) { l == r } else { false } } \n\
type_name(l) < type_name(r) def new(x) { eval(type_name(x))(); } \n\
} def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) { eval(type_name(x))(x); } \n\
} # to_string for Pair()\n\
def to_string(x) : call_exists(first, x) && call_exists(second, x) { \n\
"<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \n\
def gt(l, r) { }\n\
if (call_exists(`>`, l, r)) { # to_string for containers\n\
l > r def to_string(x) : call_exists(range, x) && !x.is_type("string"){ \n\
} else { "[" + x.join(", ") + "]"; \n\
type_name(l) > type_name(r) }\n\
} # Basic to_string function\n\
} def to_string(x) { \n\
internal_to_string(x); \n\
def eq(l, r) { }\n\
if (call_exists(`==`, l, r)) { # Prints to console with no carriage return\n\
l == r def puts(x) { \n\
} else { print_string(x.to_string()); \n\
false } \n\
} # Prints to console with carriage return\n\
} def print(x) { \n\
println_string(x.to_string()); \n\
def new(x) { } \n\
eval(type_name(x))(); # Returns the maximum value of two numbers\n\
} def max(a, b) { if (a>b) { a } else { b } } \n\
# Returns the minimum value of two numbers\n\
def clone(double x) { def min(a, b) { if (a<b) { a } else { b } } \n\
double(x).clone_var_attrs(x) # Returns true if the value is odd\n\
} def odd(x) { if (x % 2 == 1) { true } else { false } } \n\
# Returns true if the value is even\n\
def clone(string x) { def even(x) { if (x % 2 == 0) { true } else { false } } \n\
string(x).clone_var_attrs(x) # Pushes the second value onto the container first value while making a clone of the value\n\
} def push_back(container, x) : call_exists(push_back_ref, container, x) { container.push_back_ref(clone(x)) } \n\
# Pushes the second value onto the front of the container first value while making a clone of the value\n\
def clone(vector x) { def push_front(container, x) : call_exists(push_front_ref, container, x) { container.push_front_ref(clone(x)) } \n\
vector(x).clone_var_attrs(x) # Inserts the third value at the position of the second value into the container of the first\n\
} # while making a clone. \n\
def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\
# Returns the reverse of the given container\n\
def clone(int x) { def reverse(container) {\n\
int(x).clone_var_attrs(x) var retval = new(container); \n\
} var r = range(container); \n\
while (!r.empty()) { \n\
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) retval.push_back(r.back()); \n\
{ r.pop_back(); \n\
eval(type_name(x))(x).clone_var_attrs(x); } \n\
} retval; \n\
} \n\
# Return a range from a range \n\
# to_string for Pair() def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) { return clone(r); }\n\
def to_string(x) : call_exists(first, x) && call_exists(second, x) { # The retro attribute that contains the underlying range \n\
"<" + x.first.to_string() + ", " + x.second.to_string() + ">"; attr retro::m_range; \n\
} # Creates a retro from a retro by returning the original range\n\
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro" { clone(r.m_range) }\n\
# to_string for containers # Creates a retro range from a range\n\
def to_string(x) : call_exists(range, x) && !x.is_type("string"){ def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) { this.m_range = r; }\n\
"[" + x.join(", ") + "]"; # Returns the first value of a retro\n\
} def retro::front() { back(this.m_range) }\n\
# Returns the last value of a retro\n\
# Prints to console with no carriage return def retro::back() { front(this.m_range) }\n\
def puts(x) { # Moves the back iterator of a retro towards the front by one \n\
print_string(x.to_string()); def retro::pop_back() { pop_front(this.m_range) }\n\
} # Moves the front iterator of a retro towards the back by one \n\
def retro::pop_front() { pop_back(this.m_range) } \n\
# Prints to console with carriage return # returns true if the retro is out of elements \n\
def print(x) { def retro::empty() { empty(this.m_range); } \n\
println_string(x.to_string()); # Performs the second value function over the container first value\n\
} def for_each(container, func) : call_exists(range, container) { \n\
var t_range = range(container); \n\
# Returns the maximum value of two numbers while (!t_range.empty()) { \n\
def max(a, b) { func(t_range.front()); \n\
if (a>b) { t_range.pop_front(); \n\
a } \n\
} else { } \n\
b def back_inserter(container) { \n\
} bind(push_back, container, _); \n\
} }\n\
\n\
# Returns the minimum value of two numbers def contains(container, item, compare_func) : call_exists(range, container) { \n\
def min(a, b) var t_range = range(container); \n\
{ while (!t_range.empty()) { \n\
if (a<b) if ( compare_func(t_range.front(), item) ) { return true; } \n\
{ t_range.pop_front(); \n\
a } \n\
} else { return false; \n\
b } \n\
} def contains(container, item) { return contains(container, item, eq) } \n\
} def map(container, func, inserter) : call_exists(range, container) { \n\
var range = range(container); \n\
while (!range.empty()) { \n\
# Returns true if the value is odd inserter(func(range.front())); \n\
def odd(x) { range.pop_front(); \n\
if (x % 2 == 1) } \n\
{ } \n\
true # Performs the second value function over the container first value. Creates a new container with the results\n\
} else { def map(container, func) { \n\
false var retval = new(container); \n\
} map(container, func, back_inserter(retval));\n\
} retval;\n\
}\n\
# Performs the second value function over the container first value. Starts with initial and continues with each element.\n\
# Returns true if the value is even def foldl(container, func, initial) : call_exists(range, container){ \n\
def even(x) var retval = initial; \n\
{ var range = range(container); \n\
if (x % 2 == 0) while (!range.empty()) { \n\
{ retval = (func(range.front(), retval)); \n\
true range.pop_front(); \n\
} else { } \n\
false retval; \n\
} } \n\
} # Returns the sum of the elements of the given value\n\
def sum(container) { foldl(container, `+`, 0.0) } \n\
# Returns the product of the elements of the given value\n\
# Inserts the third value at the position of the second value into the container of the first def product(container) { foldl(container, `*`, 1.0) } \n\
# while making a clone. # Returns a new container with the elements of the first value concatenated with the elements of the second value\n\
def insert_at(container, pos, x) def concat(x, y) : call_exists(clone, x) { \n\
{ var retval = x; \n\
container.insert_ref_at(pos, clone(x)); var inserter = back_inserter(retval); \n\
} var range = range(y); \n\
while (!range.empty()) { \n\
# Returns the reverse of the given container inserter(range.front()); \n\
def reverse(container) { range.pop_front(); \n\
auto retval := new(container); } \n\
auto r := range(container); retval; \n\
while (!r.empty()) { } \n\
retval.push_back(r.back()); def take(container, num, inserter) : call_exists(range, container) { \n\
r.pop_back(); var r = range(container); \n\
} var i = num; \n\
retval; while ((i > 0) && (!r.empty())) { \n\
} inserter(r.front()); \n\
r.pop_front(); \n\
--i; \n\
def range(r) : call_exists(range_internal, r) } \n\
{ } \n\
var ri := range_internal(r); # Returns a new container with the given number of elements taken from the container\n\
ri.get_var_attr("internal_obj") := r; def take(container, num) {\n\
ri; var retval = new(container); \n\
} take(container, num, back_inserter(retval)); \n\
retval; \n\
# Return a range from a range }\n\
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) def take_while(container, f, inserter) : call_exists(range, container) { \n\
{ var r = range(container); \n\
clone(r); while ((!r.empty()) && f(r.front())) { \n\
} inserter(r.front()); \n\
r.pop_front(); \n\
} \n\
# The retro attribute that contains the underlying range } \n\
attr retro::m_range; # Returns a new container with the given elements match the second value function\n\
def take_while(container, f) {\n\
# Creates a retro from a retro by returning the original range var retval = new(container); \n\
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro" take_while(container, f, back_inserter(retval)); \n\
{ retval;\n\
clone(r.m_range) }\n\
} def drop(container, num, inserter) : call_exists(range, container) { \n\
var r = range(container); \n\
var i = num; \n\
# Creates a retro range from a range while ((i > 0) && (!r.empty())) { \n\
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) r.pop_front(); \n\
{ --i; \n\
this.m_range = r; } \n\
} while (!r.empty()) { \n\
inserter(r.front()); \n\
# Returns the first value of a retro r.pop_front(); \n\
def retro::front() } \n\
{ } \n\
back(this.m_range) # Returns a new container with the given number of elements dropped from the given container \n\
} def drop(container, num) {\n\
var retval = new(container); \n\
# Returns the last value of a retro drop(container, num, back_inserter(retval)); \n\
def retro::back() retval; \n\
{ }\n\
front(this.m_range) def drop_while(container, f, inserter) : call_exists(range, container) { \n\
} var r = range(container); \n\
while ((!r.empty())&& f(r.front())) { \n\
# Moves the back iterator of a retro towards the front by one r.pop_front(); \n\
def retro::pop_back() } \n\
{ while (!r.empty()) { \n\
pop_front(this.m_range) inserter(r.front()); \n\
} r.pop_front(); \n\
} \n\
# Moves the front iterator of a retro towards the back by one } \n\
def retro::pop_front() # Returns a new container with the given elements dropped that match the second value function\n\
{ def drop_while(container, f) {\n\
pop_back(this.m_range) var retval = new(container); \n\
} drop_while(container, f, back_inserter(retval)); \n\
retval; \n\
# returns true if the retro is out of elements }\n\
def retro::empty() # Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.\n\
{ def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \n\
empty(this.m_range); var r = range(container); \n\
} var retval = r.front(); \n\
r.pop_front(); \n\
# Performs the second value function over the container first value retval = func(retval, r.front()); \n\
def for_each(container, func) : call_exists(range, container) { r.pop_front(); \n\
var t_range := range(container); while (!r.empty()) { \n\
while (!t_range.empty()) { retval = func(retval, r.front()); \n\
func(t_range.front()); r.pop_front(); \n\
t_range.pop_front(); } \n\
} retval; \n\
} } \n\
# Returns a string of the elements in container delimited by the second value string\n\
def any_of(container, func) : call_exists(range, container) { def join(container, delim) { \n\
var t_range := range(container); var retval = ""; \n\
while (!t_range.empty()) { var range = range(container); \n\
if (func(t_range.front())) { if (!range.empty()) { \n\
return true; retval += to_string(range.front()); \n\
} range.pop_front(); \n\
t_range.pop_front(); while (!range.empty()) { \n\
} retval += delim; \n\
false; retval += to_string(range.front()); \n\
} range.pop_front(); \n\
} \n\
def all_of(container, func) : call_exists(range, container) { } \n\
var t_range := range(container); retval; \n\
while (!t_range.empty()) { } \n\
if (!func(t_range.front())) { def filter(container, f, inserter) : call_exists(range, container) { \n\
return false; var r = range(container); \n\
} while (!r.empty()) { \n\
t_range.pop_front(); if (f(r.front())) { \n\
} inserter(r.front()); \n\
} \n\
true; r.pop_front(); \n\
} } \n\
} \n\
def back_inserter(container) { # Returns a new Vector which match the second value function\n\
bind(push_back, container, _); def filter(container, f) { \n\
} var retval = new(container); \n\
filter(container, f, back_inserter(retval));\n\
def contains(container, item, compare_func) : call_exists(range, container) { retval;\n\
auto t_range := range(container); }\n\
while (!t_range.empty()) { def generate_range(x, y, inserter) { \n\
if ( compare_func(t_range.front(), item) ) { var i = x; \n\
return true; while (i <= y) { \n\
} inserter(i); \n\
++i; \n\
t_range.pop_front(); } \n\
} } \n\
false; # Returns a new Vector which represents the range from the first value to the second value\n\
} def generate_range(x, y) { \n\
var retval = Vector(); \n\
def contains(container, item) { generate_range(x,y,back_inserter(retval)); \n\
contains(container, item, eq) retval; \n\
} }\n\
# Returns a new Vector with the first value to the second value as its elements\n\
def map(container, func, inserter) : call_exists(range, container) { def collate(x, y) { \n\
auto range := range(container); [x, y]; \n\
while (!range.empty()) { } \n\
inserter(func(range.front())); def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { \n\
range.pop_front(); var r_x = range(x); \n\
} var r_y = range(y); \n\
} while (!r_x.empty() && !r_y.empty()) { \n\
inserter(f(r_x.front(), r_y.front())); \n\
# Performs the second value function over the container first value. Creates a new container with the results r_x.pop_front(); \n\
def map(container, func) { r_y.pop_front(); \n\
auto retval := new(container); } \n\
map(container, func, back_inserter(retval)); } \n\
retval; # Returns a new Vector which joins matching elements of the second and third value with the first value function\n\
} def zip_with(f, x, y) { \n\
var retval = Vector(); \n\
# Performs the second value function over the container first value. Starts with initial and continues with each element. zip_with(f,x,y,back_inserter(retval)); \n\
def foldl(container, func, initial) : call_exists(range, container){ retval;\n\
auto retval = initial; }\n\
auto range := range(container); # Returns a new Vector which joins matching elements of the first and second\n\
while (!range.empty()) { def zip(x, y) { \n\
retval = (func(range.front(), retval)); zip_with(collate, x, y); \n\
range.pop_front(); }\n\
} # Returns the position of the second value string in the first value string\n\
retval; def string::find(substr) : is_type(substr, "string") { \n\
} int(find(this, substr, 0)); \n\
} \n\
# Returns the sum of the elements of the given value # Returns the position of last match of the second value string in the first value string\n\
def sum(container) { def string::rfind(substr) : is_type(substr, "string") { \n\
foldl(container, `+`, 0.0) int(rfind(this, substr, -1)); \n\
} } \n\
# Returns the position of the first match of elements in the second value string in the first value string\n\
# Returns the product of the elements of the given value def string::find_first_of(list) : is_type(list, "string") { \n\
def product(container) { int(find_first_of(this, list, 0)); \n\
foldl(container, `*`, 1.0) } \n\
} # Returns the position of the last match of elements in the second value string in the first value string\n\
def string::find_last_of(list) : is_type(list, "string") { \n\
# Returns a new container with the elements of the first value concatenated with the elements of the second value int(find_last_of(this, list, -1)); \n\
def concat(x, y) : call_exists(clone, x) { } \n\
auto retval = x; # Returns the position of the first non-matching element in the second value string in the first value string\n\
auto inserter := back_inserter(retval); def string::find_first_not_of(list) : is_type(list, "string") { \n\
auto range := range(y); int(find_first_not_of(this, list, 0)); \n\
while (!range.empty()) { } \n\
inserter(range.front()); # Returns the position of the last non-matching element in the second value string in the first value string\n\
range.pop_front(); def string::find_last_not_of(list) : is_type(list, "string") { \n\
} int(find_last_not_of(this, list, -1)); \n\
retval; } \n\
} def string::ltrim() { \n\
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}); \n\
} \n\
def take(container, num, inserter) : call_exists(range, container) { def string::rtrim() { \n\
auto r := range(container); reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'})); \n\
auto i = num; } \n\
while ((i > 0) && (!r.empty())) { def string::trim() { \n\
inserter(r.front()); ltrim(rtrim(this)); \n\
r.pop_front(); } \n\
--i; def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") { \n\
} var range = range(container); \n\
} while (!range.empty()) { \n\
if (compare_func(range.front(), value)) { \n\
return range; \n\
# Returns a new container with the given number of elements taken from the container } else { \n\
def take(container, num) { range.pop_front(); \n\
auto retval := new(container); } \n\
take(container, num, back_inserter(retval)); } \n\
retval; return range; \n\
} } \n\
def find(container, value) { return find(container, value, eq) } \
)
def take_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty()) && f(r.front())) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given elements match the second value function
def take_while(container, f) {
auto retval := new(container);
take_while(container, f, back_inserter(retval));
retval;
}
def drop(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
r.pop_front();
--i;
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given number of elements dropped from the given container
def drop(container, num) {
auto retval := new(container);
drop(container, num, back_inserter(retval));
retval;
}
def drop_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty())&& f(r.front())) {
r.pop_front();
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given elements dropped that match the second value function
def drop_while(container, f) {
auto retval := new(container);
drop_while(container, f, back_inserter(retval));
retval;
}
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
auto r := range(container);
auto retval = r.front();
r.pop_front();
retval = func(retval, r.front());
r.pop_front();
while (!r.empty()) {
retval = func(retval, r.front());
r.pop_front();
}
retval;
}
# Returns a string of the elements in container delimited by the second value string
def join(container, delim) {
auto retval = "";
auto range := range(container);
if (!range.empty()) {
retval += to_string(range.front());
range.pop_front();
while (!range.empty()) {
retval += delim;
retval += to_string(range.front());
range.pop_front();
}
}
retval;
}
def filter(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while (!r.empty()) {
if (f(r.front())) {
inserter(r.front());
}
r.pop_front();
}
}
# Returns a new Vector which match the second value function
def filter(container, f) {
auto retval := new(container);
filter(container, f, back_inserter(retval));
retval;
}
def generate_range(x, y, inserter) {
auto i = x;
while (i <= y) {
inserter(i);
++i;
}
}
# Returns a new Vector which represents the range from the first value to the second value
def generate_range(x, y) {
auto retval := Vector();
generate_range(x,y,back_inserter(retval));
retval;
}
# Returns a new Vector with the first value to the second value as its elements
def collate(x, y) {
return [x, y];
}
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
auto r_x := range(x);
auto r_y := range(y);
while (!r_x.empty() && !r_y.empty()) {
inserter(f(r_x.front(), r_y.front()));
r_x.pop_front();
r_y.pop_front();
}
}
# Returns a new Vector which joins matching elements of the second and third value with the first value function
def zip_with(f, x, y) {
auto retval := Vector();
zip_with(f,x,y,back_inserter(retval));
retval;
}
# Returns a new Vector which joins matching elements of the first and second
def zip(x, y) {
zip_with(collate, x, y);
}
# Returns the position of the second value string in the first value string
def string::find(string substr) {
find(this, substr, size_t(0));
}
# Returns the position of last match of the second value string in the first value string
def string::rfind(string substr) {
rfind(this, substr, size_t(-1));
}
# Returns the position of the first match of elements in the second value string in the first value string
def string::find_first_of(string list) {
find_first_of(this, list, size_t(0));
}
# Returns the position of the last match of elements in the second value string in the first value string
def string::find_last_of(string list) {
find_last_of(this, list, size_t(-1));
}
# Returns the position of the first non-matching element in the second value string in the first value string
def string::find_first_not_of(string list) {
find_first_not_of(this, list, size_t(0));
}
# Returns the position of the last non-matching element in the second value string in the first value string
def string::find_last_not_of(string list) {
find_last_not_of(this, list, size_t(-1));
}
def string::ltrim() {
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
}
def string::rtrim() {
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
}
def string::trim() {
ltrim(rtrim(this));
}
def find(container, value, Function compare_func) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
if (compare_func(range.front(), value)) {
return range;
} else {
range.pop_front();
}
}
range;
}
def find(container, value) {
find(container, value, eq)
}
)chaiscript";
}
};
}
#endif /* CHAISCRIPT_PRELUDE_HPP_ */ #endif /* CHAISCRIPT_PRELUDE_HPP_ */

View File

@ -5,7 +5,7 @@
namespace ChaiScript_Language namespace ChaiScript_Language
{ {
/// \page LangStandardLibraryRef ChaiScript Language Standard Library Reference /// \page LangStandardLibraryRef ChaiScript Language Standard Libary Reference
/// ///
/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly /// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly
/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available /// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available
@ -112,7 +112,7 @@ class Map
}; };
/// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable /// \brief A concept implemented by string, Vector and Map. It is convertable to Range, default constructable and back_insertable
class Container class Container
{ {
public: public:
@ -153,10 +153,10 @@ void print(Object o);
/// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript. /// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript.
/// ///
/// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string /// Because the ChaiScript string object is an std::string, it is directly convertable to and from std::string
/// using the chaiscript::boxed_cast and chaiscript::var functions. /// using the chaiscript::boxed_cast and chaiscript::var functions.
/// ///
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the /// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct passthroughs to the
/// std::string of the same name. /// std::string of the same name.
/// ///
/// \note Object and function notations are equivalent in ChaiScript. This means that /// \note Object and function notations are equivalent in ChaiScript. This means that
@ -309,7 +309,7 @@ class Range
/// \brief Moves the front pointer forward one /// \brief Moves the front pointer forward one
/// ///
/// \post front() returns the element at front() + 1; /// \post front() returne the element at front() + 1;
void pop_front(); void pop_front();
}; };
@ -340,7 +340,7 @@ class Const_Range
/// \brief Moves the front pointer forward one /// \brief Moves the front pointer forward one
/// ///
/// \post front() returns the element at front() + 1; /// \post front() returne the element at front() + 1;
void pop_front(); void pop_front();
}; };
@ -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
@ -519,7 +519,7 @@ class Function
/// \brief Returns a vector of Type_Info objects that represent the param types for this function. /// \brief Returns a vector of Type_Info objects that represent the param types for this function.
/// The first value in the list is the return type. /// The first value in the list is the return type.
/// ///
/// If this function is a conglomerate of several functions (get_contained_values().size() > 0) /// If this function is a conglomeration of several functions (get_contained_values().size() > 0)
/// then the function returns as many Type_Info objects as it can. If the functions contained all have /// then the function returns as many Type_Info objects as it can. If the functions contained all have
/// the same arity, then it represents the arity. If they have different arities, it returns only /// the same arity, then it represents the arity. If they have different arities, it returns only
/// one value - the return type. /// one value - the return type.
@ -534,7 +534,7 @@ class Function
/// \endcode /// \endcode
Vector get_param_types() const; Vector get_param_types() const;
/// \brief Returns true if the function has a guard to it. Always returns false for a conglomerate function /// \brief Returns true if the function has a guard to it. Always returns falls for a conglomerate function
bool has_guard() const; bool has_guard() const;
/// \brief Calls the function with the given set of parameters and returns the value; /// \brief Calls the function with the given set of parameters and returns the value;
@ -718,14 +718,14 @@ Object drop_while(Range c, Function f);
Object reduce(Range c, Function f); Object reduce(Range c, Function f);
/// \brief Takes elements from Container c that match function f, return them. /// \brief Takes elements from Range c that match function f, return them.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> filter([1, 2, 3, 4], odd) /// eval> filter([1, 2, 3, 4], odd)
/// [1, 3] /// [1, 3]
/// \endcode /// \endcode
Object filter(Container c, Function f); Object filter(Range c, Function f);
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string. /// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.

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

@ -1,674 +0,0 @@
// From github.com/nbsdx/SimpleJSON.
// Released under the DWTFYW PL
//
#pragma once
#ifndef SIMPLEJSON_HPP
#define SIMPLEJSON_HPP
#include <cstdint>
#include <cmath>
#include <cctype>
#include <string>
#include <vector>
#include <map>
#include <type_traits>
#include <initializer_list>
#include <ostream>
#include <iostream>
#include "../chaiscript_defines.hpp"
namespace json {
using std::enable_if;
using std::initializer_list;
using std::is_same;
using std::is_convertible;
using std::is_integral;
using std::is_floating_point;
class JSON
{
public:
enum class Class {
Null,
Object,
Array,
String,
Floating,
Integral,
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>
class JSONWrapper {
Container *object = nullptr;
public:
JSONWrapper( Container *val ) : object( val ) {}
JSONWrapper( std::nullptr_t ) {}
typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
};
template <typename Container>
class JSONConstWrapper {
const Container *object = nullptr;
public:
JSONConstWrapper( const Container *val ) : object( val ) {}
JSONConstWrapper( std::nullptr_t ) {}
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(); }
};
JSON() = default;
JSON( std::nullptr_t ) {}
explicit JSON(Class type)
: internal(type)
{
}
JSON( initializer_list<JSON> list )
: internal(Class::Object)
{
for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) {
operator[]( i->to_string() ) = *std::next( i );
}
}
template <typename T>
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<bool>(b) ) {}
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) ) {}
template <typename T>
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) : internal( static_cast<double>(f) ) {}
template <typename T>
explicit JSON( T s, typename enable_if<is_convertible<T,std::string>::value>::type* = nullptr ) : internal( static_cast<std::string>(s) ) {}
static JSON Load( const std::string & );
JSON& operator[]( const std::string &key ) {
internal.set_type( Class::Object );
return internal.Map->operator[]( key );
}
JSON& operator[]( const size_t index ) {
internal.set_type( Class::Array );
if( index >= internal.List->size() ) {
internal.List->resize( index + 1 );
}
return internal.List->operator[]( index );
}
JSON &at( const std::string &key ) {
return operator[]( key );
}
const JSON &at( const std::string &key ) const {
return internal.Map->at( key );
}
JSON &at( size_t index ) {
return operator[]( index );
}
const JSON &at( size_t index ) const {
return internal.List->at( index );
}
long length() const {
if( internal.Type == Class::Array ) {
return static_cast<long>(internal.List->size());
} else {
return -1;
}
}
bool has_key( const std::string &key ) const {
if( internal.Type == Class::Object ) {
return internal.Map->count(key) != 0;
}
return false;
}
int size() const {
if( internal.Type == Class::Object ) {
return static_cast<int>(internal.Map->size());
} else if( internal.Type == Class::Array ) {
return static_cast<int>(internal.List->size());
} else {
return -1;
}
}
Class JSONType() const { return internal.Type; }
/// Functions for getting primitives from the JSON object.
bool is_null() const { return internal.Type == Class::Null; }
std::string to_string() const { bool b; return to_string( b ); }
std::string to_string( bool &ok ) const {
ok = (internal.Type == Class::String);
return ok ? *internal.String : std::string("");
}
double to_float() const { bool b; return to_float( b ); }
double to_float( bool &ok ) const {
ok = (internal.Type == Class::Floating);
return ok ? internal.Float : 0.0;
}
long to_int() const { bool b; return to_int( b ); }
long to_int( bool &ok ) const {
ok = (internal.Type == Class::Integral);
return ok ? internal.Int : 0;
}
bool to_bool() const { bool b; return to_bool( b ); }
bool to_bool( bool &ok ) const {
ok = (internal.Type == Class::Boolean);
return ok ? internal.Bool : false;
}
JSONWrapper<QuickFlatMap> object_range() {
if( internal.Type == Class::Object ) {
return JSONWrapper<QuickFlatMap>( internal.Map.get() );
} else {
return JSONWrapper<QuickFlatMap>( nullptr );
}
}
JSONWrapper<std::vector<JSON>> array_range() {
if( internal.Type == Class::Array ) {
return JSONWrapper<std::vector<JSON>>( internal.List.get() );
} else {
return JSONWrapper<std::vector<JSON>>( nullptr );
}
}
JSONConstWrapper<QuickFlatMap> object_range() const {
if( internal.Type == Class::Object ) {
return JSONConstWrapper<QuickFlatMap>( internal.Map.get() );
} else {
return JSONConstWrapper<QuickFlatMap>( nullptr );
}
}
JSONConstWrapper<std::vector<JSON>> array_range() const {
if( internal.Type == Class::Array ) {
return JSONConstWrapper<std::vector<JSON>>( internal.List.get() );
} else {
return JSONConstWrapper<std::vector<JSON>>( nullptr );
}
}
std::string dump( long depth = 1, std::string tab = " ") const {
switch( internal.Type ) {
case Class::Null:
return "null";
case Class::Object: {
std::string pad = "";
for( long i = 0; i < depth; ++i, pad += tab ) { }
std::string s = "{\n";
bool skip = true;
for( auto &p : *internal.Map ) {
if( !skip ) { s += ",\n"; }
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
skip = false;
}
s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
return s;
}
case Class::Array: {
std::string s = "[";
bool skip = true;
for( auto &p : *internal.List ) {
if( !skip ) { s += ", "; }
s += p.dump( depth + 1, tab );
skip = false;
}
s += "]";
return s;
}
case Class::String:
return "\"" + json_escape( *internal.String ) + "\"";
case Class::Floating:
return std::to_string( internal.Float );
case Class::Integral:
return std::to_string( internal.Int );
case Class::Boolean:
return internal.Bool ? "true" : "false";
}
throw std::runtime_error("Unhandled JSON type");
}
private:
static std::string json_escape( const std::string &str ) {
std::string output;
for(char i : str) {
switch( 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 += i; break;
}
}
return output;
}
private:
};
struct JSONParser {
static bool isspace(const char c)
{
#ifdef CHAISCRIPT_MSVC
// MSVC warns on these line in some circumstances
#pragma warning(push)
#pragma warning(disable : 6330)
#endif
return ::isspace(c) != 0;
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
static void consume_ws( const std::string &str, size_t &offset ) {
while( isspace( str[offset] ) && offset <= str.size() ) { ++offset; }
}
static JSON parse_object( const std::string &str, size_t &offset ) {
JSON Object( JSON::Class::Object );
++offset;
consume_ws( str, offset );
if( str[offset] == '}' ) {
++offset; return Object;
}
for (;offset<str.size();) {
JSON Key = parse_next( str, offset );
consume_ws( str, offset );
if( str[offset] != ':' ) {
throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str[offset] + "'\n");
}
consume_ws( str, ++offset );
JSON Value = parse_next( str, offset );
Object[Key.to_string()] = Value;
consume_ws( str, offset );
if( str[offset] == ',' ) {
++offset; continue;
}
else if( str[offset] == '}' ) {
++offset; break;
}
else {
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str[offset] + "'\n");
}
}
return Object;
}
static JSON parse_array( const std::string &str, size_t &offset ) {
JSON Array( JSON::Class::Array );
size_t index = 0;
++offset;
consume_ws( str, offset );
if( str[offset] == ']' ) {
++offset; return Array;
}
for (;offset < str.size();) {
Array[index++] = parse_next( str, offset );
consume_ws( str, offset );
if( str[offset] == ',' ) {
++offset; continue;
}
else if( str[offset] == ']' ) {
++offset; break;
}
else {
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str[offset] + "'\n");
}
}
return Array;
}
static JSON parse_string( const std::string &str, size_t &offset ) {
std::string val;
for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
if( c == '\\' ) {
switch( str[ ++offset ] ) {
case '\"': val += '\"'; break;
case '\\': val += '\\'; break;
case '/' : val += '/' ; break;
case 'b' : val += '\b'; break;
case 'f' : val += '\f'; break;
case 'n' : val += '\n'; break;
case 'r' : val += '\r'; break;
case 't' : val += '\t'; break;
case 'u' : {
val += "\\u" ;
for( size_t i = 1; i <= 4; ++i ) {
c = str[offset+i];
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) {
val += c;
} else {
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
}
}
offset += 4;
} break;
default : val += '\\'; break;
}
} else {
val += c;
}
}
++offset;
return JSON(val);
}
static JSON parse_number( const std::string &str, size_t &offset ) {
std::string val, exp_str;
char c = '\0';
bool isDouble = false;
bool isNegative = false;
long exp = 0;
if( offset < str.size() && str[offset] == '-' ) {
isNegative = true;
++offset;
}
for (; offset < str.size() ;) {
c = str[offset++];
if( c >= '0' && c <= '9' ) {
val += c;
} else if( c == '.' && !isDouble ) {
val += c;
isDouble = true;
} else {
break;
}
}
if( offset < str.size() && (c == 'E' || c == 'e' )) {
c = str[ offset++ ];
if( c == '-' ) {
exp_str += '-';
} else if( c == '+' ) {
// do nothing
} else {
--offset;
}
for (; offset < str.size() ;) {
c = str[ offset++ ];
if( c >= '0' && c <= '9' ) {
exp_str += c;
} else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
}
else {
break;
}
}
exp = chaiscript::parse_num<long>( exp_str );
}
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
}
--offset;
if( isDouble ) {
return JSON((isNegative?-1:1) * chaiscript::parse_num<double>( val ) * std::pow( 10, exp ));
} else {
if( !exp_str.empty() ) {
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<long>( val )) * std::pow( 10, exp ));
} else {
return JSON((isNegative?-1:1) * chaiscript::parse_num<long>( val ));
}
}
}
static JSON parse_bool( const std::string &str, size_t &offset ) {
if( str.substr( offset, 4 ) == "true" ) {
offset += 4;
return JSON(true);
} else if( str.substr( offset, 5 ) == "false" ) {
offset += 5;
return JSON(false);
} else {
throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'");
}
}
static JSON parse_null( const std::string &str, size_t &offset ) {
if( str.substr( offset, 4 ) != "null" ) {
throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'");
}
offset += 4;
return JSON();
}
static JSON parse_next( const std::string &str, size_t &offset ) {
char value;
consume_ws( str, offset );
value = str[offset];
switch( value ) {
case '[' : return parse_array( str, offset );
case '{' : return parse_object( str, offset );
case '\"': return parse_string( str, offset );
case 't' :
case 'f' : return parse_bool( str, offset );
case 'n' : return parse_null( str, offset );
default : if( ( value <= '9' && value >= '0' ) || value == '-' ) {
return parse_number( str, offset );
}
}
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
}
};
inline JSON JSON::Load( const std::string &str ) {
size_t offset = 0;
return JSONParser::parse_next( str, offset );
}
} // End Namespace json
#endif

View File

@ -1,150 +0,0 @@
#ifndef CHAISCRIPT_SIMPLEJSON_WRAP_HPP
#define CHAISCRIPT_SIMPLEJSON_WRAP_HPP
#include "json.hpp"
namespace chaiscript
{
class json_wrap
{
public:
static Module& library(Module& m)
{
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");
return m;
}
private:
static Boxed_Value from_json(const json::JSON &t_json)
{
switch( t_json.JSONType() ) {
case json::JSON::Class::Null:
return Boxed_Value();
case json::JSON::Class::Object:
{
std::map<std::string, Boxed_Value> m;
for (const auto &p : t_json.object_range())
{
m.insert(std::make_pair(p.first, from_json(p.second)));
}
return Boxed_Value(m);
}
case json::JSON::Class::Array:
{
std::vector<Boxed_Value> vec;
for (const auto &p : t_json.array_range())
{
vec.emplace_back(from_json(p));
}
return Boxed_Value(vec);
}
case json::JSON::Class::String:
return Boxed_Value(t_json.to_string());
case json::JSON::Class::Floating:
return Boxed_Value(t_json.to_float());
case json::JSON::Class::Integral:
return Boxed_Value(t_json.to_int());
case json::JSON::Class::Boolean:
return Boxed_Value(t_json.to_bool());
}
throw std::runtime_error("Unknown JSON type");
}
static Boxed_Value from_json(const std::string &t_json)
{
return from_json( json::JSON::Load(t_json) );
}
static std::string to_json(const Boxed_Value &t_bv)
{
return to_json_object(t_bv).dump();
}
static json::JSON to_json_object(const Boxed_Value &t_bv)
{
try {
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv);
json::JSON obj;
for (const auto &o : m)
{
obj[o.first] = to_json_object(o.second);
}
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a map
}
try {
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
json::JSON obj;
for (size_t i = 0; i < v.size(); ++i)
{
obj[i] = to_json_object(v[i]);
}
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a vector
}
try {
Boxed_Number bn(t_bv);
if (Boxed_Number::is_floating_point(t_bv))
{
return json::JSON(bn.get_as<double>());
} else {
return json::JSON(bn.get_as<long>());
}
} catch (const chaiscript::detail::exception::bad_any_cast &) {
// not a number
}
try {
return json::JSON(boxed_cast<bool>(t_bv));
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a bool
}
try {
return json::JSON(boxed_cast<std::string>(t_bv));
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a string
}
try {
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
json::JSON obj;
for (const auto &attr : o.get_attrs())
{
obj[attr.first] = to_json_object(attr.second);
}
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a dynamic object
}
throw std::runtime_error("Unknown object type to convert to JSON");
}
};
}
#endif

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,121 +1,97 @@
// 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-2014, 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_
#include "../chaiscript.hpp"
#include <boost/preprocessor.hpp>
#include <string> #include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "../language/chaiscript_common.hpp" #define CHAISCRIPT_MODULE(_info) BOOST_PP_SEQ_ELEM(0, _info)
#include "../dispatchkit/register_function.hpp"
#include "../dispatchkit/operators.hpp"
#define CHAISCRIPT_CLASS_ELEM(_info) BOOST_PP_SEQ_ELEM(1, _info)
#define CHAISCRIPT_METHOD(_info, _method) & CHAISCRIPT_CLASS_ELEM(_info) :: BOOST_PP_SEQ_ELEM(0, _method)
#define CHAISCRIPT_METHOD_NAME(_info, _method) \
BOOST_PP_SEQ_ELEM(3, _info) (BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(0, _method ) ) )
#define CHAISCRIPT_CLASS_NAME(_info) \
BOOST_PP_SEQ_ELEM(2, _info) (BOOST_PP_STRINGIZE(CHAISCRIPT_CLASS_ELEM(_info) ) )
#define CHAISCRIPT_METHOD_SIGNATURE_PART(_r, _info, _i, _method_part) \
BOOST_PP_EXPR_IF(BOOST_PP_EQUAL(_i, 1), < _method_part > )
#define CHAISCRIPT_METHOD_SIGNATURE(_info, _method) \
BOOST_PP_SEQ_FOR_EACH_I(CHAISCRIPT_METHOD_SIGNATURE_PART, _info, _method)
#define CHAISCRIPT_CLASS_CONSTRUCTOR(_r, _info, _constructor) \
CHAISCRIPT_MODULE(_info) ->add BOOST_PP_LPAREN() chaiscript::constructor<_constructor>() BOOST_PP_COMMA() CHAISCRIPT_CLASS_NAME(_info) BOOST_PP_RPAREN() ;
#define CHAISCRIPT_CLASS_METHOD(_r, _info, _method) \
CHAISCRIPT_MODULE(_info) ->add BOOST_PP_LPAREN() chaiscript::fun CHAISCRIPT_METHOD_SIGNATURE(_info, _method) \
BOOST_PP_LPAREN() CHAISCRIPT_METHOD(_info, _method) BOOST_PP_RPAREN() BOOST_PP_COMMA() CHAISCRIPT_METHOD_NAME(_info, _method)BOOST_PP_RPAREN() ;
#define CHAISCRIPT_CLASS_CONSTRUCTORS(_info, _constructors) \
BOOST_PP_SEQ_FOR_EACH(CHAISCRIPT_CLASS_CONSTRUCTOR, _info, _constructors)
#define CHAISCRIPT_CLASS_METHODS(_info, _methods) \
BOOST_PP_SEQ_FOR_EACH(CHAISCRIPT_CLASS_METHOD, _info, _methods)
#define CHAISCRIPT_CLASS_EX(_module, _class_name, _class_name_translator, _method_name_translator, _constructors, _methods) \
{ \
_module->add(chaiscript::user_type<_class_name>(), _class_name_translator (BOOST_PP_STRINGIZE(_class_name))); \
CHAISCRIPT_CLASS_CONSTRUCTORS((_module)(_class_name)(_class_name_translator), _constructors) \
CHAISCRIPT_CLASS_METHODS((_module)(_class_name)(_class_name_translator)(_method_name_translator), _methods) \
}
#define CHAISCRIPT_CLASS_NO_CONSTRUCTOR_EX(_module, _class_name, _class_name_translator, _method_name_translator, _methods) \
{ \
_module->add(chaiscript::user_type<_class_name>(), _class_name_translator (BOOST_PP_STRINGIZE(_class_name))); \
CHAISCRIPT_CLASS_METHODS((_module)(_class_name)(_class_name_translator)(_method_name_translator), _methods) \
}
#define CHAISCRIPT_CLASS(_module, _class_name, _constructors, _methods) \
CHAISCRIPT_CLASS_EX(_module, _class_name, chaiscript::utility::class_name_translator, \
chaiscript::utility::method_name_translator, _constructors, _methods)
#define CHAISCRIPT_CLASS_NO_CONSTRUCTOR(_module, _class_name, _methods) \
CHAISCRIPT_CLASS_NO_CONSTRUCTOR_EX(_module, _class_name, chaiscript::utility::class_name_translator, \
chaiscript::utility::method_name_translator, _methods)
namespace chaiscript namespace chaiscript
{ {
/// \brief Classes and functions which provide general utility to the end user.
namespace utility namespace utility
{ {
inline std::string class_name_translator(const std::string &t_name)
/// Single step command for registering a class with ChaiScript {
/// size_t colon = t_name.rfind("::");
/// \param[in,out] t_module Model to add class to if (colon != std::string::npos)
/// \param[in] t_class_name Name of the class being registered
/// \param[in] t_constructors Vector of constructors to add
/// \param[in] t_funcs Vector of methods to add
///
/// \example Adding a basic class to ChaiScript in one step
///
/// \code
/// chaiscript::utility::add_class<test>(*m,
/// "test",
/// { constructor<test ()>(),
/// constructor<test (const test &)>() },
/// { {fun(&test::function), "function"},
/// {fun(&test::function2), "function2"},
/// {fun(&test::function3), "function3"},
/// {fun(static_cast<std::string(test::*)(double)>(&test::function_overload)), "function_overload" },
/// {fun(static_cast<std::string(test::*)(int)>(&test::function_overload)), "function_overload" },
/// {fun(static_cast<test & (test::*)(const test &)>(&test::operator=)), "=" }
/// }
/// );
///
template<typename Class, typename ModuleType>
void add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<chaiscript::Proxy_Function> &t_constructors,
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs)
{ {
t_module.add(chaiscript::user_type<Class>(), t_class_name); return t_name.substr(colon+2, std::string::npos);
} else {
return t_name;
}
}
for(const chaiscript::Proxy_Function &ctor: t_constructors) inline std::string method_name_translator(const std::string &t_name)
{ {
t_module.add(ctor, t_class_name); size_t namestart = t_name.rfind("operator");
} namestart = (namestart == std::string::npos)?0:namestart+strlen("operator");
for(const auto &fun: t_funcs) if (namestart == 0)
{ {
t_module.add(fun.first, fun.second); namestart = t_name.rfind("::");
} namestart = (namestart == std::string::npos)?0:namestart+strlen("::");
} }
template<typename Enum, typename ModuleType> return t_name.substr(namestart, std::string::npos);
typename std::enable_if<std::is_enum<Enum>::value, void>::type }
add_class(ModuleType &t_module,
const std::string &t_class_name,
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::constructor<Enum ()>(), t_class_name);
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<Enum>(t_module);
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 int &i, const Enum &e) { return i == e; }), "==");
for (const auto &constant : t_constants)
{
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-2014 Jason Turner
Copyright 2009-2012 Jonathan Turner. Copyright 2009-2012 Jonathan Turner.
All Rights Reserved. All Rights Reserved.

View File

@ -1,19 +0,0 @@
def go()
{
var my_array=["1", 4, 6.6l, 10ul, "1000", 100, 10.9f ];
var q = 0;
for (var j = 0; j < 10000; ++j)
{
for (var i = 0; i < 6; ++i)
{
to_string(my_array[i]);
}
q += j;
}
}
go();

View File

@ -1,26 +0,0 @@
var test_str = "bob was a string";
for( var i = 0; i < 200000; ++i)
{
test_str.size();
// test_str.find("a", i);
test_str.c_str();
test_str.erase_at(1);
test_str.erase_at(1);
test_str.erase_at(1);
test_str.erase_at(1);
test_str.erase_at(1);
test_str.erase_at(1);
size(test_str);
// test_str.find("a", i);
c_str(test_str);
erase_at(test_str, 1);
erase_at(test_str, 1);
erase_at(test_str, 1);
erase_at(test_str, 1);
erase_at(test_str, 1);
erase_at(test_str, 1);
test_str = "bob was a string";
}

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,22 +0,0 @@
load_module("test_module")
auto t := TestBaseType();
// This uses the TestBaseType to Type2 user type
// conversion which was added in the module and then calls
// "get_val()" which exists on the Type2 type
//assert_equal(t.get_val(), 10);
//print("Made it past test 1");
var t2 := Type2(t);
//dump_system();
for (var i = 0; i < 50000; ++i) {
var str = string(get_str(t2));
size(get_str(t2));
t2.get_str().size();
t.get_str().size();
}

View File

@ -1,63 +1,41 @@
<a href="https://www.patreon.com/bePatron?u=2977989&redirect_uri=https%3A%2F%2Fwww.patreon.com%2Flefticus"> [![Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript)
<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)
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)
<a href="https://scan.coverity.com/projects/5297">
<img alt="Coverity Scan Build Status"
src="https://img.shields.io/coverity/scan/5297.svg"/>
</a>
ChaiScript 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-2014 Jason Turner
Release under the BSD license, see "license.txt" for details. Release under the BSD license, see "license.txt" for details.
Introduction Introduction
============ ============
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/ChaiScript/ChaiScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
ChaiScript is one of the only embedded scripting language designed from the ChaiScript is one of the only embedded scripting language designed from the
ground up to directly target C++ and take advantage of modern C++ development ground up to directly target C++ and take advantage of modern C++ development
techniques, working with the developer like he expects it to work. Being a techniques, working with the developer like he expects it to work. Being a
native C++ application, it has some advantages over existing embedded scripting native C++ application, it has some advantages over existing embedded scripting
languages: languages:
1. It uses a header-only approach, which makes it easy to integrate with 1) It uses a header-only approach, which makes it easy to integrate with
existing projects. existing projects.
2. It maintains type safety between your C++ application and the user scripts. 2) It maintains type safety between your C++ application and the user scripts.
3. It supports a variety of C++ techniques including callbacks, overloaded 3) It supports a variety of C++ techniques including callbacks, overloaded
functions, class methods, and stl containers. functions, class methods, and stl containers.
Requirements Requirements
============ ============
ChaiScript requires a C++14 compiler to build with support for variadic ChaiScript requires a recent version of Boost (http://www.boost.org) to build.
templates. It has been tested with gcc 4.9 and clang 3.6 (with libcxx).
For more information see the build
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
Usage Usage
===== =====
* Add the ChaiScript include directory to your project's header search path * Add the ChaiScript include directory to your project's header search path
* Add `#include <chaiscript/chaiscript.hpp>` to your source file * Add `#include <chaiscript/chaiscript.hpp>` to your source file
* Instantiate the ChaiScript engine in your application. For example, create a * Instantiate the ChaiScript engine in your application. For example, create
new engine with the name `chai` like so: `chaiscript::ChaiScript chai` a new engine with the name `chai` like so: `chaiscript::ChaiScript chai`
* The default behavior is to load the ChaiScript standard library from a
loadable module. A second option is to compile the library into your code,
see below for an example.
Once instantiated, the engine is ready to start running ChaiScript source. You Once instantiated, the engine is ready to start running ChaiScript source. You
have two main options for processing ChaiScript source: a line at a time using have two main options for processing ChaiScript source: a line at a time using
@ -79,7 +57,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 +65,21 @@ 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()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}
```

View File

@ -1,299 +0,0 @@
Notes:
=======
Current Version: 6.0.0
### 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
* Build time reduction
* Build size reduction
* Performance increases
* Fixed ~20 crash-bugs found with fuzzy testing #194
* Let unhandled exceptions propogate to user
* Report eval_error when break statement is not in loop
* Fix handling of 0 length scripts closes #193
* Don't crash on arity mismatch - Specifically affects the case where no overloads exist for a given function
* Fix error printing for `bind` calls
* Handle unexpected continue statement
* Check arity during bind
* Don't allow arith conversion on variadic function
* Correct `bind` parameter match count
* Add in expected Boxed_Value exception cases
* Check access to AST, don't allow `;` in func def
* Don't attempt arithmetic unary & call
* Don't crash on 0 param call to `bind`
* Catch errors during member function dispatch
* Properly handle type of const bool &
* Automatic deduction of lambda type signatures
* Work with non-polymorphic parent/child conversions
* Move to codecov for coverage reporting
* Add `.at` method for Map objects
* Various corrections for support of move-only objects
### Changes since 5.6.0
* Significant code cleanups and reduction
* Smaller builds
* Faster compiles
* Less runtime memory usage
* ~2x faster runtimes
* biicode support
* method_missing feature added #164 @arBmind
* Generic objects with dynamic properties support
* Add ability to call functions contained in properties
* Add lambda captures
* Create [cheatsheet.md](cheatsheet.md) for all-in-one reference of features
* Fix support for libc++
* Eliminate clone of return value stored locally
* Eliminate 'return' statements when last line of function
* Reduce number of runtime exceptions occuring
* Reduce copies / moves of return values.
* make `use` statement return value of last statement in file
* Add ability to access fixed array sizes
* Add support for scientific notation floating point literals #174 @totalgee
### Changes since 5.5.1
* Throw exception on integer divide by 0
* Add optional type specification to function declarations
```
def func(int i, j, double k) {
// i must be an int.
// j can be anything
// k must be a double
// normal conversion rules still apply
}
```
* Many minor fixes for compiler warnings
* Add support for `std::future` and `std::async`
```
var f := async(someFunction);
var f2 := async(someFunction2);
// someFunction and someFunction2 are running in parallel now
f.get();
f2.get();
```
* Fully support r-value returns, supporting move-only objects and reducing object copies
### Changes since 5.5.0
* 30% performance increase
* Fix handling of object stack, resulting in greatly reduced memory usage
* Code cleanups
### Changes since 5.4.0
* 2x performance increase
* Significant code cleanups
* Throw exception if user attempts to call function on null object
* Allow user defined type conversions
* Fix object lifetime for nested function calls made at the global scope
* Fix returning of boolean values from function calls
### Changes since 5.3.1
* Decreased compile time and build size
* Make "reflection" module built in (losing some of the time / build size gains)
* Add new "class" syntax for ChaiScript defined methods and attributes see: [unittests/class.chai](unittests/class.chai) for examples
* Minor performance enhancements
* major to_string performance enhancements
* Provide API for retrieving registered type name #124
* Added strong reference to container to range object #132
### Changes since 5.3.0
* Add automatic conversion of arithmetic return types, following the same
rules as conversion of arithmetic types when passing parameters
* Add automatic casting up the inheritence hierarchy when possible.
* Enable travis.ci testing
* Allow users to add globals from within script
* Various static analysis fixes
* Code modernization to C++11
* Unofficial support for Haiku added
* Fix #121 - Inability to compile on cygwin
* Formatting fixes and spelling corrections
* Apply "include what you use" https://code.google.com/p/include-what-you-use/
* Apply clang-modernize
* Various threading fixes
* Performance improvements
### Changes since 5.2.0
* Official support for MSVC with C++11. All major platforms and compilers are now support for C++11 release
### Changes since 4.2.0
* Enhanced unit tests
* Add `continue` statement, fix various use cases for `for` loops
* Fix use of suffixed numbers in vector initialization
* Code cleanups
* Eliminate global data, which makes code more portable and thread safe
* Fix issue #79
* Merge pretty_print fixes from @mgee #82
* Compiler warning fixes for latest compiler releases
* Fix threading problems
* Fix linking error on MacOS Mavericks #88
* Allow non-const globals
* Make sure user cannot name a variable with `::` in it #91
* Fix various string / map / vector `size` and `count` calls for compilers which have weird overloads for them. #90 #93 #95
* Make module search path relative to the currently running executable
* Build and work with wstring windows builds
* fix for some new line cases in the middle of a vector initialization from jespada
### Changes since 5.1.0
* Add support for automatic conversion of arithmetic types when possible
and when no ambiguous method dispatch exists.
### Changes since 5.0.0
* Fix sizing of numeric constants to match that of the C++ standard
* Add support for u,ll,l,f suffixes for numeric constants
* Siginificant improvement in error reporting
### Changes since 4.0.0
* Dropped boost in favor of C++11
* Separated out stdlib to make more options for compile time improvements
### Changes since 3.1.0
* svenstaro: Unused variables and CMake consistency fixes
* Added support for returning pointers from functions (#13)
* Compile with -pedantic (#9)
* Fix issues with multiple ChaiScript object types having the same attribute name (#15)
* Prevent variable redeclaration in same scope (#22)
* mgee: Boxed_Number improvements (#27)
* Support switch statements (#34)
* Fix uint16 comparions (#26)
* Add ability to add const_var globals in Module objects (#14)
* Add support for ternary operators ?:
* Add headers to CMakeLists so they show up in IDEs
* Add ability to get vector of defined objects and vector of defined functions
* Fix memory leak in cyclical references
* Clean up static analysis issues discovered
* Fix vector construction to be consistent with map construction
* Increased unit tests to 161
* Performance enhancements
### Changes since 3.0.0
* Numeric operations performance increased approximately 10x
* Looping operations performance increased up to 2x
* Engine start up time decreased
* Several parsing bugs related to index operators fixed
* Added full support for all C algebraic types: double, long double, float, int, long, char,
uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t
* Enhanced support for capturing of exceptions thrown from ChaiScript in C++
### Changes since 2.3.3
* Code simplifications
* Fully integrate documentation with source code in doxygen style comments
* Unit tests increased from 114 to 137
* Automatic conversion between boost::function objects and ChaiScript functions
* Many bug fixes
* Minor performance improvements
* Namespace reorganization to make end user code more accessible
* clang support
* VisualStudio 2010 Support
* Support for C++ base classes and automatic upcasting
* Remove __ reserved identifiers
* Better code organization to reduce #ifdefs
* clanmills: command line options for chai eval
* clanmills: parser cleanups and code reduction
* Function introspection and reflection
* Correct function dispatch order to account for base classes and provide a defined order of dispatch
* Predictable object lifetime that emulates C++ stack lifetime
* emarcotte: pkgconfig support
* standardize on method/member naming and indentation
* 64bit Visual Studio support
* Better support for const objects
* Drastic reduction of runtime exceptions - making debug builds orders of magnitude faster
* Support for platforms with no loadable module support
* Add helper macro for registering class

92
releasenotes.txt Normal file
View File

@ -0,0 +1,92 @@
Current Version: 4.3.1
Note: this is scheduled to be the last release that requires boost, new releases after this will require a C++11 compiler.
### Changes since 4.3.0
* Add automatic conversion of arithmetic return types, following the same
rules as conversion of arithmetic types when passing parameters
* Add automatic casting up the inheritence hierarchy when possible.
* Enable travis.ci testing
### Changes since 4.2.0
* Enhanced unit tests
* Add `continue` statement, fix various use cases for `for` loops
* Fix use of suffixed numbers in vector initialization
* Code cleanups
* Eliminate global data, which makes code more portable and thread safe
* Fix issue #79
* Merge pretty_print fixes from @mgee #82
* Compiler warning fixes for latest compiler releases
* Fix threading problems
* Fix linking error on MacOS Mavericks #88
* Allow non-const globals
* Make sure user cannot name a variable with `::` in it #91
* Fix various string / map / vector `size` and `count` calls for compilers which have weird overloads for them. #90 #93 #95
* Make module search path relative to the currently running executable
* Build and work with wstring windows builds
### Changes since 4.1.1
* Add support for automatic conversion of arithmetic types when possible
and when no ambiguous method dispatch exists.
### Changes since 4.1.0
* Fix missed gcc build error in 4.1.0
Changes since 4.0.0
* Fix sizing of numeric constants to match that of the C++ standard
* Add support for u,ll,l,f suffixes for numeric constants
* Siginificant improvement in error reporting
Changes since 3.1.0
* svenstaro: Unused variables and CMake consistency fixes
* Added support for returning pointers from functions (#13)
* Compile with -pedantic (#9)
* Fix issues with multiple ChaiScript object types having the same attribute name (#15)
* Prevent variable redeclaration in same scope (#22)
* mgee: Boxed_Number improvements (#27)
* Support switch statements (#34)
* Fix uint16 comparions (#26)
* Add ability to add const_var globals in Module objects (#14)
* Add support for ternary operators ?:
* Add headers to CMakeLists so they show up in IDEs
* Add ability to get vector of defined objects and vector of defined functions
* Fix memory leak in cyclical references
* Clean up static analysis issues discovered
* Fix vector construction to be consistent with map construction
* Increased unit tests to 161
* Performance enhancements
### Changes since 3.0.0
* Numeric operations performance increased approximately 10x
* Looping operations performance increased up to 2x
* Engine start up time decreased
* Several parsing bugs related to index operators fixed
* Added full support for all C algebraic types: double, long double, float, int, long, char,
uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t
* Enhanced support for capturing of exceptions thrown from ChaiScript in C++
### Changes since 2.3.3
* Code simplifications
* Fully integrate documentation with source code in doxygen style comments
* Unit tests increased from 114 to 137
* Automatic conversion between boost::function objects and ChaiScript functions
* Many bug fixes
* Minor performance improvements
* Namespace reorganization to make end user code more accessible
* clang support
* VisualStudio 2010 Support
* Support for C++ base classes and automatic upcasting
* Remove __ reserved identifiers
* Better code organization to reduce #ifdefs
* clanmills: command line options for chai eval
* clanmills: parser cleanups and code reduction
* Function introspection and reflection
* Correct function dispatch order to account for base classes and provide a defined order of dispatch
* Predictable object lifetime that emulates C++ stack lifetime
* emarcotte: pkgconfig support
* standardize on method/member naming and indentation
* 64bit Visual Studio support
* Better support for const objects
* Drastic reduction of runtime exceptions - making debug builds orders of magnitude faster
* Support for platforms with no loadable module support
* Add helper macro for registering class

View File

@ -5,20 +5,32 @@
// http://www.chaiscript.com // http://www.chaiscript.com
#include <iostream> #include <iostream>
#include <ctime>
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp> #include <chaiscript/dispatchkit/function_call.hpp>
#include <boost/function.hpp>
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
#include <boost/date_time/posix_time/posix_time.hpp>
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#include <boost/regex.hpp>
void log(const std::string &msg) void log(const std::string &msg)
{ {
std::cout << "[" << time(nullptr) << "] " << msg << '\n'; std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] " << msg << std::endl;
} }
void log(const std::string &module, const std::string &msg) void log(const std::string &module, const std::string &msg)
{ {
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n'; std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] <" << module << "> " << msg << std::endl;
} }
void bound_log(const std::string &msg) void bound_log(const std::string &msg)
@ -28,21 +40,21 @@ void bound_log(const std::string &msg)
void hello_world(const chaiscript::Boxed_Value & /*o*/) void hello_world(const chaiscript::Boxed_Value & /*o*/)
{ {
std::cout << "Hello World\n"; std::cout << "Hello World" << std::endl;
} }
void hello_constructor(const chaiscript::Boxed_Value & /*o*/) void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
{ {
std::cout << "Hello Constructor\n"; std::cout << "Hello Constructor" << std::endl;
} }
struct System struct System
{ {
std::map<std::string, std::function<std::string (const std::string &) > > m_callbacks; std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks;
void add_callback(const std::string &t_name, void add_callback(const std::string &t_name,
const std::function<std::string (const std::string &)> &t_func) const boost::function<std::string (const std::string &)> &t_func)
{ {
m_callbacks[t_name] = t_func; m_callbacks[t_name] = t_func;
} }
@ -51,7 +63,7 @@ struct System
void do_callbacks(const std::string &inp) void do_callbacks(const std::string &inp)
{ {
log("Running Callbacks: " + inp); log("Running Callbacks: " + inp);
for (std::map<std::string, std::function<std::string (const std::string &)> >::iterator itr = m_callbacks.begin(); for (std::map<std::string, boost::function<std::string (const std::string &)> >::iterator itr = m_callbacks.begin();
itr != m_callbacks.end(); itr != m_callbacks.end();
++itr) ++itr)
{ {
@ -60,9 +72,9 @@ struct System
} }
}; };
void take_shared_ptr(const std::shared_ptr<const std::string> &p) void take_shared_ptr(const boost::shared_ptr<const std::string> &p)
{ {
std::cout << *p << '\n'; std::cout << *p << std::endl;
} }
int main(int /*argc*/, char * /*argv*/[]) { int main(int /*argc*/, char * /*argv*/[]) {
@ -70,13 +82,12 @@ int main(int /*argc*/, char * /*argv*/[]) {
ChaiScript chai; ChaiScript chai;
//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, system), "add_callback_bound");
//Register the two methods of the System structure. //Register the two methods of the System structure.
chai.add(fun(&System::add_callback), "add_callback"); chai.add(fun(&System::add_callback), "add_callback");
@ -87,7 +98,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
// Let's use chaiscript to add a new lambda callback to our system. // Let's use chaiscript to add a new lambda callback to our system.
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application // The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
// in the "add_callback" function of struct System the chaiscript function is converted into a // in the "add_callback" function of struct System the chaiscript function is converted into a
// std::function, so it can be handled and called easily and type-safely // boost::function, so it can be handled and called easily and type-safely
chai.eval("system.add_callback(\"#1\", fun(x) { \"Callback1 \" + x });"); chai.eval("system.add_callback(\"#1\", fun(x) { \"Callback1 \" + x });");
// Because we are sharing the "system" object with the chaiscript engine we have equal // Because we are sharing the "system" object with the chaiscript engine we have equal
@ -108,14 +119,14 @@ 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 boost::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, boost::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()");
std::function<void ()> caller = chai.eval<std::function<void ()> >("fun() { system.do_callbacks(\"From Functor\"); }"); boost::function<void ()> caller = chai.eval<boost::function<void ()> >("fun() { system.do_callbacks(\"From Functor\"); }");
caller(); caller();
@ -123,7 +134,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
//the templated version of eval: //the templated version of eval:
int i = chai.eval<int>("5+5"); int i = chai.eval<int>("5+5");
std::cout << "5+5: " << i << '\n'; std::cout << "5+5: " << i << std::endl;
//Add a new variable //Add a new variable
chai("var scripti = 15"); chai("var scripti = 15");
@ -131,21 +142,21 @@ int main(int /*argc*/, char * /*argv*/[]) {
//We can even get a handle to the variables in the system //We can even get a handle to the variables in the system
int &scripti = chai.eval<int &>("scripti"); int &scripti = chai.eval<int &>("scripti");
std::cout << "scripti: " << scripti << '\n'; std::cout << "scripti: " << scripti << std::endl;
scripti *= 2; scripti *= 2;
std::cout << "scripti (updated): " << scripti << '\n'; std::cout << "scripti (updated): " << scripti << std::endl;
chai("print(\"Scripti from chai: \" + to_string(scripti))"); chai("print(\"Scripti from chai: \" + to_string(scripti))");
//To do: Add examples of handling Boxed_Values directly when needed //To do: Add examples of handling Boxed_Values directly when needed
//Creating a functor on the stack and using it immediately //Creating a functor on the stack and using it immediatly
int x = chai.eval<std::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6); int x = chai.eval<boost::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
std::stringstream ss; std::stringstream ss;
ss << x; ss << x;
log("Functor test output", ss.str()); log("Functor test output", ss.str());
chai.add(var(std::shared_ptr<int>()), "nullvar"); chai.add(var(boost::shared_ptr<int>()), "nullvar");
chai("print(\"This should be true.\"); print(nullvar.is_var_null())"); chai("print(\"This should be true.\"); print(nullvar.is_var_null())");
// test the global const action // test the global const action
@ -167,7 +178,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
//Dynamic objects test //Dynamic objects test
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world"); chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType"); chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr"); // chai.add(fun(boost::function<Boxed_Value (dispatch::Dynamic_Object &)>(boost::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", _1))), "attr");
chai.eval("var x = TestType()"); chai.eval("var x = TestType()");
// chai.eval("x.attr = \"hi\""); // chai.eval("x.attr = \"hi\"");

View File

@ -1,102 +0,0 @@
#include <chaiscript/chaiscript.hpp>
class Entity
{
public:
int width;
int height;
int x;
int y;
std::string name;
std::function<void (Entity &)> updater;
Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name)
: width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name))
{
}
};
class Factory
{
public:
// we may as well pass the parameters for the entity to the factory method, this does the initialization
// in one step.
Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name)
{
auto entity = entities.insert({name, Entity{width, height, x, y, name}});
return &(entity.first->second);
}
Entity *get_entity(const std::string &name)
{
return &entities.at(name);
}
// loop over all entities and all their updater function (if it exists)
void update_entities()
{
for (auto &entity : entities)
{
if (entity.second.updater) {
entity.second.updater(entity.second);
}
}
}
private:
// we cannot store the entities in a std::vector if we want to return a pointer to them,
// because a vector automatically resizing itself can invalidate the pointer that was returned.
// using a map guarantees that the memory assigned to the entity will never change, plus
// lets us easily look up an entity by name
std::map<std::string, Entity> entities;
};
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&Entity::width), "width");
chai.add(chaiscript::fun(&Entity::height), "height");
chai.add(chaiscript::fun(&Entity::x), "x");
chai.add(chaiscript::fun(&Entity::y), "y");
chai.add(chaiscript::fun(&Entity::name), "name");
chai.add(chaiscript::fun(&Entity::updater), "updater");
chai.add(chaiscript::user_type<Entity>(), "Entity"); // this isn't strictly necessary but makes error messages nicer
chai.add(chaiscript::fun(&Factory::make_entity), "make_entity");
chai.add(chaiscript::fun(&Factory::get_entity), "get_entity");
chai.add(chaiscript::fun(&Factory::update_entities), "update_entities");
chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer
Factory f;
chai.add(chaiscript::var(&f), "f");
std::string script = R""(
f.make_entity(10,10,1,1,"entity1").updater = fun(e){ e.x += 1; e.y += 1 };
f.make_entity(10,10,10,10,"entity2").updater = fun(e){ e.x += 2; e.y += 2 };
f.make_entity(10,10,20,20,"entity3");
print(f.get_entity("entity1").x == 1)
print(f.get_entity("entity2").x == 10)
print(f.get_entity("entity3").x == 20)
f.update_entities(); // this runs the function objects we set in the previous lines
// we should now see the updated values
print(f.get_entity("entity1").x == 2)
print(f.get_entity("entity2").x == 12)
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
)"";
chai.eval(script);
}

View File

@ -1,13 +1,13 @@
for (var i = 0; i < 10; ++i) { for (var i = 0; i < 10; ++i) {
print(i) print(i)
} }
for (var i = 10; i >= 0; i -= 2) { for (var i = 10; i >= 0; i -= 2) {
print(i) print(i)
} }
var i = 0 var i = 0
for (; i < 5; ++i) { for (; i < 5; ++i) {
print(i) print(i)
} }

View File

@ -1,10 +1,10 @@
//functions of zero params don't need them: //functions of zero params don't need them:
def meet { def meet {
print("Hello") print("Hello")
} }
def greet(x) { def greet(x) {
print("Hello, " + x.to_string()) print("Hello, " + x.to_string())
} }
//but you need parens for invocation: //but you need parens for invocation:

View File

@ -1,4 +0,0 @@
for (var i = 0; i < 1000; ++i) {
puts(helloWorld("Bob12345"))
}

View File

@ -1,410 +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
// 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 <list>
#include <regex>
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <chaiscript/chaiscript.hpp>
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#else
char *mystrdup(const char *s) {
size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char*>(malloc(len + 1));
if (d == nullptr) return nullptr; // No memory
#ifdef CHAISCRIPT_MSVC
strcpy_s(d, len + 1, s); // Copy the characters
#else
strncpy(d, s, len); // Copy the characters
#endif
d[len] = '\0';
return d; // Return the new string
}
char* readline(const char* p)
{
std::string retval;
std::cout << p;
std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
}
void add_history(const char*){}
void using_history(){}
#endif
void *cast_module_symbol(std::vector<std::string>(*t_path)())
{
union cast_union
{
std::vector<std::string>(*in_ptr)();
void *out_ptr;
};
cast_union c;
c.in_ptr = t_path;
return c.out_ptr;
}
std::vector<std::string> default_search_paths()
{
std::vector<std::string> paths;
#ifndef CHAISCRIPT_NO_DYNLOAD
#ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096];
int size = GetModuleFileNameA(0, path, sizeof(path) - 1);
std::string exepath(path, size);
size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
return{ exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\" };
}
#else
std::string exepath;
std::vector<char> buf(2048);
ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size));
}
if (exepath.empty())
{
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size));
}
}
if (exepath.empty())
{
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size));
}
}
if (exepath.empty())
{
Dl_info rInfo;
memset(&rInfo, 0, sizeof(rInfo));
if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) {
return paths;
}
exepath = std::string(rInfo.dli_fname);
}
size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
}
#endif
#endif // ifndef CHAISCRIPT_NO_DYNLOAD
return paths;
}
void help(int n) {
if (n >= 0) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
}
else {
std::cout << "usage : chai [option]+" << std::endl;
std::cout << "option:" << std::endl;
std::cout << " -h | --help" << std::endl;
std::cout << " -i | --interactive" << std::endl;
std::cout << " -c | --command cmd" << std::endl;
std::cout << " -v | --version" << std::endl;
std::cout << " - --stdin" << std::endl;
std::cout << " filepath" << std::endl;
}
}
std::string helloWorld(const std::string &t_name)
{
return "Hello " + t_name + "!";
}
bool throws_exception(const std::function<void()> &f)
{
try {
f();
}
catch (...) {
return true;
}
return false;
}
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f)
{
try {
f();
}
catch (const chaiscript::exception::eval_error &e) {
return e;
}
throw std::runtime_error("no exception throw");
}
std::string get_next_command() {
std::string retval("quit");
if (!std::cin.eof()) {
char *input_raw = readline("eval> ");
if (input_raw) {
add_history(input_raw);
std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(0, pos);
}
pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(pos + 1, std::string::npos);
}
retval = val;
::free(input_raw);
}
}
if (retval == "quit"
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
retval += "(0)";
}
return retval;
}
// We have to wrap exit with our own because Clang has a hard time with
// function pointers to functions with special attributes (system exit being marked NORETURN)
void myexit(int return_val) {
exit(return_val);
}
void interactive(chaiscript::ChaiScript& chai)
{
using_history();
for (;;) {
std::string input = get_next_command();
try {
// evaluate input
chaiscript::Boxed_Value val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try {
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl;
}
catch (...) {} //If we can't, do nothing
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what();
if (ee.call_stack.size() > 0) {
std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
}
std::cout << std::endl;
}
catch (const std::exception &e) {
std::cout << e.what();
std::cout << std::endl;
}
}
}
int main(int argc, char *argv[])
{
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
const char *usepath = getenv("CHAI_USE_PATH");
const char *modulepath = getenv("CHAI_MODULE_PATH");
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
std::vector<std::string> usepaths;
usepaths.push_back("");
if (usepath)
{
usepaths.push_back(usepath);
}
std::vector<std::string> modulepaths;
std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.push_back("");
if (modulepath)
{
modulepaths.push_back(modulepath);
}
//chaiscript::ChaiScript chai(modulepaths, usepaths);
chaiscript::ChaiScript chai(usepaths);
chai.add(chaiscript::fun(&myexit), "exit");
chai.add(chaiscript::fun(&myexit), "quit");
chai.add(chaiscript::fun(&help), "help");
chai.add(chaiscript::fun(&throws_exception), "throws_exception");
chai.add(chaiscript::fun(&get_eval_error), "get_eval_error");
chai.add(chaiscript::fun(&helloWorld), "helloWorld");
clock_t begin = clock();
for (int i = 0; i < 1000; i++)
{
std::string str = helloWorld("Bob12345");
fwrite(str.c_str(), 1, str.size(), stdout);
}
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//begin = clock();
////for (int i = 0; i < 1000; i++)
////{
//// chai.eval("puts(helloWorld(\"Bob12345\"));");
////}
//chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai");
//end = clock();
//elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//printf("**MyProgram::time= %lf\n", elapsed_secs);
for (int i = 0; i < argc; ++i) {
if (i == 0 && argc > 1) {
++i;
}
std::string arg(i ? argv[i] : "--interactive");
enum {
eInteractive
, eCommand
, eFile
} mode = eCommand;
if (arg == "-c" || arg == "--command") {
if ((i + 1) >= argc) {
std::cout << "insufficient input following " << arg << std::endl;
return EXIT_FAILURE;
}
else {
arg = argv[++i];
}
}
else if (arg == "-" || arg == "--stdin") {
arg = "";
std::string line;
while (std::getline(std::cin, line)) {
arg += line + '\n';
}
}
else if (arg == "-v" || arg == "--version") {
arg = "version()";
}
else if (arg == "-h" || arg == "--help") {
arg = "help(-1)";
}
else if (arg == "-i" || arg == "--interactive") {
mode = eInteractive;
}
else if (arg.find('-') == 0) {
std::cout << "unrecognised argument " << arg << std::endl;
return EXIT_FAILURE;
}
else {
mode = eFile;
}
chaiscript::Boxed_Value val;
try {
switch (mode) {
case eInteractive: interactive(chai); break;
case eCommand: val = chai.eval(arg); break;
case eFile: {
begin = clock();
val = chai.eval_file(arg);
end = clock();
double elapsed_secs1 = double(end - begin) / CLOCKS_PER_SEC;
printf("**C++::time= %.10f\n", elapsed_secs);
printf("**ChaiScript::time= %.10f\n", elapsed_secs1);
break;
}
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print();
std::cout << std::endl;
return EXIT_FAILURE;
}
catch (std::exception &e) {
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

View File

@ -1,10 +1,10 @@
var i = 0 var i = 0
if (i == 0) { if (i == 0) {
print("i is 0") print("i is 0")
} }
else if (i == 1) { else if (i == 1) {
print("i is 1") print("i is 1")
} }
else { else {
print("i is not 0 or 1") print("i is not 0 or 1")
} }

View File

@ -1,135 +0,0 @@
#include <chaiscript/chaiscript.hpp>
class BaseClass
{
public:
BaseClass()
{
}
BaseClass(const BaseClass &) = default;
virtual ~BaseClass() {}
virtual std::string doSomething(float, double) const = 0;
void setValue(const std::string &t_val) {
if (validateValue(t_val))
{
m_value = t_val;
}
}
std::string getValue() const {
return m_value;
}
protected:
virtual bool validateValue(const std::string &t_val) = 0;
private:
std::string m_value;
};
class ChaiScriptDerived : public BaseClass
{
public:
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs)
{
// using the range-checked .at() methods to give us an exception
// instead of a crash if the user passed in too-few params
tie(t_funcs.at(0), m_doSomethingImpl);
tie(t_funcs.at(1), m_validateValueImpl);
}
std::string doSomething(float f, double d) const override
{
assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d);
}
protected:
bool validateValue(const std::string &t_val) override
{
assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val);
}
private:
template<typename Param>
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param)
{
t_param = chaiscript::boxed_cast<Param>(t_func);
}
std::function<std::string (const ChaiScriptDerived&, float, double)> m_doSomethingImpl;
std::function<bool (ChaiScriptDerived&, const std::string &t_val)> m_validateValueImpl;
};
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
chai.add(chaiscript::constructor<ChaiScriptDerived (const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>());
chai.add(chaiscript::user_type<BaseClass>(), "BaseClass");
chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived");
std::string script = R""(
def MakeDerived() {
return ChaiScriptDerived(
// create a dynamically created array and pass it in to the constructor
[
fun(this, f, d) {
// see here that we are calling back into the 'this' pointer
return "${this.getValue()}${f * d}";
},
fun(this, new_val) {
if (new_val.size() < 5) {
true;
} else {
print("String ${new_val} is too long");
false;
}
}
]
);
}
var myderived := MakeDerived(); // avoid a copy by using reference assignment :=
)"";
chai.eval(script);
BaseClass &myderived = chai.eval<ChaiScriptDerived&>("myderived");
// at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases
// it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors
// assigned in the MakeDerived() factory function
//
// Notice that our validateValue() function has a requirement that the new string be < 5 characters long
myderived.setValue("1234");
assert(myderived.getValue() == "1234");
// chaiscript defined function will print out an error message and refuse to allow the setting
myderived.setValue("12345");
assert(myderived.getValue() == "1234");
chai.eval("myderived.setValue(\"new\")"); // set the value via chaiscript
assert(myderived.getValue() == "new");
// call the other derived method via chaiscript and return the value to c++ land:
std::string retval = chai.eval<std::string>("myderived.doSomething(2,4.3)");
assert(retval == "new8.6");
// The whole process is fully orthogonal
}

View File

@ -1,20 +1,20 @@
for (var i = 0; i < 10; ++i) { for (var i = 0; i < 10; ++i) {
print("i: " + i.to_string()) print("i: " + i.to_string())
if (i == 5) { if (i == 5) {
break break
} }
} }
var j = 0 var j = 0
while (true) { while (true) {
while (true) { while (true) {
++j; ++j;
if (j == 5) { if (j == 5) {
break break
} }
} }
break break
} }
print("j: " + j.to_string()) print("j: " + j.to_string())

View File

@ -1,13 +1,13 @@
#include <iostream> #include <iostream>
#include <chaiscript/chaiscript.hpp> #include "chaiscript/chaiscript.hpp"
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/readline.h> #include <readline/readline.h>
#include <readline/history.h> #include <readline/history.h>
#endif #endif
using namespace chaiscript;
std::string get_next_command() { std::string get_next_command() {
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
@ -23,21 +23,26 @@ std::string get_next_command() {
#endif #endif
} }
void function(void) void fuction(void)
{ {
// do nothing // do nothing
} }
class test class test
{ {
chaiscript::ChaiScript chai; ChaiScript chai;
chaiscript::ChaiScript::State backupState = chai.get_state(); ChaiScript::State backupState;
public: public:
test()
{
backupState = chai.get_state();
}
~test(){}
void ResetState() void ResetState()
{ {
chai.set_state(backupState); chai.set_state(backupState);
chai.add(chaiscript::fun(&function),"Whatever()"); chai.add(fun(&fuction),"Whatever()");
} }
void RunFile(std::string sFile) void RunFile(std::string sFile)
@ -46,7 +51,7 @@ class test
chaiscript::Boxed_Value val = chai.eval_file(sFile); chaiscript::Boxed_Value val = chai.eval_file(sFile);
} }
catch (std::exception &e) { catch (std::exception &e) {
std::cout << e.what() << '\n'; std::cout << e.what() << std::endl;
} }
} }
@ -62,12 +67,12 @@ int main(int /*argc*/, char * /*argv*/[]) {
std::string command = ""; std::string command = "";
// //
// this loop increases memory usage, if RunFile is not called (just hitting enter) // this loop increases memoryusage, if RunFile is not called (just hittin enter)
// as soon RunFile gets called, memory will be freed. // as soon RunFile gets called, memory will be freed.
// //
// scenario1 - RunFile gets called every Loop: memory usage does not change // scenario1 - RunFile gets called every Loop: memoryusage does not change
// scenario2 - RunFile gets never called (just hitting enter): memory usage increases every loop // scenario2 - RunFile gets never called (just hitting enter): memoryusage increases every loop
// scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as // scenario3 - RunFile gets in changing intervals: memoryusage goes up and down, but never as
// low as in case 1 scenario3 : // low as in case 1 scenario3 :
while(command != "quit") while(command != "quit")

View File

@ -2,7 +2,7 @@ var x = -(1 + 2 - 3 * 4 / 2)
print("Answer: " + x.to_string()) print("Answer: " + x.to_string())
if (x >= 2 && x <= 4) { if (x >= 2 && x <= 4) {
print("x is between 2 and 4") print("x is between 2 and 4")
} }

View File

@ -6,10 +6,10 @@
*/ */
var x = 4 var x = 4
def do_it() { def do_it() {
var x = 1 var x = 1
print(x) print(x)
var y = fun(x) { x + 1 } var y = fun(x) { x + 1 }
print(y(9)) print(y(9))
} }
do_it() do_it()
print(x) print(x)

View File

@ -1,33 +0,0 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp>
int main( int /*argc*/ , char * /*argv*/[] )
{
chaiscript::ChaiScript ch;
try
{
static const char script[ ] =
R""(
class Rectangle
{
def Rectangle() { }
}
var rect = Rectangle( );
)"";
ch.eval( script );
}
catch ( const std::exception &e )
{
printf( " >>> Exception thrown: %s \n" , e.what( ) );
}
return 1;
}

View File

@ -11,6 +11,6 @@ var size = vec.size()
print("Vector Size: " + size.to_string()); print("Vector Size: " + size.to_string());
while (i < size) { while (i < size) {
print(i.to_string() + ": " + to_string(vec[i])) print(i.to_string() + ": " + to_string(vec[i]))
i = i + 1 i = i + 1
} }

View File

@ -1,5 +1,5 @@
var i = 0 var i = 0
while (i < 10) { while (i < 10) {
print("i: " + i.to_string()) print("i: " + i.to_string())
i = i + 1 i = i + 1
} }

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