Compare commits

..

No commits in common. "develop" and "v5.8.5" have entirely different histories.

312 changed files with 24738 additions and 32398 deletions

View File

@ -1,33 +0,0 @@
# clang-format: 11
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveBitFields: false
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AlwaysBreakTemplateDeclarations: true
BasedOnStyle: WebKit
BinPackArguments: true
BinPackParameters: true
BreakBeforeBraces: Attach
ColumnLimit: 0
Cpp11BracedListStyle: true
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: false
NamespaceIndentation: All
PenaltyBreakBeforeFirstCallParameter: 200
PenaltyBreakComment: 5
PenaltyBreakFirstLessLess: 50
PenaltyExcessCharacter: 4
PointerAlignment: Right
SortIncludes: true
SpaceAfterTemplateKeyword: false
SpaceBeforeCpp11BracedList: false
SpaceInEmptyBlock: false
Standard: Latest
TabWidth: 2
UseTab: Never

View File

@ -1,12 +1,12 @@
compilers: compilers:
- name: "clang" - name: "clang"
version: "3.6" version: "3.5"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true collect_performance_results: true
- name: "clang" - name: "clang"
build_tag: "LibC++" build_tag: "LibC++"
version: "3.6" version: "3.5"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "clang" - name: "clang"
@ -19,28 +19,17 @@ compilers:
version: "3.6" version: "3.6"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON
- name: "clang"
version: "3.7"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: "clang"
build_tag: "LibC++"
version: "3.7"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "gcc" - name: "gcc"
version: "4.9" version: "4.8"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: "gcc"
version: "4.9"
skip_packaging: true
build_tag: "NoThreads" 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 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 collect_performance_results: true
- name: "gcc" - name: "gcc"
version: "5" version: "4.8"
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.6"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true collect_performance_results: true

View File

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

6
.gitignore vendored
View File

@ -1,6 +0,0 @@
/buck-out/
/.buckd/
/buckaroo/
.buckconfig.local
BUCKAROO_DEPS
/build

View File

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

11
BUCK
View File

@ -1,11 +0,0 @@
prebuilt_cxx_library(
name = 'chaiscript',
header_only = True,
header_namespace = 'chaiscript',
exported_headers = subdir_glob([
('include/chaiscript', '**/*.hpp'),
]),
visibility = [
'PUBLIC',
],
)

View File

@ -1,16 +1,19 @@
cmake_minimum_required(VERSION 3.12) cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0054 NEW)
set(CMAKE_CXX_STANDARD 20) if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
set(CMAKE_CXX_STANDARD_REQUIRED ON) cmake_policy(SET CMP0054 NEW)
endif()
IF(BIICODE)
INIT_BIICODE_BLOCK()
ADD_BIICODE_TARGETS()
ELSE()
# Your regular CMakeLists configuration here
# required since cmake 3.4 at least for libc++
set(CMAKE_ENABLE_EXPORTS ON)
project(chaiscript) project(chaiscript)
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE) option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE) option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
@ -45,14 +48,12 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if(ENABLE_ADDRESS_SANITIZER) if(ENABLE_ADDRESS_SANITIZER)
add_definitions(-fsanitize=address -g) add_definitions(-fsanitize=address -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address") set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
option(BUILD_LIBFUZZ_TESTER "Build libfuzzer tool" FALSE)
endif() endif()
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE) option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER) if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -fsanitize-memory-track-origins -g) add_definitions(-fsanitize=memory -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins ") set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
endif() endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE) option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
@ -62,26 +63,27 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
endif() endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE) option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if(ENABLE_LTO)
check_ipo_supported() if (ENABLE_LTO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif() endif()
option(GPROF_OUTPUT "Generate profile data" FALSE) option(GPROF_OUTPUT "Generate profile data" FALSE)
if(GPROF_OUTPUT) if (GPROF_OUTPUT)
add_definitions(-pg) add_definitions(-pg)
set(LINKER_FLAGS "${LINKER_FLAGS} -pg") set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
endif() endif()
option(PROFILE_GENERATE "Generate profile data" FALSE) option(PROFILE_GENERATE "Generate profile data" FALSE)
if(PROFILE_GENERATE) if (PROFILE_GENERATE)
add_definitions(-fprofile-generate) add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate") set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif() endif()
option(PROFILE_USE "Use profile data" FALSE) option(PROFILE_USE "Use profile data" FALSE)
if(PROFILE_USE) if (PROFILE_USE)
add_definitions(-fprofile-use) add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use") set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif() endif()
@ -99,9 +101,9 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md") set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 7) set(CPACK_PACKAGE_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 0) set(CPACK_PACKAGE_VERSION_MINOR 8)
set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_VERSION_PATCH 5)
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")
@ -120,13 +122,12 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest) include(CTest)
include(CPack) include(CPack)
include(cmake/Catch.cmake)
if(NOT MINGW) if(NOT MINGW)
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib) find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
endif() endif()
if(UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin) find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
endif() endif()
@ -144,10 +145,22 @@ else()
set(READLINE_FLAG) set(READLINE_FLAG)
endif() endif()
if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_LESS 4.8)
set(CPP11_FLAG "-std=c++0x")
else()
set(CPP11_FLAG "-std=c++11")
endif()
else()
set(CPP11_FLAG "-std=c++11")
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 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
if(MSVC_VERSION STREQUAL "1800") if (MSVC_VERSION STREQUAL "1800")
# VS2013 doesn't have magic statics # VS2013 doesn't have magic statics
add_definitions(/w44640) add_definitions(/w44640)
else() else()
@ -155,7 +168,7 @@ if(MSVC)
add_definitions(/w34062) add_definitions(/w34062)
endif() endif()
add_definitions(/bigobj /permissive- /utf-8) add_definitions(/bigobj)
# Note on MSVC compiler flags. # Note on MSVC compiler flags.
# The code base selective disables warnings as necessary when the compiler is complaining too much # 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 # about something that is perfectly valid, or there is simply no technical way around it
@ -165,10 +178,10 @@ if(MSVC)
# how to workaround or fix the error. So I'm disabling it globally. # how to workaround or fix the error. So I'm disabling it globally.
add_definitions(/wd4503) add_definitions(/wd4503)
else() else()
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic -Werror=return-type) add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template -Wno-undef -Wno-double-promotion) 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)
else() else()
add_definitions(-Wnoexcept) add_definitions(-Wnoexcept)
endif() endif()
@ -179,12 +192,16 @@ else()
endif() endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" FALSE) option(USE_LIBCXX "Use clang's libcxx" TRUE)
if(USE_LIBCXX) if(USE_LIBCXX)
add_definitions(-stdlib=libc++) add_definitions(-stdlib=libc++)
set(LINKER_FLAGS "${LINKER_FLAGS} -stdlib=libc++") set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++")
else()
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
endif() endif()
elseif(CMAKE_COMPILER_IS_GNUCC)
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
endif() endif()
# limitations in MinGW require us to make an optimized build # limitations in MinGW require us to make an optimized build
@ -196,7 +213,7 @@ endif()
include_directories(include) include_directories(include)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.hpp include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp) set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
@ -204,15 +221,9 @@ if(NOT MULTITHREAD_SUPPORT_ENABLED)
add_definitions(-DCHAISCRIPT_NO_THREADS) add_definitions(-DCHAISCRIPT_NO_THREADS)
endif() endif()
if(NOT DYNLOAD_ENABLED)
add_definitions(-DCHAISCRIPT_NO_DYNLOAD)
endif()
if(CMAKE_HOST_UNIX) if(CMAKE_HOST_UNIX)
if(DYNLOAD_ENABLED) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku") list(APPEND LIBS "dl")
list(APPEND LIBS "dl")
endif()
endif() endif()
if(MULTITHREAD_SUPPORT_ENABLED) if(MULTITHREAD_SUPPORT_ENABLED)
@ -238,47 +249,37 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
add_library(stdlib STATIC static_libs/chaiscript_stdlib.cpp)
add_library(parser STATIC static_libs/chaiscript_parser.cpp)
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp) add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib.cpp)
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
set(CHAISCRIPT_LIBS stdlib parser)
add_executable(chai src/main.cpp ${Chai_INCLUDES}) add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(chai ${LIBS})
add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
add_library(chaiscript INTERFACE)
target_include_directories(chaiscript INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
if(BUILD_SAMPLES) if(BUILD_SAMPLES)
add_executable(sanity_checks src/sanity_checks.cpp) add_executable(example samples/example.cpp)
target_link_libraries(sanity_checks ${LIBS}) target_link_libraries(example ${LIBS})
add_executable(test_num_exceptions samples/test_num_exceptions.cpp) add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(test_num_exceptions ${LIBS})
add_executable(memory_leak_test samples/memory_leak_test.cpp) add_executable(memory_leak_test samples/memory_leak_test.cpp)
target_link_libraries(memory_leak_test ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(memory_leak_test ${LIBS})
add_executable(inheritance samples/inheritance.cpp) add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(inheritance ${LIBS})
add_executable(factory samples/factory.cpp) add_executable(factory samples/factory.cpp)
target_link_libraries(factory ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(factory ${LIBS})
add_executable(fun_call_performance samples/fun_call_performance.cpp) add_executable(fun_call_performance samples/fun_call_performance.cpp)
target_link_libraries(fun_call_performance ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(fun_call_performance ${LIBS})
endif() endif()
if(BUILD_MODULES) if(BUILD_MODULES)
add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${LIBS})
add_library(stl_extra MODULE src/stl_extra.cpp) add_library(stl_extra MODULE src/stl_extra.cpp)
target_link_libraries(stl_extra ${LIBS}) target_link_libraries(stl_extra ${LIBS})
set(MODULES stl_extra) set(MODULES stl_extra)
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 ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
list(SORT UNIT_TESTS) list(SORT UNIT_TESTS)
@ -286,22 +287,37 @@ file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tes
list(SORT PERFORMANCE_TESTS) list(SORT PERFORMANCE_TESTS)
if(RUN_FUZZY_TESTS) if (RUN_FUZZY_TESTS)
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests") file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
execute_process( execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2017-07-20.tar.bz2 COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2015-07-16.tar.bz2
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
) )
file(GLOB FUZZY_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/MINIMIZED/*) file(GLOB FUZZY_CRASH_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/id*)
list(SORT FUZZY_TESTS) list(SORT FUZZY_CRASH_TESTS)
foreach(filename ${FUZZY_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}") message(STATUS "Adding test ${filename}")
add_test(fuzz.${filename} chai "-e" "--exception" "--any-exception" ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzz_unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${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() endforeach()
set_property(TEST ${FUZZY_EXCEPTION_TESTS} set_property(TEST ${FUZZY_EXCEPTION_TESTS}
@ -315,6 +331,37 @@ 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) }") 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) }")
@ -346,7 +393,7 @@ if(BUILD_TESTING)
list(APPEND TESTS unit.${filename}) list(APPEND TESTS unit.${filename})
endforeach() endforeach()
if(RUN_PERFORMANCE_TESTS) if (RUN_PERFORMANCE_TESTS)
foreach(filename ${PERFORMANCE_TESTS}) foreach(filename ${PERFORMANCE_TESTS})
message(STATUS "Adding performance test ${filename}") message(STATUS "Adding performance test ${filename}")
@ -371,12 +418,9 @@ if(BUILD_TESTING)
if(NOT UNIT_TEST_LIGHT) if(NOT UNIT_TEST_LIGHT)
add_executable(compiled_tests unittests/compiled_tests.cpp) add_executable(compiled_tests unittests/compiled_tests.cpp)
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(compiled_tests ${LIBS})
catch_discover_tests(compiled_tests TEST_PREFIX "compiled.") ADD_CATCH_TESTS(compiled_tests)
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp)
target_link_libraries(static_chaiscript_test ${LIBS})
add_test(NAME Static_ChaiScript_Test COMMAND static_chaiscript_test)
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp) add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
target_link_libraries(boxed_cast_test ${LIBS}) target_link_libraries(boxed_cast_test ${LIBS})
@ -387,11 +431,11 @@ if(BUILD_TESTING)
add_test(NAME Type_Info_Test COMMAND type_info_test) add_test(NAME Type_Info_Test COMMAND type_info_test)
add_executable(c_linkage_test unittests/c_linkage_test.cpp) add_executable(c_linkage_test unittests/c_linkage_test.cpp)
target_link_libraries(c_linkage_test ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(c_linkage_test ${LIBS})
add_test(NAME C_Linkage_Test COMMAND c_linkage_test) add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
add_executable(integer_literal_test unittests/integer_literal_test.cpp) add_executable(integer_literal_test unittests/integer_literal_test.cpp)
target_link_libraries(integer_literal_test ${LIBS} ${CHAISCRIPT_LIBS}) target_link_libraries(integer_literal_test ${LIBS})
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test) add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
if(MULTITHREAD_SUPPORT_ENABLED) if(MULTITHREAD_SUPPORT_ENABLED)
@ -403,8 +447,10 @@ if(BUILD_TESTING)
"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_main.cpp
unittests/multifile_test_chai.cpp unittests/multifile_test_chai.cpp
@ -413,19 +459,14 @@ if(BUILD_TESTING)
target_link_libraries(multifile_test ${LIBS}) target_link_libraries(multifile_test ${LIBS})
add_test(NAME MultiFile_Test COMMAND multifile_test) add_test(NAME MultiFile_Test COMMAND multifile_test)
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript") add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${LIBS})
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
endif() endif()
endif() endif()
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
if(BUILD_LIBFUZZ_TESTER)
add_executable(fuzzer src/libfuzzer_client.cpp src/sha3.cpp)
target_compile_options(fuzzer PRIVATE "-fsanitize=fuzzer,address")
target_link_libraries(fuzzer PRIVATE ${LIBS} "-fsanitize=fuzzer,address")
endif()
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
install(DIRECTORY include/chaiscript DESTINATION include install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp" PATTERN "*.hpp"
@ -446,6 +487,8 @@ install(DIRECTORY samples DESTINATION share/chaiscript
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 "${CMAKE_INSTALL_LIBDIR}/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)

View File

@ -1,7 +1,5 @@
BSD-3-Clause License Copyright 2009-2016 Jason Turner
Copyright 2009-2012 Jonathan Turner.
Copyright 2009-2018 Jason Turner
Copyright 2009-2012 Jonathan Turner.
All Rights Reserved. All Rights Reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -1,23 +1,16 @@
version: 6.1.x.{build} version: 5.7.2.{build}
image: os: Visual Studio 2015
- Visual Studio 2019
environment: environment:
matrix: matrix:
- VS_VERSION: "Visual Studio 16" - {}
build_script: build_script:
- cmd: >- - cmd: >-
mkdir build mkdir build
cd build cd build
cmake c:\Projects\chaiscript -G "%VS_VERSION%" -DBUILD_TESTING:BOOL=ON -DBUILD_MODULES:BOOL=ON cmake c:\Projects\chaiscript -G "Visual Studio 14"
cmake --build . --config Debug cmake --build . --config Debug
test_script: test_script:
- cmd: ctest -C Debug - 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,3 +0,0 @@
{
"name": "ChaiScript"
}

View File

@ -5,52 +5,44 @@ ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme.
* Major Version Number: API changes / breaking changes * Major Version Number: API changes / breaking changes
* Minor Version Number: New Features * Minor Version Number: New Features
* Patch Version Number: Minor changes / enhancements * Patch Version Number: Minor changes / enhancements
# Initializing ChaiScript # Initializing ChaiScript
``` ```
chaiscript::ChaiScript chai; // initializes ChaiScript, adding the standard ChaiScript types (map, string, ...) chaiscript::ChaiScript chai; // loads stdlib from loadable module on file system
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
``` ```
Note that ChaiScript cannot be used as a global / static object unless it is being compiled with `CHAISCRIPT_NO_THREADS`.
# Adding Things To The Engine # Adding Things To The Engine
## Adding a Function / Method / Member ## Adding a Function / Method / Member
### General ### General
```cpp ```
chai.add(chaiscript::fun(&function_name), "function_name"); chai.add(chaiscript::fun(&function_name), "function_name");
chai.add(chaiscript::fun(&Class::method_name), "method_name"); chai.add(chaiscript::fun(&Class::method_name), "method_name");
chai.add(chaiscript::fun(&Class::member_name), "member_name"); chai.add(chaiscript::fun(&Class::member_name), "member_name");
``` ```
### Bound Member Functions ### With Overloads
```cpp
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 #### Preferred
```cpp ```
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name"); chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
``` ```
#### Alternative #### Alternative
```cpp
chai.add(chaiscript::fun(static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
``` ```
This overload technique is also used when exposing base members using derived type 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
```cpp ```
struct Base struct Base
{ {
int data; int data;
@ -64,18 +56,18 @@ chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
### Lambda ### Lambda
```cpp ```
chai.add( chai.add(
chaiscript::fun<std::function<std::string (bool)>>( chaiscript::fun<std::string (bool)>(
[](bool type) { [](bool type) {
if (type) { return "x"; } if (type) { return "x"; }
else { return "y"; } else { return "y"; }
}), "function_name"); }), "function_name");
``` ```
### Constructors ### Constructors
```cpp ```
chai.add(chaiscript::constructor<MyType ()>(), "MyType"); chai.add(chaiscript::constructor<MyType ()>(), "MyType");
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType"); chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
``` ```
@ -84,56 +76,13 @@ chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc. It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
```cpp ```
chai.add(chaiscript::user_type<MyClass>(), "MyClass"); chai.add(chaiscript::user_type<MyClass>(), "MyClass");
``` ```
## Adding Type Conversions ## Adding Type Conversions
User-defined type conversions are possible, defined in either script or in C++. User defined type conversions are possible, defined in either script or in C++.
### ChaiScript Defined Conversions
Function objects (including lambdas) can be used to add type conversions
from inside of ChaiScript:
```
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
```
### C++ Defined Conversions
Invoking a C++ type conversion possible with `static_cast`
```cpp
chai.add(chaiscript::type_conversion<T, bool>());
```
Calling a user-defined type conversion that takes a lambda
```cpp
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 ChaiScript about the relationship.
```cpp
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.
```cpp
chai.add(chaiscript::base_class<Base, Derived>());
chai.add(chaiscript::base_class<Derived, MoreDerived>());
chai.add(chaiscript::base_class<Base, MoreDerived>());
```
### Helpers
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition: A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
@ -148,14 +97,13 @@ chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
``` ```
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>` This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
## Adding Objects ## Adding Objects
``` ```
chai.add(chaiscript::var(somevar), "somevar"); // copied in chai.add(chaiscript::var(somevar), "somevar"); // copied in
chai.add(chaiscript::var(std::ref(somevar)), "somevar"); // by reference, shared between C++ and chai chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared between C++ and chai
auto shareddouble = std::make_shared<double>(4.3); auto shareddouble = std::make_shared<double>(4.3);
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
@ -163,29 +111,10 @@ chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global cons
chai.add_global(chaiscript::var(somevar), "somevar"); // global 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 chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
``` ```
## Adding Namespaces
Namespaces will not be populated until `import` is called.
This saves memory and computing costs if a namespace is not imported into every ChaiScript instance.
```cpp
chai.register_namespace([](chaiscript::Namespace& math) {
math["pi"] = chaiscript::const_var(3.14159);
math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); },
"math");
```
Import namespace in ChaiScript
```
import("math")
print(math.pi) // prints 3.14159
```
# Using STL # Using STL
ChaiScript recognizes many types from STL, but you have to add specific instantiation yourself. ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
```cpp ```
typedef std::vector<std::pair<int, std::string>> data_list; typedef std::vector<std::pair<int, std::string>> data_list;
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") }; 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::vector_type<data_list>("DataList"));
@ -203,7 +132,7 @@ chai.eval(R"_(
## General ## General
```cpp ```
chai.eval("print(\"Hello World\")"); chai.eval("print(\"Hello World\")");
chai.eval(R"(print("Hello World"))"); chai.eval(R"(print("Hello World"))");
``` ```
@ -214,13 +143,13 @@ Returns values are of the type `Boxed_Value` which is meant to be opaque to the
### Prefered ### Prefered
```cpp ```
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
``` ```
### Alternative ### Alternative
```cpp ```
auto v = chai.eval("5.3 + 2.1"); auto v = chai.eval("5.3 + 2.1");
chai.boxed_cast<double>(v); // extracts double value from boxed_value and applies known conversions 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 chaiscript::boxed_cast<double>(v); // free function version, does not know about conversions
@ -228,7 +157,7 @@ chaiscript::boxed_cast<double>(v); // free function version, does not know about
### Converting Between Algebraic Types ### Converting Between Algebraic Types
```cpp ```
chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with any number type 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: // 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 static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
@ -241,7 +170,7 @@ Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you
```cpp ```cpp
// ok this is supported, you can register it with chaiscript engine // ok this is supported, you can register it with chaiscript engine
void nullify_shared_ptr(std::shared_ptr<int> &t) { void nullify_shared_ptr(std::shared_ptr<int> &t) {
t = nullptr t == nullptr
} }
``` ```
@ -258,7 +187,7 @@ int main()
## Sharing Values ## Sharing Values
```cpp ```
double &d = chai.eval("var i = 5.2; i"); // d is now a reference to i in the script 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 std::shared_ptr<double> d = chai.eval("var i = 5.2; i"); // same result but reference counted
@ -268,7 +197,7 @@ chai.eval("print(i)"); // prints 3
## Catching Eval Errors ## Catching Eval Errors
```cpp ```
try { try {
chai.eval("2.3 + \"String\""); chai.eval("2.3 + \"String\"");
} catch (const chaiscript::exception::eval_error &e) { } catch (const chaiscript::exception::eval_error &e) {
@ -278,7 +207,7 @@ try {
## Catching Errors Thrown From Script ## Catching Errors Thrown From Script
```cpp ```
try { try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>()); chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double e) { } catch (const double e) {
@ -286,26 +215,26 @@ try {
} catch (float) { } catch (float) {
} catch (const std::string &) { } catch (const std::string &) {
} catch (const std::exception &e) { } catch (const std::exception &e) {
// This is the one that will be called in the specific throw() above // This is the one what will be called in the specific throw() above
} }
``` ```
## Sharing Functions ## Sharing Functions
```cpp ```
auto p = chai.eval<std::function<std::string (double)>>("to_string"); auto p = chai.eval<std::function<std::string (double)>>("to_string");
p(5); // calls chaiscript's 'to_string' function, returning std::string("5") p(5); // calls chaiscript's 'to_string' function, returning std::string("5")
``` ```
Note: backtick treats operators as normal functions Note: backtick treats operators as normal functions
```cpp ```
auto p = chai.eval<std::function<int (int, int)>>("`+`"); auto p = chai.eval<std::function<int (int, int)>>(`+`);
p(5, 6); // calls chaiscript's '+' function, returning 11 p(5, 6); // calls chaiscript's '+' function, returning 11
``` ```
```cpp ```
auto p = chai.eval<std::function<std::string (int, double)>>("fun(x,y) { to_string(x) + to_string(y); }"); 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++ p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
``` ```
@ -331,82 +260,13 @@ if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hi
GLOBAL g3; // all upper case version also accepted GLOBAL g3; // all upper case version also accepted
``` ```
## Looping ## Built in Types
```
// c-style for loops
for (var i = 0; i < 100; ++i) { print(i); }
```
```
// while
while (some_condition()) { /* do something */ }
```
```
// ranged for
for (i : [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) { }
```
## Switch Statements
``` chaiscript
var myvalue = 2
switch (myvalue) {
case (1) {
print("My Value is 1");
break;
}
case (2) {
print("My Value is 2");
break;
}
default {
print("My Value is something else.";
}
}
```
## Built-in Types
There are a number of built-in types that are part of ChaiScript.
### Vectors and Maps
``` ```
var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
var m = ["a":1, "b":2]; // map of string:value pairs var m = ["a":1, "b":2]; // map of string:value pairs
// Add a value to the vector by value.
v.push_back(123);
// Add an object to the vector by reference.
v.push_back_ref(m);
``` ```
### Numbers
Floating point values default to `double` type and integers default to `int` type. All C++ suffixes 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 such as `f`, `ll`, `u` as well as scientific notation are supported
@ -427,7 +287,7 @@ on your platform.
## Functions ## Functions
Note that any type of ChaiScript function can be passed freely to C++ and automatically Note that any type of ChaiScript function can be passed freely to C++ and automatically
converted into a `std::function` object. converted into an `std::function` object.
### General ### General
@ -526,20 +386,6 @@ o.f = fun(y) { print(this.x + y); }
o.f(10); // prints 13 o.f(10); // prints 13
``` ```
## Namespaces
Namespaces in ChaiScript are Dynamic Objects with global scope
```
namespace("math") // create a new namespace
math.square = fun(x) { x * x } // add a function to the "math" namespace
math.sum_squares = fun(x, y) { math.square(x) + math.square(y) }
print(math.square(4)) // prints 16
print(math.sum_squares(2, 5)) // prints 29
```
### Option Explicit ### Option Explicit
If you want to disable dynamic parameter definitions, you can `set_explicit`. If you want to disable dynamic parameter definitions, you can `set_explicit`.
@ -572,15 +418,8 @@ the contained function.
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins. If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
## Context
* `__LINE__` Current file line number # Built In Functions
* `__FILE__` Full path of current file
* `__CLASS__` Name of current class
* `__FUNC__` Name of current function
# Built-in Functions
## Evaluation ## Evaluation
@ -593,10 +432,4 @@ use("filename") // evals file exactly once and returns value of last statement
Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor
## JSON
* `from_json` converts a JSON string into its strongly typed (map, vector, int, double, string) representations
* `to_json` converts a ChaiScript object (either a `Object` or one of map, vector, int, double, string) tree into its JSON string representation
## Extras
ChaiScript itself does not provide a link to the math functions defined in `<cmath>`. You can either add them yourself, or use the [ChaiScript_Extras](https://github.com/ChaiScript/ChaiScript_Extras) helper library. (Which also provides some additional string functions.)

View File

@ -1,175 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
Catch
-----
This module defines a function to help use the Catch test framework.
The :command:`catch_discover_tests` discovers tests by asking the compiled test
executable to enumerate its tests. This does not require CMake to be re-run
when tests change. However, it may not work in a cross-compiling environment,
and setting test properties is less convenient.
This command is intended to replace use of :command:`add_test` to register
tests, and will create a separate CTest test for each Catch test case. Note
that this is in some cases less efficient, as common set-up and tear-down logic
cannot be shared by multiple test cases executing in the same instance.
However, it provides more fine-grained pass/fail information to CTest, which is
usually considered as more beneficial. By default, the CTest test name is the
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
.. command:: catch_discover_tests
Automatically add tests with CTest by querying the compiled test executable
for available tests::
catch_discover_tests(target
[TEST_SPEC arg1...]
[EXTRA_ARGS arg1...]
[WORKING_DIRECTORY dir]
[TEST_PREFIX prefix]
[TEST_SUFFIX suffix]
[PROPERTIES name1 value1...]
[TEST_LIST var]
)
``catch_discover_tests`` sets up a post-build command on the test executable
that generates the list of tests by parsing the output from running the test
with the ``--list-test-names-only`` argument. This ensures that the full
list of tests is obtained. Since test discovery occurs at build time, it is
not necessary to re-run CMake when the list of tests changes.
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
in order to function in a cross-compiling environment.
Additionally, setting properties on tests is somewhat less convenient, since
the tests are not available at CMake time. Additional test properties may be
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
more fine-grained test control is needed, custom content may be provided
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
directory property. The set of discovered tests is made accessible to such a
script via the ``<target>_TESTS`` variable.
The options are:
``target``
Specifies the Catch executable, which must be a known CMake executable
target. CMake will substitute the location of the built executable when
running the test.
``TEST_SPEC arg1...``
Specifies test cases, wildcarded test cases, tags and tag expressions to
pass to the Catch executable with the ``--list-test-names-only`` argument.
``EXTRA_ARGS arg1...``
Any extra arguments to pass on the command line to each test case.
``WORKING_DIRECTORY dir``
Specifies the directory in which to run the discovered test cases. If this
option is not provided, the current binary directory is used.
``TEST_PREFIX prefix``
Specifies a ``prefix`` to be prepended to the name of each discovered test
case. This can be useful when the same test executable is being used in
multiple calls to ``catch_discover_tests()`` but with different
``TEST_SPEC`` or ``EXTRA_ARGS``.
``TEST_SUFFIX suffix``
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
be specified.
``PROPERTIES name1 value1...``
Specifies additional properties to be set on all tests discovered by this
invocation of ``catch_discover_tests``.
``TEST_LIST var``
Make the list of tests available in the variable ``var``, rather than the
default ``<target>_TESTS``. This can be useful when the same test
executable is being used in multiple calls to ``catch_discover_tests()``.
Note that this variable is only available in CTest.
#]=======================================================================]
#------------------------------------------------------------------------------
function(catch_discover_tests TARGET)
cmake_parse_arguments(
""
""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
${ARGN}
)
if(NOT _WORKING_DIRECTORY)
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT _TEST_LIST)
set(_TEST_LIST ${TARGET}_TESTS)
endif()
## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
get_property(crosscompiling_emulator
TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR
)
add_custom_command(
TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${ctest_tests_file}"
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "CTEST_FILE=${ctest_tests_file}"
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
VERBATIM
)
file(WRITE "${ctest_include_file}"
"if(EXISTS \"${ctest_tests_file}\")\n"
" include(\"${ctest_tests_file}\")\n"
"else()\n"
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
"endif()\n"
)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
# Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
)
else()
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
if (NOT ${test_include_file_set})
set_property(DIRECTORY
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
)
else()
message(FATAL_ERROR
"Cannot set more than one TEST_INCLUDE_FILE"
)
endif()
endif()
endfunction()
###############################################################################
set(_CATCH_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
)

View File

@ -1,76 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
set(prefix "${TEST_PREFIX}")
set(suffix "${TEST_SUFFIX}")
set(spec ${TEST_SPEC})
set(extra_args ${TEST_EXTRA_ARGS})
set(properties ${TEST_PROPERTIES})
set(script)
set(suite)
set(tests)
function(add_command NAME)
set(_args "")
foreach(_arg ${ARGN})
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
# Run test executable to get list of available tests
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
)
endif()
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
OUTPUT_VARIABLE output
RESULT_VARIABLE result
)
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
if(${result} EQUAL 0)
message(WARNING
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
)
elseif(${result} LESS 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${result}\n"
" Output: ${output}\n"
)
endif()
string(REPLACE "\n" ";" output "${output}")
# Parse output
foreach(line ${output})
set(test ${line})
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
${test}
${extra_args}
)
add_command(set_tests_properties
"${prefix}${test}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
${properties}
)
list(APPEND tests "${prefix}${test}${suffix}")
endforeach()
# Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests
add_command(set ${TEST_LIST} ${tests})
# Write CTest script
file(WRITE "${CTEST_FILE}" "${script}")

View File

@ -1,185 +0,0 @@
#==================================================================================================#
# supported macros #
# - TEST_CASE, #
# - SCENARIO, #
# - TEST_CASE_METHOD, #
# - CATCH_TEST_CASE, #
# - CATCH_SCENARIO, #
# - CATCH_TEST_CASE_METHOD. #
# #
# Usage #
# 1. make sure this module is in the path or add this otherwise: #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# 2. make sure that you've enabled testing option for the project by the call: #
# enable_testing() #
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
# project(testing_target) #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# enable_testing() #
# #
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
# #
# file(GLOB SOURCE_FILES "*.cpp") #
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
# #
# include(ParseAndAddCatchTests) #
# ParseAndAddCatchTests(${PROJECT_NAME}) #
# #
# The following variables affect the behavior of the script: #
# #
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
# -- enables debug messages #
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
# -- adds fixture class name to the test name #
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
# -- adds cmake target name to the test name #
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
# #
#==================================================================================================#
cmake_minimum_required(VERSION 2.8.8)
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
function(PrintDebugMessage)
if(PARSE_CATCH_TESTS_VERBOSE)
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
endif()
endfunction()
# This removes the contents between
# - block comments (i.e. /* ... */)
# - full line comments (i.e. // ... )
# contents have been read into '${CppCode}'.
# !keep partial line comments
function(RemoveComments CppCode)
string(ASCII 2 CMakeBeginBlockComment)
string(ASCII 3 CMakeEndBlockComment)
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
endfunction()
# Worker function
function(ParseFile SourceFile TestTarget)
# According to CMake docs EXISTS behavior is well-defined only for full paths.
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
if(NOT EXISTS ${SourceFile})
message(WARNING "Cannot find source file: ${SourceFile}")
return()
endif()
PrintDebugMessage("parsing ${SourceFile}")
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
# Remove block and fullline comments
RemoveComments(Contents)
# Find definition of test names
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
)
endif()
foreach(TestName ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
# Get test type and fixture if applicable
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
string(REPLACE "${TestType}(" "" TestFixture "${TestTypeAndFixture}")
# Get string parts of test definition
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
# Strip wrapping quotation marks
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
# Validate that a test name and tags have been provided
list(LENGTH TestStrings TestStringsLength)
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
endif()
# Assign name and tags
list(GET TestStrings 0 Name)
if("${TestType}" STREQUAL "SCENARIO")
set(Name "Scenario: ${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
set(CTestName "${TestFixture}:${Name}")
else()
set(CTestName "${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
set(CTestName "${TestTarget}:${CTestName}")
endif()
# add target to labels to enable running all tests added from this target
set(Labels ${TestTarget})
if(TestStringsLength EQUAL 2)
list(GET TestStrings 1 Tags)
string(TOLOWER "${Tags}" Tags)
# remove target from labels if the test is hidden
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
list(REMOVE_ITEM Labels ${TestTarget})
endif()
string(REPLACE "]" ";" Tags "${Tags}")
string(REPLACE "[" "" Tags "${Tags}")
endif()
list(APPEND Labels ${Tags})
list(FIND Labels "!hide" IndexOfHideLabel)
set(HiddenTagFound OFF)
foreach(label ${Labels})
string(REGEX MATCH "^!hide|^\\." result ${label})
if(result)
set(HiddenTagFound ON)
break()
endif(result)
endforeach(label)
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound})
PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
else()
PrintDebugMessage("Adding test \"${CTestName}\"")
if(Labels)
PrintDebugMessage("Setting labels to ${Labels}")
endif()
# Add the test and set its properties
add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Labels}")
endif()
endforeach()
endfunction()
# entry point
function(ParseAndAddCatchTests TestTarget)
PrintDebugMessage("Started parsing ${TestTarget}")
get_target_property(SourceFiles ${TestTarget} SOURCES)
PrintDebugMessage("Found the following sources: ${SourceFiles}")
foreach(SourceFile ${SourceFiles})
ParseFile(${SourceFile} ${TestTarget})
endforeach()
PrintDebugMessage("Finished parsing ${TestTarget}")
endfunction()

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

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

View File

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

View File

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

View File

@ -1 +0,0 @@
vim support can be found at https://github.com/ChaiScript/vim-chaiscript

7
contrib/vim/README.txt Normal file
View File

@ -0,0 +1,7 @@
Install ftdetect, indent and syntax subdirectories to:
~/.vim/
See the vim documentation on this:
http://vimdoc.sourceforge.net/htmldoc/syntax.html#mysyntaxfile

View File

@ -0,0 +1,2 @@
au BufRead,BufNewFile *.chai set filetype=chaiscript

View File

@ -0,0 +1,50 @@
" Vim indent file
" Language: ChaiScript
" Maintainer: Jason Turner <lefticus 'at' gmail com>
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
finish
endif
let b:did_indent = 1
setlocal indentexpr=GetChaiScriptIndent()
setlocal autoindent
" Only define the function once.
if exists("*GetChaiScriptIndent")
finish
endif
function! GetChaiScriptIndent()
" Find a non-blank line above the current line.
let lnum = prevnonblank(v:lnum - 1)
" Hit the start of the file, use zero indent.
if lnum == 0
return 0
endif
" Add a 'shiftwidth' after lines that start a block:
" lines containing a {
let ind = indent(lnum)
let flag = 0
let prevline = getline(lnum)
if prevline =~ '^.*{.*'
let ind = ind + &shiftwidth
let flag = 1
endif
" Subtract a 'shiftwidth' after lines containing a { followed by a }
" to keep it balanced
if flag == 1 && prevline =~ '.*{.*}.*'
let ind = ind - &shiftwidth
endif
" Subtract a 'shiftwidth' on lines ending with }
if getline(v:lnum) =~ '^\s*\%(}\)'
let ind = ind - &shiftwidth
endif
return ind
endfunction

View File

@ -0,0 +1,99 @@
" Vim syntax file
" Language: ChaiScript
" Maintainer: Jason Turner <lefticus 'at' gmail com>
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
finish
end
let s:cpo_save = &cpo
set cpo&vim
syn case match
" syncing method
syn sync fromstart
" Strings
syn region chaiscriptString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=chaiscriptSpecial,chaiscriptEval,@Spell
" Escape characters
syn match chaiscriptSpecial contained "\\[\\abfnrtv\'\"]\|\\\d\{,3}"
" String evals
syn region chaiscriptEval contained start="${" end="}"
" integer number
syn match chaiscriptNumber "\<\d\+\>"
" floating point number, with dot, optional exponent
syn match chaiscriptFloat "\<\d\+\.\d*\%(e[-+]\=\d\+\)\=\>"
" floating point number, starting with a dot, optional exponent
syn match chaiscriptFloat "\.\d\+\%(e[-+]\=\d\+\)\=\>"
" floating point number, without dot, with exponent
syn match chaiscriptFloat "\<\d\+e[-+]\=\d\+\>"
" Hex strings
syn match chaiscriptNumber "\<0x\x\+\>"
" Binary strings
syn match chaiscriptNumber "\<0b[01]\+\>"
" Various language features
syn keyword chaiscriptCond if else
syn keyword chaiscriptRepeat while for do
syn keyword chaiscriptStatement break continue return switch case default
syn keyword chaiscriptExceptions try catch throw
"Keyword
syn keyword chaiscriptKeyword def true false attr
"Built in types
syn keyword chaiscriptType fun var auto
"Built in funcs, keep it simple
syn keyword chaiscriptFunc eval throw
"Let's treat all backtick operator function lookups as built in too
syn region chaiscriptFunc matchgroup=chaiscriptFunc start="`" end="`"
" Account for the "[1..10]" syntax, treating it as an operator
" Intentionally leaving out all of the normal, well known operators
syn match chaiscriptOperator "\.\."
" Guard seperator as an operator
syn match chaiscriptOperator ":"
" Comments
syn match chaiscriptComment "//.*$" contains=@Spell
syn region chaiscriptComment matchgroup=chaiscriptComment start="/\*" end="\*/" contains=@Spell
hi def link chaiscriptExceptions Exception
hi def link chaiscriptKeyword Keyword
hi def link chaiscriptStatement Statement
hi def link chaiscriptRepeat Repeat
hi def link chaiscriptString String
hi def link chaiscriptNumber Number
hi def link chaiscriptFloat Float
hi def link chaiscriptOperator Operator
hi def link chaiscriptConstant Constant
hi def link chaiscriptCond Conditional
hi def link chaiscriptFunction Function
hi def link chaiscriptComment Comment
hi def link chaiscriptTodo Todo
hi def link chaiscriptError Error
hi def link chaiscriptSpecial SpecialChar
hi def link chaiscriptFunc Identifier
hi def link chaiscriptType Type
hi def link chaiscriptEval Special
let b:current_syntax = "chaiscript"
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: nowrap sw=2 sts=2 ts=8 noet

View File

@ -1,29 +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-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HPP_ #ifndef CHAISCRIPT_HPP_
#define CHAISCRIPT_HPP_ #define CHAISCRIPT_HPP_
/// @mainpage /// @mainpage
/// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides /// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions. /// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
/// ///
/// The parts of the ChaiScript API that the average user will be concerned with are contained in the /// The parts of the ChaiScript API that the average user will be concerned with are contained in the
/// chaiscript namespace and the chaiscript::ChaiScript class. /// chaiscript namespace and the chaiscript::ChaiScript class.
/// ///
/// The end user parts of the API are extremely simple both in size and ease of use. /// The end user parts of the API are extremely simple both in size and ease of use.
/// ///
/// Currently, all source control and project management aspects of ChaiScript occur on /// Currently, all source control and project management aspects of ChaiScript occur on [github](http://www.github.com/ChaiScript/ChaiScript").
/// [github](http://www.github.com/ChaiScript/ChaiScript").
/// ///
/// ------------------------------------------------------------ /// ------------------------------------------------------------
/// ///
/// @sa chaiscript /// @sa chaiscript
/// @sa chaiscript::ChaiScript /// @sa chaiscript::ChaiScript
/// @sa ChaiScript_Language for Built in Functions /// @sa ChaiScript_Language for Built in Functions
@ -49,16 +47,16 @@
/// - @ref functionobjects /// - @ref functionobjects
/// - @ref threading /// - @ref threading
/// - @ref exceptions /// - @ref exceptions
/// ///
/// ///
/// @subsection basics Basics /// @subsection basics Basics
/// ///
/// Basic simple example: /// Basic simple example:
/// ///
/// ~~~~~~~{.cpp} /// ~~~~~~~{.cpp}
/// //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;
@ -67,10 +65,10 @@
/// int main() /// int main()
/// { /// {
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::fun(&function), "function"); /// chai.add(&function, "function");
/// ///
/// double d = chai.eval<double>("function(3, 4.75);"); /// double d = chai.eval<double>("function(3, 4.75);");
/// } /// }
/// ~~~~~~~ /// ~~~~~~~
/// ///
/// ------------------------------------------------------ /// ------------------------------------------------------
@ -79,14 +77,14 @@
/// ///
/// ChaiScript is a header only library with only one dependency: The /// ChaiScript is a header only library with only one dependency: The
/// operating system provided dynamic library loader, which has to be specified on some platforms. /// operating system provided dynamic library loader, which has to be specified on some platforms.
/// ///
/// @subsubsection compilinggcc Compiling with GCC /// @subsubsection compilinggcc Compiling with GCC
/// ///
/// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link /// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link
/// the dynamic loader. For example: /// the dynamic loader. For example:
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl /// gcc main.cpp -I/path/to/chaiscript/headers -ldl
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// Alternatively, you may compile without threading support. /// Alternatively, you may compile without threading support.
@ -109,11 +107,11 @@
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai("print(@"hello world@")"); /// chai("print(@"hello world@")");
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// @sa chaiscript::ChaiScript::operator()(const std::string &) /// @sa chaiscript::ChaiScript::operator()(const std::string &)
/// ///
/// @subsubsection evalmethod Method 'eval' /// @subsubsection evalmethod Method 'eval'
/// ///
/// The eval method is somewhat more verbose and can be used to get type safely return values /// The eval method is somewhat more verbose and can be used to get type safely return values
/// from the script. /// from the script.
/// ///
@ -127,15 +125,15 @@
/// @sa chaiscript::ChaiScript::eval /// @sa chaiscript::ChaiScript::eval
/// ///
/// @subsubsection evalfilemethod Method 'eval_file' /// @subsubsection evalfilemethod Method 'eval_file'
/// ///
/// The 'eval_file' method loads a file from disk and executes the script in it /// The 'eval_file' method loads a file from disk and executes the script in it
/// ///
/// ~~~~~~~~{.cpp} /// ~~~~~~~~{.cpp}
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.eval_file("myfile.chai"); /// chai.eval_file("myfile.chai");
/// std::string result = chai.eval_file<std::string>("myfile.chai") // extract the last value returned from the file /// std::string result = chai.eval_file<std::string>("myfile.chai") // extract the last value returned from the file
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// @sa chaiscript::ChaiScript::eval_file /// @sa chaiscript::ChaiScript::eval_file
/// ///
/// -------------------------------------------------- /// --------------------------------------------------
@ -147,10 +145,10 @@
/// @subsubsection adding_objects Adding Objects /// @subsubsection adding_objects Adding Objects
/// ///
/// Named objects can be created with the chaiscript::var function. Note: adding a object /// Named objects can be created with the chaiscript::var function. Note: adding a object
/// adds it to the current thread scope, not to a global scope. If you have multiple /// adds it to the current thread scope, not to a global scope. If you have multiple
/// threads that need to access the same variables you will need to add them /// threads that need to access the same variables you will need to add them
/// separately for each thread, from the thread itself. /// separately for each thread, from the thread itself.
/// ///
/// ~~~~~~~~~{.cpp} /// ~~~~~~~~~{.cpp}
/// using namespace chaiscript; /// using namespace chaiscript;
/// ChaiScript chai; /// ChaiScript chai;
@ -165,23 +163,23 @@
/// chai.add(const_var(i), "i"); /// chai.add(const_var(i), "i");
/// chai("i = 5"); // exception throw, cannot assign const var /// chai("i = 5"); // exception throw, cannot assign const var
/// ~~~~~~~~~ /// ~~~~~~~~~
/// ///
/// Named variables can only be accessed from the context they are created in. /// Named variables can only be accessed from the context they are created in.
/// If you want a global variable, it must be const, and created with the /// If you want a global variable, it must be const, and created with the
/// chaiscript::ChaiScript::add_global_const function. /// chaiscript::ChaiScript::add_global_const function.
/// ///
/// ~~~~~~~~~{.cpp} /// ~~~~~~~~~{.cpp}
/// chai.add_global_const(const_var(i), "i"); /// chai.add_global_const(const_var(i), "i");
/// chai("def somefun() { print(i); }; somefun();"); /// chai("def somefun() { print(i); }; somefun();");
/// ~~~~~~~~~ /// ~~~~~~~~~
/// ///
/// @subsubsection adding_functions Adding Functions /// @subsubsection adding_functions Adding Functions
/// ///
/// Functions, methods and members are all added using the same function: chaiscript::fun. /// Functions, methods and members are all added using the same function: chaiscript::fun.
/// ///
/// ~~~~~~~~~{.cpp} /// ~~~~~~~~~{.cpp}
/// using namespace chaiscript; /// using namespace chaiscript;
/// ///
/// class MyClass { /// class MyClass {
/// public: /// public:
/// int memberdata; /// int memberdata;
@ -191,7 +189,7 @@
/// void overloadedmethod(); /// void overloadedmethod();
/// void overloadedmethod(const std::string &); /// void overloadedmethod(const std::string &);
/// }; /// };
/// ///
/// ChaiScript chai; /// ChaiScript chai;
/// chai.add(fun(&MyClass::memberdata), "memberdata"); /// chai.add(fun(&MyClass::memberdata), "memberdata");
/// chai.add(fun(&MyClass::method), "method"); /// chai.add(fun(&MyClass::method), "method");
@ -206,7 +204,7 @@
/// ~~~~~~~~~ /// ~~~~~~~~~
/// ///
/// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function. /// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function.
/// ///
/// ~~~~~~~~~{.cpp} /// ~~~~~~~~~{.cpp}
/// MyClass obj; /// MyClass obj;
/// chai.add(fun(&MyClass::method, &obj), "method"); /// chai.add(fun(&MyClass::method, &obj), "method");
@ -218,7 +216,7 @@
/// @subsubsection addingtypeinfo Adding Type Info /// @subsubsection addingtypeinfo Adding Type Info
/// ///
/// ChaiScript will automatically support any type implicitly provided to it in the form /// ChaiScript will automatically support any type implicitly provided to it in the form
/// of objects and function parameters / return types. However, it can be nice to let ChaiScript /// of objects and function parameters / return types. However, it can be nice to let ChaiScript
/// know more details about the types you are giving it. For instance, the "clone" functionality /// know more details about the types you are giving it. For instance, the "clone" functionality
/// cannot work unless there is a copy constructor registered and the name of the type is known /// cannot work unless there is a copy constructor registered and the name of the type is known
/// (so that ChaiScript can look up the copy constructor). /// (so that ChaiScript can look up the copy constructor).
@ -230,23 +228,23 @@
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// @subsubsection adding_modules Adding Modules /// @subsubsection adding_modules Adding Modules
/// ///
/// Modules are holders for collections of ChaiScript registrations. /// Modules are holders for collections of ChaiScript registrations.
/// ///
/// ~~~~~~~~{.cpp} /// ~~~~~~~~{.cpp}
/// ModulePtr module = get_sum_module(); /// ModulePtr module = get_sum_module();
/// chai.add(module); /// chai.add(module);
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// @sa chaiscript::Module /// @sa chaiscript::Module
/// ///
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// @subsection operatoroverloading Operator Overloading /// @subsection operatoroverloading Operator Overloading
/// ///
/// Operators are just like any other function in ChaiScript, to overload an operator, simply register it. /// Operators are just like any other function in ChaiScript, to overload an operator, simply register it.
/// ///
/// ~~~~~~~~{.cpp} /// ~~~~~~~~{.cpp}
/// class MyClass { /// class MyClass {
/// MyClass operator+(const MyClass &) const; /// MyClass operator+(const MyClass &) const;
/// }; /// };
@ -268,7 +266,7 @@
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// @subsection add_class Class Helper Utility /// @subsection add_class Class Helper Utility
/// ///
/// Much of the work of adding new classes to ChaiScript can be reduced with the help /// Much of the work of adding new classes to ChaiScript can be reduced with the help
/// of the add_class helper utility. /// of the add_class helper utility.
/// ///
@ -293,8 +291,8 @@
/// constructor<Test(const Test &)>() }, /// constructor<Test(const Test &)>() },
/// { {fun(&Test::function), "function"}, /// { {fun(&Test::function), "function"},
/// {fun(&Test::function2), "function2"}, /// {fun(&Test::function2), "function2"},
/// {fun(&Test::function2), "function3"} /// {fun(&Test::function2), "function3"}
/// {fun(static_cast<std::string Test::*(double)>(&Test::functionOverload)), "functionOverload"} /// {fun(static_cast<std::string Test::*(double)>(&Test::functionOverload)), "functionOverload"}
/// {fun(static_cast<std::string Test::*(int)>(&Test::functionOverload)), "functionOverload"} } /// {fun(static_cast<std::string Test::*(int)>(&Test::functionOverload)), "functionOverload"} }
/// ); /// );
/// ///
@ -303,7 +301,7 @@
/// chai.add(m); /// chai.add(m);
/// } /// }
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// @sa @ref adding_modules /// @sa @ref adding_modules
/// ///
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
@ -313,8 +311,8 @@
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>, /// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically. /// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
/// ///
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference /// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference counting).
/// counting). Const may be added, but never removed. /// Const may be added, but never removed.
/// ///
/// The take away is that you can pretty much expect function calls to Just Work when you need them to. /// The take away is that you can pretty much expect function calls to Just Work when you need them to.
/// ///
@ -357,16 +355,16 @@
/// chai("fun8(i)"); /// chai("fun8(i)");
/// chai("fun9(i)"); /// chai("fun9(i)");
/// chai("fun10(i)"); /// chai("fun10(i)");
/// } /// }
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that /// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that
/// available and tested. /// available and tested.
/// ///
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// @subsection baseclasses Base Classes /// @subsection baseclasses Base Classes
/// ///
/// ChaiScript supports handling of passing a derived class object to a function expecting a base class object. /// ChaiScript supports handling of passing a derived class object to a function expecting a base class object.
/// For the process to work, the base/derived relationship must be registered with the engine. /// For the process to work, the base/derived relationship must be registered with the engine.
/// ///
@ -385,7 +383,7 @@
/// chai("myfunction(d)"); /// chai("myfunction(d)");
/// } /// }
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// ///
@ -399,7 +397,7 @@
/// { /// {
/// t_func("bob"); /// t_func("bob");
/// } /// }
/// ///
/// int main() /// int main()
/// { /// {
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
@ -411,16 +409,16 @@
/// f(); // call the ChaiScript function dump_system, from C++ /// f(); // call the ChaiScript function dump_system, from C++
/// } /// }
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// ///
/// @subsection threading Threading /// @subsection threading Threading
/// ///
/// Thread safety is automatically handled within the ChaiScript system. Objects can be added /// Thread safety is automatically handled within the ChaiScript system. Objects can be added
/// and scripts executed from multiple threads. For each thread that executes scripts, a new /// and scripts executed from multiple threads. For each thread that executes scripts, a new
/// context is created and managed by the engine. /// context is created and managed by the engine.
/// ///
/// Thread safety can be disabled by defining CHAISCRIPT_NO_THREADS when using the library. /// Thread safety can be disabled by defining CHAISCRIPT_NO_THREADS when using the library.
/// ///
/// Disabling thread safety increases performance in many cases. /// Disabling thread safety increases performance in many cases.
@ -429,10 +427,10 @@
/// ///
/// ///
/// @subsection exceptions Exception Handling /// @subsection exceptions Exception Handling
/// ///
/// @subsubsection exceptionsbasics Exception Handling Basics /// @subsubsection exceptionsbasics Exception Handling Basics
/// ///
/// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in /// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in
/// ChaiScript. /// ChaiScript.
/// ///
/// ~~~~~~~~{.cpp} /// ~~~~~~~~{.cpp}
@ -440,14 +438,14 @@
/// { /// {
/// throw std::runtime_error("err"); /// throw std::runtime_error("err");
/// } /// }
/// ///
/// int main() /// int main()
/// { /// {
/// // Throw in C++, catch in ChaiScript /// // Throw in C++, catch in ChaiScript
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::fun(&throwexception), "throwexception"); /// chai.add(chaiscript::fun(&throwexception), "throwexception");
/// chai("try { throwexception(); } catch (e) { print(e.what()); }"); // prints "err" /// chai("try { throwexception(); } catch (e) { print(e.what()); }"); // prints "err"
/// ///
/// // Throw in ChaiScript, catch in C++ /// // Throw in ChaiScript, catch in C++
/// try { /// try {
/// chai("throw(1)"); /// chai("throw(1)");
@ -457,19 +455,18 @@
/// } /// }
/// } /// }
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// @subsubsection exceptionsautomatic Exception Handling Automatic Unboxing /// @subsubsection exceptionsautomatic Exception Handling Automatic Unboxing
/// ///
/// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell /// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell
/// ChaiScript what possible exceptions are expected from the script being executed. /// ChaiScript what possible exceptions are expected from the script being executed.
/// ///
/// Example: /// Example:
/// ~~~~~~~~{.cpp} /// ~~~~~~~~{.cpp}
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// ///
/// try { /// try {
/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const /// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
/// std::exception &>());
/// } catch (const double e) { /// } catch (const double e) {
/// } catch (int) { /// } catch (int) {
/// } catch (float) { /// } catch (float) {
@ -479,9 +476,11 @@
/// } /// }
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing /// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
/// @sa chaiscript::exception_specification /// @sa chaiscript::exception_specification
/// @page LangObjectSystemRef ChaiScript Language Object Model Reference /// @page LangObjectSystemRef ChaiScript Language Object Model Reference
/// ///
/// ///
@ -492,7 +491,7 @@
/// attr Rectangle::width /// attr Rectangle::width
/// def Rectangle::Rectangle() { this.height = 10; this.width = 20 } /// def Rectangle::Rectangle() { this.height = 10; this.width = 20 }
/// def Rectangle::area() { this.height * this.width } /// def Rectangle::area() { this.height * this.width }
/// ///
/// var rect = Rectangle() /// var rect = Rectangle()
/// rect.height = 30 /// rect.height = 30
/// print(rect.area()) /// print(rect.area())
@ -518,7 +517,7 @@
/// @page LangInPlaceRef ChaiScript Language In-Place Creation Reference /// @page LangInPlaceRef ChaiScript Language In-Place Creation Reference
/// @section inplacevector Vector /// @section inplacevector Vector
/// ///
/// ~~~~~~~~~ /// ~~~~~~~~~
/// In-place Vector ::= "[" [expression ("," expression)*] "]" /// In-place Vector ::= "[" [expression ("," expression)*] "]"
/// ~~~~~~~~~ /// ~~~~~~~~~
@ -538,9 +537,9 @@
/// ~~~~~~~~ /// ~~~~~~~~
/// @page LangGettingStarted ChaiScript Language Getting Started /// @page LangGettingStarted ChaiScript Language Getting Started
/// ///
/// ChaiScript is a simple language that should feel familiar to anyone who knows /// ChaiScript is a simple language that should feel familiar to anyone who knows
/// C++ or ECMAScript (JavaScript). /// C++ or ECMAScript (JavaScript).
/// ///
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
@ -572,10 +571,10 @@
/// @section chaiscriptifs Conditionals /// @section chaiscriptifs Conditionals
/// ///
/// If statements work as expected /// If statements work as expected
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
/// var b = true; /// var b = true;
/// ///
/// if (b) { /// if (b) {
/// // do something /// // do something
/// } else if (c < 10) { /// } else if (c < 10) {
@ -590,9 +589,9 @@
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// @section chaiscriptfunctions Functions /// @section chaiscriptfunctions Functions
/// ///
/// Functions are defined with the def keyword /// Functions are defined with the def keyword
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
/// def myfun(x) { print(x); } /// def myfun(x) { print(x); }
/// ///
@ -609,7 +608,7 @@
/// eval> myfun2(12) /// eval> myfun2(12)
/// 10 or greater /// 10 or greater
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// @sa @ref keyworddef /// @sa @ref keyworddef
/// @sa @ref keywordattr /// @sa @ref keywordattr
/// @sa @ref LangObjectSystemRef /// @sa @ref LangObjectSystemRef
@ -617,7 +616,7 @@
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// @section chaiscriptfunctionobjects Function Objects /// @section chaiscriptfunctionobjects Function Objects
/// ///
/// Functions are first class types in ChaiScript and can be used as variables. /// Functions are first class types in ChaiScript and can be used as variables.
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
@ -625,8 +624,8 @@
/// eval> p(1); /// eval> p(1);
/// 1 /// 1
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// They can also be passed to functions. /// They can also be passed to functions.
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
/// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); } /// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); }
@ -636,7 +635,7 @@
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// Operators can also be treated as functions by using the back tick operator. Building on the above example: /// Operators can also be treated as functions by using the back tick operator. Building on the above example:
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
/// eval> callfunc(`+`, 1, 4); /// eval> callfunc(`+`, 1, 4);
/// 5 /// 5
@ -649,6 +648,7 @@
/// @sa @ref LangKeywordRef /// @sa @ref LangKeywordRef
/// @sa ChaiScript_Language for Built in Functions /// @sa ChaiScript_Language for Built in Functions
/// @page LangKeywordRef ChaiScript Language Keyword Reference /// @page LangKeywordRef ChaiScript Language Keyword Reference
/// ///
/// ///
@ -656,8 +656,8 @@
/// ///
/// @section keywordattr attr /// @section keywordattr attr
/// Defines a ChaiScript object attribute /// Defines a ChaiScript object attribute
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
/// Attribute Definition ::= "attr" class_name "::" attribute_name /// Attribute Definition ::= "attr" class_name "::" attribute_name
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
@ -686,7 +686,7 @@
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// @sa @ref keywordfor /// @sa @ref keywordfor
/// @sa @ref keywordwhile /// @sa @ref keywordwhile
/// ///
/// ///
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
@ -695,10 +695,11 @@
/// Begins a function or method definition /// Begins a function or method definition
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
/// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block /// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block /// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// annotation: meta-annotation on function, currently used as documentation. Optional.
/// identifier: name of function. Required. /// identifier: name of function. Required.
/// args: comma-delimited list of parameter names with optional type specifiers. Optional. /// args: comma-delimited list of parameter names with optional type specifiers. Optional.
/// guards: guarding statement that act as a prerequisite for the function. Optional. /// guards: guarding statement that act as a prerequisite for the function. Optional.
@ -718,7 +719,7 @@
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// @section keywordelse else /// @section keywordelse else
/// @sa @ref keywordif /// @sa @ref keywordif
/// ///
/// ///
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
@ -758,7 +759,7 @@
/// Else If Block ::= "else if" "(" condition ")" block /// Else If Block ::= "else if" "(" condition ")" block
/// Else Block ::= "else" block /// Else Block ::= "else" block
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// _Example_ /// _Example_
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
@ -776,8 +777,8 @@
/// ///
/// @section keywordtry try /// @section keywordtry try
/// ~~~~~~~~ /// ~~~~~~~~
/// Try Block ::= "try" block /// Try Block ::= "try" block
/// ("catch" ["(" [type] variable ")"] [":" guards] block)+ /// ("catch" ["(" [type] variable ")"] [":" guards] block)+
/// ["finally" block] /// ["finally" block]
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
@ -787,7 +788,7 @@
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// @section keywordwhile while /// @section keywordwhile while
/// ///
/// Begins a conditional block of code that loops 0 or more times, as long as the condition is true /// Begins a conditional block of code that loops 0 or more times, as long as the condition is true
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
@ -800,7 +801,7 @@
/// ----------------------------------------------------------------------- /// -----------------------------------------------------------------------
/// ///
/// @section keywordvar var /// @section keywordvar var
/// ///
/// Defines a variable /// Defines a variable
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
@ -809,29 +810,23 @@
/// ///
/// Synonym for @ref keywordauto /// Synonym for @ref keywordauto
/// @namespace chaiscript /// @namespace chaiscript
/// @brief Namespace chaiscript contains every API call that the average user will be concerned with. /// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
/// @namespace chaiscript::detail /// @namespace chaiscript::detail
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported. /// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
#include "chaiscript_basic.hpp" #include "chaiscript_defines.hpp"
#include "chaiscript_stdlib.hpp"
#include "language/chaiscript_parser.hpp" #include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
namespace chaiscript {
class ChaiScript : public ChaiScript_Basic {
public:
ChaiScript(std::vector<std::string> t_modulepaths = {},
std::vector<std::string> t_usepaths = {},
std::vector<Options> t_opts = chaiscript::default_options())
: ChaiScript_Basic(chaiscript::Std_Lib::library(),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
std::move(t_modulepaths),
std::move(t_usepaths),
std::move(t_opts)) {
}
};
} // namespace chaiscript
#endif /* CHAISCRIPT_HPP_ */ #endif /* CHAISCRIPT_HPP_ */

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-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BASIC_HPP_
#define CHAISCRIPT_BASIC_HPP_
#include "chaiscript_defines.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/function_call.hpp"
#include "language/chaiscript_engine.hpp"
#include "language/chaiscript_eval.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,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_ #ifndef CHAISCRIPT_DEFINES_HPP_
@ -9,21 +9,23 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#define CHAISCRIPT_STRINGIZE(x) "" #x #define CHAISCRIPT_STRINGIZE(x) "" #x
#define CHAISCRIPT_STRINGIZE_EXPANDED(x) CHAISCRIPT_STRINGIZE(x) #define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE(_MSC_FULL_VER)
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE_EXPANDED(_MSC_FULL_VER)
#define CHAISCRIPT_MSVC _MSC_VER #define CHAISCRIPT_MSVC _MSC_VER
#define CHAISCRIPT_HAS_DECLSPEC #define CHAISCRIPT_HAS_DECLSPEC
#if _MSC_VER <= 1800
static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required"); #define CHAISCRIPT_MSVC_12
#endif
#else #else
#define CHAISCRIPT_COMPILER_VERSION __VERSION__ #define CHAISCRIPT_COMPILER_VERSION __VERSION__
#endif #endif
#include <string_view> #ifndef CHAISCRIPT_MSVC_12
#define CHAISCRIPT_HAS_MAGIC_STATICS
#endif
#include <vector> #include <vector>
#if defined(_LIBCPP_VERSION) #if defined( _LIBCPP_VERSION )
#define CHAISCRIPT_LIBCPP #define CHAISCRIPT_LIBCPP
#endif #endif
@ -49,18 +51,39 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#endif #endif
#endif #endif
#if (defined(CHAISCRIPT_MSVC) && !defined(CHAISCRIPT_MSVC_12)) || (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP))
/// Currently only g++>=4.8 supports this natively
/// \todo Make this support other compilers when possible
#define CHAISCRIPT_HAS_THREAD_LOCAL
#endif
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 6)
#define CHAISCRIPT_GCC_4_6
#endif
#if defined(__llvm__) #if defined(__llvm__)
#define CHAISCRIPT_CLANG #define CHAISCRIPT_CLANG
#endif #endif
#ifdef CHAISCRIPT_HAS_DECLSPEC #if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_CLANG)
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport) #define CHAISCRIPT_OVERRIDE override
#else #else
#define CHAISCRIPT_MODULE_EXPORT extern "C" #define CHAISCRIPT_OVERRIDE
#endif #endif
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
#define CHAISCRIPT_UTF16_UTF32 #ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#ifdef CHAISCRIPT_MSVC_12
#define CHAISCRIPT_NOEXCEPT throw()
#define CHAISCRIPT_CONSTEXPR
#else
#define CHAISCRIPT_NOEXCEPT noexcept
#define CHAISCRIPT_CONSTEXPR constexpr
#endif #endif
#ifdef _DEBUG #ifdef _DEBUG
@ -69,176 +92,101 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_DEBUG false #define CHAISCRIPT_DEBUG false
#endif #endif
#include <cmath>
#include <memory> #include <memory>
#include <string> #include <string>
#include <cmath>
namespace chaiscript { namespace chaiscript {
constexpr static const int version_major = 7; static const int version_major = 5;
constexpr static const int version_minor = 0; static const int version_minor = 8;
constexpr static const int version_patch = 0; static const int version_patch = 5;
constexpr static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION; static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME; static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
constexpr static const bool debug_build = CHAISCRIPT_DEBUG; static const bool debug_build = CHAISCRIPT_DEBUG;
template<typename B, typename D, typename... Arg> template<typename B, typename D, typename ...Arg>
inline std::shared_ptr<B> make_shared(Arg &&...arg) { inline std::shared_ptr<B> make_shared(Arg && ... arg)
{
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED #ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_shared<D>(std::forward<Arg>(arg)...); return std::make_shared<D>(std::forward<Arg>(arg)...);
#else #else
return std::shared_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...))); return std::shared_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...)));
#endif #endif
} }
template<typename B, typename D, typename... Arg> template<typename Iter, typename Distance>
inline std::unique_ptr<B> make_unique(Arg &&...arg) { Iter advance_copy(Iter iter, Distance distance) {
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED std::advance(iter, static_cast<typename std::iterator_traits<Iter>::difference_type>(distance));
return std::make_unique<D>(std::forward<Arg>(arg)...); return iter;
#else
return std::unique_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
#endif
}
struct Build_Info {
[[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; }
[[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; }
[[nodiscard]] constexpr static int version_patch() noexcept { return chaiscript::version_patch; }
[[nodiscard]] static std::string version() {
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
} }
[[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); }
[[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build() ? "-Debug" : "-Release"); }
[[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; }
[[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; }
[[nodiscard]] constexpr static bool debug_build() noexcept { return chaiscript::debug_build; }
};
template<typename T> template<typename T>
[[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type { auto parse_num(const char *t_str) -> typename std::enable_if<std::is_integral<T>::value, T>::type
T t = 0; {
for (const auto c : t_str) { T t = 0;
if (c < '0' || c > '9') { for (char c = *t_str; (c = *t_str); ++t_str) {
return t; if (c < '0' || c > '9') {
return t;
}
t *= 10;
t += c - '0';
} }
t *= 10; return t;
t += c - '0';
} }
return t;
}
template<typename T> template<typename T>
[[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type { auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
T t = 0; {
T base{}; T t = 0;
T decimal_place = 0; T base = 0;
int exponent = 0; T decimal_place = 0;
bool exponent = false;
bool neg_exponent = false;
for (const auto c : t_str) { const auto final_value = [](const T val, const T baseval, const bool hasexp, const bool negexp) -> T {
switch (c) { if (!hasexp) {
case '.': 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; decimal_place = 10;
break; } else if (c == 'e' || c == 'E') {
case 'e': exponent = true;
case 'E':
exponent = 1;
decimal_place = 0; decimal_place = 0;
base = t; base = t;
t = 0; t = 0;
break; } else if (c == '-' && exponent) {
case '-': neg_exponent = true;
exponent = -1; } else if (c == '+' && exponent) {
break; neg_exponent = false;
case '+': } else if (c < '0' || c > '9') {
break; return final_value(t, base, exponent, neg_exponent);
case '0': } else if (decimal_place < T(10)) {
case '1': t *= T(10);
case '2': t += T(c - '0');
case '3': } else {
case '4': t += (T(c - '0') / (T(decimal_place)));
case '5': decimal_place *= 10;
case '6': }
case '7':
case '8':
case '9':
if (decimal_place < 10) {
t *= 10;
t += static_cast<T>(c - '0');
} else {
t += static_cast<T>(c - '0') / decimal_place;
decimal_place *= 10;
}
break;
default:
break;
} }
return final_value(t, base, exponent, neg_exponent);
} }
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
}
struct str_equal { template<typename T>
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs == t_rhs; } T parse_num(const std::string &t_str)
template<typename LHS, typename RHS> {
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { return parse_num<T>(t_str.c_str());
return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
} }
struct is_transparent {
};
};
struct str_less { }
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; }
template<typename LHS, typename RHS>
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
}
struct is_transparent {
};
};
enum class Options {
No_Load_Modules,
Load_Modules,
No_External_Scripts,
External_Scripts
};
template<typename From, typename To>
struct is_nothrow_forward_constructible : std::bool_constant<noexcept(To{std::declval<From>()})> {
};
template<class From, class To>
static inline constexpr bool is_nothrow_forward_constructible_v = is_nothrow_forward_constructible<From, To>::value;
template<typename Container, typename... T>
[[nodiscard]] constexpr auto make_container(T &&...t) {
Container c;
c.reserve(sizeof...(t));
(c.push_back(std::forward<T>(t)), ...);
return c;
}
template<typename... T>
[[nodiscard]] auto make_vector(T &&...t) -> std::vector<std::common_type_t<std::decay_t<T>...>> {
using container_type = std::vector<std::common_type_t<std::decay_t<T>...>>;
return make_container<container_type>(std::forward<T>(t)...);
}
[[nodiscard]] 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
}
} // namespace chaiscript
#endif #endif

View File

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

View File

@ -1,24 +1,21 @@
// 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-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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> #include <unordered_map>
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
#include <mutex>
#include <shared_mutex>
#include <thread> #include <thread>
#include <mutex>
#else #else
#ifndef CHAISCRIPT_NO_THREADS_WARNING #ifndef CHAISCRIPT_NO_THREADS_WARNING
#pragma message("ChaiScript is compiling without thread safety.") #pragma message ("ChaiScript is compiling without thread safety.")
#endif #endif
#endif #endif
@ -32,102 +29,214 @@
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than /// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
/// one thread simultaneously. /// one thread simultaneously.
/// If threading is enabled, then this namespace contains std thread classes. namespace chaiscript
/// 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. namespace detail
namespace chaiscript::detail::threading { {
/// If threading is enabled, then this namespace contains std thread classes.
/// 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.
namespace threading
{
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
template<typename T> template<typename T>
using unique_lock = std::unique_lock<T>; class unique_lock : public std::unique_lock<T>
{
public:
explicit unique_lock(T &t) : std::unique_lock<T>(t) {}
};
template<typename T> template<typename T>
using shared_lock = std::shared_lock<T>; class shared_lock : public std::unique_lock<T>
{
public:
explicit shared_lock(T &t) : std::unique_lock<T>(t) {}
void unlock() {}
};
template<typename T> template<typename T>
using lock_guard = std::lock_guard<T>; class lock_guard : public std::lock_guard<T>
{
public:
explicit lock_guard(T &t) : std::lock_guard<T>(t) {}
};
using std::shared_mutex; class shared_mutex : public std::mutex { };
using std::mutex; using std::mutex;
using std::recursive_mutex; using std::recursive_mutex;
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If #ifdef CHAISCRIPT_HAS_THREAD_LOCAL
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from. /// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
template<typename T> /// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
class Thread_Storage { template<typename T>
public: class Thread_Storage
Thread_Storage() = default; {
Thread_Storage(const Thread_Storage &) = delete; public:
Thread_Storage(Thread_Storage &&) = delete;
Thread_Storage &operator=(const Thread_Storage &) = delete;
Thread_Storage &operator=(Thread_Storage &&) = delete;
~Thread_Storage() { t().erase(this); } explicit Thread_Storage(void *t_key)
: m_key(t_key)
{
}
inline const T *operator->() const noexcept { return &(t()[this]); } ~Thread_Storage()
{
t().erase(m_key);
}
inline const T &operator*() const noexcept { return t()[this]; } inline const T *operator->() const
{
return &(t()[m_key]);
}
inline T *operator->() noexcept { return &(t()[this]); } inline const T &operator*() const
{
return t()[m_key];
}
inline T &operator*() noexcept { return t()[this]; } inline T *operator->()
{
return &(t()[m_key]);
}
void *m_key; inline T &operator*()
{
return t()[m_key];
}
private:
/// todo: is it valid to make this noexcept? The allocation could fail, but if it void *m_key;
/// does there is no possible way to recover
static std::unordered_map<const void *, T> &t() noexcept { private:
static thread_local std::unordered_map<const void *, T> my_t; static std::unordered_map<void*, T> &t()
return my_t; {
} thread_local static std::unordered_map<void *, T> my_t;
}; return my_t;
}
};
#else
/// 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.
///
/// This version is used if the compiler does not support thread_local
template<typename T>
class Thread_Storage
{
public:
explicit Thread_Storage(void *)
{
}
inline const T *operator->() const
{
return get_tls().get();
}
inline const T &operator*() const
{
return *get_tls();
}
inline T *operator->()
{
return get_tls().get();
}
inline T &operator*()
{
return *get_tls();
}
private:
/// \todo this leaks thread instances. It needs to be culled from time to time
std::shared_ptr<T> get_tls() const
{
unique_lock<mutex> lock(m_mutex);
const auto id = std::this_thread::get_id();
auto itr = m_instances.find(id);
if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(std::make_shared<T>());
m_instances.insert(std::make_pair(id, new_instance));
return new_instance;
}
mutable mutex m_mutex;
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
};
#endif // threading enabled but no tls
#else // threading disabled #else // threading disabled
template<typename T> template<typename T>
class unique_lock { class unique_lock
public: {
constexpr explicit unique_lock(T &) noexcept {} public:
constexpr void lock() noexcept {} explicit unique_lock(T &) {}
constexpr void unlock() noexcept {} void lock() {}
}; void unlock() {}
};
template<typename T> template<typename T>
class shared_lock { class shared_lock
public: {
constexpr explicit shared_lock(T &) noexcept {} public:
constexpr void lock() noexcept {} explicit shared_lock(T &) {}
constexpr void unlock() noexcept {} void lock() {}
}; void unlock() {}
};
template<typename T> template<typename T>
class lock_guard { class lock_guard
public: {
constexpr explicit lock_guard(T &) noexcept {} public:
}; explicit lock_guard(T &) {}
};
class shared_mutex { class shared_mutex { };
};
class recursive_mutex { class recursive_mutex {};
};
template<typename T>
class Thread_Storage {
public:
constexpr explicit Thread_Storage() noexcept {}
constexpr inline T *operator->() const noexcept { return &obj; } template<typename T>
class Thread_Storage
{
public:
explicit Thread_Storage(void *)
{
}
constexpr inline T &operator*() const noexcept { return obj; } inline T *operator->() const
{
return &obj;
}
private: inline T &operator*() const
mutable T obj; {
}; return obj;
}
private:
mutable T obj;
};
#endif #endif
} // namespace chaiscript::detail::threading }
}
}
#endif #endif

View File

@ -11,105 +11,165 @@
namespace chaiscript { namespace chaiscript {
namespace detail { namespace detail {
namespace exception { namespace exception
{
/// \brief Thrown in the event that an Any cannot be cast to the desired type /// \brief Thrown in the event that an Any cannot be cast to the desired type
/// ///
/// It is used internally during function dispatch. /// It is used internally during function dispatch.
/// ///
/// \sa chaiscript::detail::Any /// \sa chaiscript::detail::Any
class bad_any_cast : public std::bad_cast { class bad_any_cast : public std::bad_cast
public: {
/// \brief Description of what error occurred public:
const char *what() const noexcept override { return "bad any cast"; } bad_any_cast() CHAISCRIPT_NOEXCEPT
: m_what("bad any cast")
{
}
bad_any_cast(const bad_any_cast &) = default;
virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{
return m_what.c_str();
}
private:
std::string m_what;
}; };
} // namespace exception }
class Any { class Any {
private: private:
struct Data { struct Data
constexpr explicit Data(const std::type_info &t_type) noexcept {
: m_type(t_type) { explicit Data(const std::type_info &t_type)
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete;
virtual ~Data() {}
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))
{
}
virtual ~Data_Impl() {}
virtual void *data() CHAISCRIPT_OVERRIDE
{
return &m_data;
}
std::unique_ptr<Data> clone() const CHAISCRIPT_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(const Any &t_any)
{
if (!t_any.empty())
{
m_data = t_any.m_data->clone();
} else {
m_data.reset();
}
} }
Data &operator=(const Data &) = delete; #if !defined(_MSC_VER) || _MSC_VER != 1800
Any(Any &&) = default;
Any &operator=(Any &&t_any) = default;
#endif
virtual ~Data() noexcept = default; template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
virtual void *data() noexcept = 0; explicit Any(ValueType &&t_value)
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
const std::type_info &type() const noexcept { 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() noexcept override { return &m_data; }
std::unique_ptr<Data> clone() const override { return std::make_unique<Data_Impl<T>>(m_data); } Any & operator=(const Any &t_any)
{
Data_Impl &operator=(const Data_Impl &) = delete; Any copy(t_any);
swap(copy);
T m_data; return *this;
};
std::unique_ptr<Data> m_data;
public:
// construct/copy/destruct
constexpr Any() noexcept = default;
Any(Any &&) noexcept = default;
Any &operator=(Any &&t_any) = default;
Any(const Any &t_any)
: m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) {
}
template<typename ValueType, typename = std::enable_if_t<!std::is_same_v<Any, std::decay_t<ValueType>>>>
explicit Any(ValueType &&t_value)
: m_data(std::make_unique<Data_Impl<std::decay_t<ValueType>>>(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 template<typename ToType>
Any &swap(Any &t_other) { ToType &cast() const
std::swap(t_other.m_data, m_data); {
return *this; if (m_data && typeid(ToType) == m_data->type())
} {
return *static_cast<ToType *>(m_data->data());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
// queries
bool empty() const noexcept { return !static_cast<bool>(m_data); }
const std::type_info &type() const noexcept { ~Any()
if (m_data) { {
return m_data->type(); }
} else {
return typeid(void); // 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);
}
} }
}
}; };
} // namespace detail }
} // namespace chaiscript }
#endif #endif

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -14,51 +11,59 @@
#include <typeinfo> #include <typeinfo>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "../utility/static_string.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Info; class Type_Info;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript { namespace chaiscript
namespace exception { {
namespace exception
{
/// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type /// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type
/// ///
/// It is used internally during function dispatch and may be used by the end user. /// It is used internally during function dispatch and may be used by the end user.
/// ///
/// \sa chaiscript::boxed_cast /// \sa chaiscript::boxed_cast
class bad_boxed_cast : public std::bad_cast { class bad_boxed_cast : public std::bad_cast
public: {
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, utility::Static_String t_what) noexcept public:
: from(t_from) bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
, to(&t_to) std::string t_what) CHAISCRIPT_NOEXCEPT
, m_what(std::move(t_what)) { : from(std::move(t_from)), to(&t_to), m_what(std::move(t_what))
} {
}
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(t_from) : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
, to(&t_to) {
, m_what("Cannot perform boxed_cast") { }
}
explicit bad_boxed_cast(utility::Static_String t_what) noexcept explicit bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT
: m_what(std::move(t_what)) { : to(nullptr), m_what(std::move(t_what))
} {
}
bad_boxed_cast(const bad_boxed_cast &) noexcept = default; bad_boxed_cast(const bad_boxed_cast &) = default;
~bad_boxed_cast() noexcept override = default; virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occurred /// \brief Description of what error occurred
const char *what() const noexcept override { return m_what.c_str(); } virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{
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:
utility::Static_String m_what; std::string m_what;
}; };
} // namespace exception }
} // namespace chaiscript }
#endif #endif

View File

@ -1,60 +1,74 @@
// 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-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BIND_FIRST_HPP_ #ifndef CHAISCRIPT_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_ #define CHAISCRIPT_BIND_FIRST_HPP_
#include <functional> #include <functional>
namespace chaiscript { namespace chaiscript
namespace detail { {
template<typename T> namespace detail
constexpr T *get_pointer(T *t) noexcept { {
return t;
}
template<typename T> template<typename T>
T *get_pointer(const std::reference_wrapper<T> &t) noexcept { T* get_pointer(T *t)
return &t.get(); {
} return t;
}
template<typename O, typename Ret, typename P1, typename... Param> template<typename T>
constexpr auto bind_first(Ret (*f)(P1, Param...), O &&o) { T* get_pointer(const std::reference_wrapper<T> &t)
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); }; {
} return &t.get();
}
template<typename O, typename Ret, typename Class, typename... Param> template<typename O, typename Ret, typename P1, typename ... Param>
constexpr auto bind_first(Ret (Class::*f)(Param...), O &&o) { std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); }; {
} return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return f(std::forward<O>(o), std::forward<Param>(param)...);
}
);
}
template<typename O, typename Ret, typename Class, typename... Param> template<typename O, typename Ret, typename Class, typename ... Param>
constexpr auto bind_first(Ret (Class::*f)(Param...) const, O &&o) { std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); }; {
} return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
}
);
}
template<typename O, typename Ret, typename P1, typename... Param> template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(const std::function<Ret(P1, Param...)> &f, O &&o) { std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); }; {
} return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
}
);
template<typename F, typename O, typename Ret, typename Class, typename P1, typename... Param> }
constexpr auto bind_first(const F &fo, O &&o, Ret (Class::*f)(P1, Param...) const) {
return [fo, o = std::forward<O>(o), f](Param... param) -> Ret { return (fo.*f)(o, std::forward<Param>(param)...); };
}
template<typename F, typename O> template<typename O, typename Ret, typename P1, typename ... Param>
constexpr auto bind_first(const F &f, O &&o) { std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
return bind_first(f, std::forward<O>(o), &F::operator()); {
} return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return f(o, std::forward<Param>(param)...);
});
}
}
}
} // namespace detail
} // namespace chaiscript
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -18,19 +15,23 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions;
} namespace detail {
namespace chaiscript::detail::exception { namespace exception {
class bad_any_cast; class bad_any_cast;
} // namespace chaiscript::detail::exception } // namespace exception
} // namespace detail
} // namespace chaiscript
namespace chaiscript { namespace chaiscript
{
/// \brief Function for extracting a value stored in a Boxed_Value object /// \brief Function for extracting a value stored in a Boxed_Value object
/// \tparam Type The type to extract from the Boxed_Value /// \tparam Type The type to extract from the Boxed_Value
/// \param[in] bv The Boxed_Value to extract a typed value from /// \param[in] bv The Boxed_Value to extract a typed value from
/// \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, &, *, std::shared_ptr, std::reference_wrapper,
/// and std::function (const and non-const) where possible. boxed_cast is used internally during function /// and std::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
@ -62,13 +63,14 @@ namespace chaiscript {
/// std::function conversion example /// std::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); /// std::function<int (int, int)> f = chaiscript::boxed_cast<std::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 Type_Conversions_State *t_conversions = nullptr)
{
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) { if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
try { try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions); return detail::Cast_Helper<Type>::cast(bv, t_conversions);
@ -76,27 +78,34 @@ namespace chaiscript {
} }
} }
if (t_conversions && (*t_conversions)->convertable_type<Type>()) {
if (t_conversions && (*t_conversions)->convertable_type<Type>())
{
try { try {
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work // either way, we are not responsible if it doesn't work
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions)); return detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions);
} catch (...) { } catch (...) {
try { try {
// try going the other way // std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), // try going the other way - down the inheritance graph
t_conversions)); return detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
} }
} else { } else {
// If it's not convertable, just throw the error, don't waste the time on the // If it's not polymorphic, just throw the error, don't waste the time on the
// attempted dynamic_cast // attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
} }
} // namespace chaiscript }
#endif #endif

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -16,245 +13,274 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript {
namespace chaiscript
{
class Type_Conversions_State; class Type_Conversions_State;
namespace detail { namespace detail
{
// Cast_Helper_Inner helper classes // Cast_Helper_Inner helper classes
template<typename T> template<typename T>
constexpr T *throw_if_null(T *t) { T* throw_if_null(T *t)
if (t) { {
return t; if (t) return t;
throw std::runtime_error("Attempted to dereference null Boxed_Value");
} }
throw std::runtime_error("Attempted to dereference null Boxed_Value");
}
template<typename T>
static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info() == ti) {
return ptr;
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
if (!ob.is_const() && ob.get_type_info() == ti) {
return ptr;
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info().bare_equal_type_info(ti)) {
return throw_if_null(ptr);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static T *verify_type(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
if (!ob.is_const() && ob.get_type_info().bare_equal_type_info(ti)) {
return throw_if_null(ptr);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
/// Generic Cast_Helper_Inner, for casting to any type /// Generic Cast_Helper_Inner, for casting to any type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner { struct Cast_Helper_Inner
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) { {
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr())); typedef typename std::add_const<Result>::type Result_Type;
}
}; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
auto p = throw_if_null(ob.get_const_ptr());
return *static_cast<const Result *>(p);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> { struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
}; {
};
/// Cast_Helper_Inner for casting to a const * type /// Cast_Helper_Inner for casting to a const * type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result *> { struct Cast_Helper_Inner<const Result *>
static const Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) { {
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr())); typedef const Result * Result_Type;
} static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
}; {
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
return static_cast<const Result *>(ob.get_const_ptr());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
/// Cast_Helper_Inner for casting to a * type /// Cast_Helper_Inner for casting to a * type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result *> { struct Cast_Helper_Inner<Result *>
static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) { {
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr())); typedef Result * Result_Type;
} static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
{
return static_cast<Result *>(ob.get_ptr());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
template<typename Result>
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result *const &> : public Cast_Helper_Inner<Result *> { struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const 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 /// Cast_Helper_Inner for casting to a & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result &> { struct Cast_Helper_Inner<const Result &>
static const Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) { {
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr())); typedef const Result& Result_Type;
}
}; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
auto p = throw_if_null(ob.get_const_ptr());
return *static_cast<const Result *>(p);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
/// Cast_Helper_Inner for casting to a & type /// Cast_Helper_Inner for casting to a & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result &> { struct Cast_Helper_Inner<Result &>
static Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) { {
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())); typedef Result& Result_Type;
}
};
/// Cast_Helper_Inner for casting to a && type static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
template<typename Result> {
struct Cast_Helper_Inner<Result &&> { if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(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()))); return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
} } else {
}; throw chaiscript::detail::exception::bad_any_cast();
}
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type }
/// \todo Fix the fact that this has to be in a shared_ptr for now };
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &&> {
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &> {
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<const std::unique_ptr<Result> &> {
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type /// Cast_Helper_Inner for casting to a std::shared_ptr<> type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result>> { struct Cast_Helper_Inner<std::shared_ptr<Result> >
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob.get().cast<std::shared_ptr<Result>>(); } {
}; typedef std::shared_ptr<Result> Result_Type;
static Result_Type 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 /// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<const Result>> { struct Cast_Helper_Inner<std::shared_ptr<const Result> >
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { {
if (!ob.get_type_info().is_const()) { typedef std::shared_ptr<const Result> Result_Type;
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result>>());
} else { static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
return ob.get().cast<std::shared_ptr<const Result>>(); {
if (!ob.get_type_info().is_const())
{
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
} else {
return ob.get().cast<std::shared_ptr<const Result> >();
}
} }
} };
};
/// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type /// Cast_Helper_Inner for casting to a const std::shared_ptr<> & 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 std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> >
}; {
};
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 std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result> >
}; {
};
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> &> { struct Cast_Helper_Inner<std::shared_ptr<Result> &>
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported"); {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result>>();
return ob.pointer_sentinel(res); typedef Boxed_Value::Sentinel<Result> Result_Type;
}
}; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
return ob.pointer_sentinel(res);
}
};
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type /// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result>> : Cast_Helper_Inner<std::shared_ptr<const Result>> { struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
}; {
};
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result>> { struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> >
}; {
};
/// Cast_Helper_Inner for casting to a Boxed_Value type /// 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 *) { return ob; } {
}; typedef Boxed_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob;
}
};
/// Cast_Helper_Inner for casting to a Boxed_Value & type /// 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 std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *) { {
return std::ref(const_cast<Boxed_Value &>(ob)); typedef std::reference_wrapper<Boxed_Value> Result_Type;
}
}; static Result_Type 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 /// 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>
}; {
};
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>
}; {
};
/// Cast_Helper_Inner for casting to a std::reference_wrapper type /// Cast_Helper_Inner for casting to a std::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<std::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 std::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 std::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<std::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 std::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 std::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) { {
return (Cast_Helper_Inner<T>::cast(ob, t_conversions)); typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
}
};
} // namespace detail
} // namespace chaiscript static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
}
};
}
}
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -18,238 +15,358 @@
#include "any.hpp" #include "any.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript
{
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects /// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
/// \sa chaiscript::boxed_cast /// \sa chaiscript::boxed_cast
class Boxed_Value { class Boxed_Value
public: {
/// used for explicitly creating a "void" object public:
struct Void_Type { /// used for explicitly creating a "void" object
}; struct Void_Type
{
};
private: private:
/// structure which holds the internal state of a Boxed_Value /// 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 /// \todo Get rid of Any and merge it with this, reducing an allocation in the process
struct Data { struct Data
Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value) noexcept {
: m_type_info(ti) Data(const Type_Info &ti,
, m_obj(std::move(to)) chaiscript::detail::Any to,
, m_data_ptr(ti.is_const() ? nullptr : const_cast<void *>(t_void_ptr)) bool tr,
, m_const_data_ptr(t_void_ptr) const void *t_void_ptr,
, m_is_ref(is_ref) bool t_return_value)
, m_return_value(t_return_value) { : m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
} m_is_ref(tr), m_return_value(t_return_value)
{
Data &operator=(const Data &rhs) {
m_type_info = rhs.m_type_info;
m_obj = rhs.m_obj;
m_is_ref = rhs.m_is_ref;
m_data_ptr = rhs.m_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);
} }
Data &operator=(const Data &rhs)
{
m_type_info = rhs.m_type_info;
m_obj = rhs.m_obj;
m_is_ref = rhs.m_is_ref;
m_data_ptr = rhs.m_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::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*rhs.m_attrs));
}
return *this;
}
Data(const Data &) = delete;
#if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER != 1800)
Data(Data &&) = default;
Data &operator=(Data &&rhs) = default;
#endif
Type_Info m_type_info;
chaiscript::detail::Any m_obj;
void *m_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_return_value;
};
struct Object_Data
{
static std::shared_ptr<Data> get(Boxed_Value::Void_Type, bool t_return_value)
{
return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
chaiscript::detail::Any(),
false,
nullptr,
t_return_value)
;
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj, bool t_return_value)
{
return get(*obj, t_return_value);
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj, bool t_return_value)
{
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj),
false,
obj.get(),
t_return_value
);
}
template<typename T>
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj, bool t_return_value)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
false,
ptr,
t_return_value
);
}
template<typename T>
static std::shared_ptr<Data> get(T *t, bool t_return_value)
{
return get(std::ref(*t), t_return_value);
}
template<typename T>
static std::shared_ptr<Data> get(const T *t, bool t_return_value)
{
return get(std::cref(*t), t_return_value);
}
template<typename T>
static std::shared_ptr<Data> 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,
p,
t_return_value
);
}
template<typename T>
static std::shared_ptr<Data> 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,
ptr,
t_return_value
);
}
static std::shared_ptr<Data> get()
{
return std::make_shared<Data>(
Type_Info(),
chaiscript::detail::Any(),
false,
nullptr,
false
);
}
};
public:
/// Basic Boxed_Value constructor
template<typename T,
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)
: m_data(Object_Data::get(std::forward<T>(t), t_return_value))
{
}
/// Unknown-type constructor
Boxed_Value()
: m_data(Object_Data::get())
{
}
#if !defined(_MSC_VER) || _MSC_VER != 1800
Boxed_Value(Boxed_Value&&) = default;
Boxed_Value& operator=(Boxed_Value&&) = default;
#endif
Boxed_Value(const Boxed_Value&) = default;
Boxed_Value& operator=(const Boxed_Value&) = default;
void swap(Boxed_Value &rhs)
{
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
Boxed_Value assign(const Boxed_Value &rhs)
{
(*m_data) = (*rhs.m_data);
return *this; return *this;
} }
Data(const Data &) = delete; const Type_Info &get_type_info() const CHAISCRIPT_NOEXCEPT
{
return m_data->m_type_info;
}
Data(Data &&) = default; /// return true if the object is uninitialized
Data &operator=(Data &&rhs) = default; bool is_undef() const CHAISCRIPT_NOEXCEPT
{
return m_data->m_type_info.is_undef();
}
Type_Info m_type_info; bool is_const() const CHAISCRIPT_NOEXCEPT
chaiscript::detail::Any m_obj; {
void *m_data_ptr; return m_data->m_type_info.is_const();
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_return_value;
};
struct Object_Data { bool is_type(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
static auto get(Boxed_Value::Void_Type, bool t_return_value) { {
return std::make_shared<Data>(detail::Get_Type_Info<void>::get(), chaiscript::detail::Any(), false, nullptr, t_return_value); return m_data->m_type_info.bare_equal(ti);
} }
template<typename T> template<typename T>
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) {
return get(*obj, t_return_value);
}
template<typename T>
static auto get(const std::shared_ptr<T> &obj, bool t_return_value) {
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(obj), false, obj.get(), t_return_value);
}
template<typename T>
static auto get(std::shared_ptr<T> &&obj, bool t_return_value) {
auto ptr = obj.get();
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(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, p, t_return_value);
}
template<typename T>
static auto get(std::unique_ptr<T> &&obj, bool t_return_value) {
auto ptr = obj.get();
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
true,
ptr,
t_return_value);
}
template<typename T>
static auto get(T t, bool t_return_value) {
auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(p)), false, ptr, t_return_value);
}
static std::shared_ptr<Data> get() { return std::make_shared<Data>(Type_Info(), chaiscript::detail::Any(), false, nullptr, false); }
};
public:
/// Basic Boxed_Value constructor
template<typename T, typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_t<T>>>>
explicit Boxed_Value(T &&t, bool t_return_value = false)
: m_data(Object_Data::get(std::forward<T>(t), t_return_value)) {
}
/// Unknown-type constructor
Boxed_Value() = default;
Boxed_Value(Boxed_Value &&) = default;
Boxed_Value &operator=(Boxed_Value &&) = default;
Boxed_Value(const Boxed_Value &) = default;
Boxed_Value &operator=(const Boxed_Value &) = default;
void swap(Boxed_Value &rhs) noexcept { 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
Boxed_Value assign(const Boxed_Value &rhs) noexcept {
(*m_data) = (*rhs.m_data);
return *this;
}
const Type_Info &get_type_info() const noexcept { return m_data->m_type_info; }
/// return true if the object is uninitialized
bool is_undef() const noexcept { return m_data->m_type_info.is_undef(); }
bool is_const() const noexcept { return m_data->m_type_info.is_const(); }
bool is_type(const Type_Info &ti) const noexcept { return m_data->m_type_info.bare_equal(ti); }
template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const noexcept {
struct Sentinel { struct Sentinel {
Sentinel(std::shared_ptr<T> &t_ptr, Data &data) Sentinel(std::shared_ptr<T> &ptr, Data &data)
: m_ptr(t_ptr) : m_ptr(ptr), m_data(data)
, m_data(data) { {
} }
~Sentinel() { ~Sentinel()
{
// save new pointer data // save new pointer data
const auto ptr_ = m_ptr.get().get(); m_data.get().m_data_ptr = m_ptr.get().get();
m_data.get().m_data_ptr = ptr_; m_data.get().m_const_data_ptr = m_ptr.get().get();
m_data.get().m_const_data_ptr = ptr_;
} }
Sentinel &operator=(Sentinel &&s) = default; Sentinel& operator=(Sentinel&&s) {
Sentinel(Sentinel &&s) = default; m_ptr = std::move(s.m_ptr);
m_data = std::move(s.m_data);
}
operator std::shared_ptr<T> &() const noexcept { return m_ptr.get(); } Sentinel(Sentinel &&s)
: m_ptr(std::move(s.m_ptr)),
m_data(std::move(s.m_data))
{
}
operator std::shared_ptr<T>&() const
{
return m_ptr.get();
}
Sentinel &operator=(const Sentinel &) = delete; Sentinel &operator=(const Sentinel &) = delete;
Sentinel(Sentinel &) = delete; Sentinel(Sentinel&) = delete;
std::reference_wrapper<std::shared_ptr<T>> m_ptr; std::reference_wrapper<std::shared_ptr<T>> m_ptr;
std::reference_wrapper<Data> m_data; std::reference_wrapper<Data> m_data;
}; };
return Sentinel(ptr, *(m_data.get()));
}
bool is_null() const noexcept { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); } template<typename T>
Sentinel<T> pointer_sentinel(std::shared_ptr<T> &ptr) const
const chaiscript::detail::Any &get() const noexcept { return m_data->m_obj; } {
return Sentinel<T>(ptr, *(m_data.get()));
bool is_ref() const noexcept { return m_data->m_is_ref; }
bool is_return_value() const noexcept { 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(); }
void *get_ptr() const noexcept { return m_data->m_data_ptr; }
const void *get_const_ptr() const noexcept { 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]; bool is_null() const CHAISCRIPT_NOEXCEPT
if (attr) { {
return Boxed_Value(attr, Internal_Construction()); return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
} else {
Boxed_Value bv; // default construct a new one
attr = bv.m_data;
return bv;
} }
}
Boxed_Value &copy_attrs(const Boxed_Value &t_obj) { const chaiscript::detail::Any & get() const CHAISCRIPT_NOEXCEPT
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 m_data->m_obj;
} }
return *this;
}
Boxed_Value &clone_attrs(const Boxed_Value &t_obj) { bool is_ref() const CHAISCRIPT_NOEXCEPT
copy_attrs(t_obj); {
reset_return_value(); return m_data->m_is_ref;
return *this; }
}
/// \returns true if the two Boxed_Values share the same internal type bool is_return_value() const CHAISCRIPT_NOEXCEPT
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept { return l.get_type_info() == r.get_type_info(); } {
return m_data->m_return_value;
}
private: void reset_return_value() const CHAISCRIPT_NOEXCEPT
// necessary to avoid hitting the templated && constructor of Boxed_Value {
struct Internal_Construction { m_data->m_return_value = false;
}; }
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction) bool is_pointer() const CHAISCRIPT_NOEXCEPT
: m_data(std::move(t_data)) { {
} return !is_ref();
}
std::shared_ptr<Data> m_data = Object_Data::get(); void *get_ptr() const CHAISCRIPT_NOEXCEPT
{
return m_data->m_data_ptr;
}
const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
{
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::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>());
}
auto &attr = (*m_data->m_attrs)[t_name];
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::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*t_obj.m_data->m_attrs));
}
return *this;
}
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) CHAISCRIPT_NOEXCEPT
{
return l.get_type_info() == r.get_type_info();
}
private:
// necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction{};
Boxed_Value(const std::shared_ptr<Data> &t_data, Internal_Construction)
: m_data(t_data) {
}
std::shared_ptr<Data> m_data;
}; };
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or /// @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
/// std::reference_type
/// a copy is not made. /// a copy is not made.
/// @param t The value to box /// @param t The value to box
/// ///
@ -264,19 +381,21 @@ namespace chaiscript {
/// ///
/// @sa @ref adding_objects /// @sa @ref adding_objects
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(std::forward<T>(t));
}
namespace detail { namespace detail {
/// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable /// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable
/// \param[in] t Value to copy and make const /// \param[in] t Value to copy and make const
/// \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 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(std::make_shared<typename std::add_const<T>::type >(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.
/// Does not copy the pointed to value. /// Does not copy the pointed to value.
@ -284,9 +403,10 @@ namespace chaiscript {
/// \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(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 std::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 std::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.
@ -294,9 +414,10 @@ namespace chaiscript {
/// \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 std::shared_ptr<T> &t)
return Boxed_Value(std::const_pointer_cast<typename std::add_const<T>::type>(t)); {
} return Boxed_Value( std::const_pointer_cast<typename std::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 std::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.
@ -304,10 +425,11 @@ namespace chaiscript {
/// \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 std::reference_wrapper<T> &t)
return Boxed_Value(std::cref(t.get())); {
} return Boxed_Value( std::cref(t.get()) );
} // namespace detail }
}
/// \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 std::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.
@ -329,22 +451,19 @@ namespace chaiscript {
/// chai.add(chaiscript::const_var(Red), "Red"); /// chai.add(chaiscript::const_var(Red), "Red");
/// chai.add(chaiscript::const_var(Green), "Green"); /// chai.add(chaiscript::const_var(Green), "Green");
/// \endcode /// \endcode
/// ///
/// \todo support C++11 strongly typed enums /// \todo support C++11 strongly typed enums
/// \sa \ref adding_objects /// \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;
}
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS
inline Boxed_Value const_var(bool b) { inline Boxed_Value const_var(bool b) {
static const auto t = detail::const_var_impl(true); static auto t = detail::const_var_impl(true);
static const auto f = detail::const_var_impl(false); static auto f = detail::const_var_impl(false);
if (b) { if (b) {
return t; return t;
@ -352,7 +471,9 @@ namespace chaiscript {
return f; return f;
} }
} }
#endif
} // namespace chaiscript }
#endif #endif

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_ #ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
@ -12,50 +12,49 @@
namespace chaiscript { namespace chaiscript {
namespace dispatch { namespace dispatch {
namespace detail { namespace detail {
template<typename Class, typename... Param>
struct Constructor { template<typename Class, typename ... Param>
template<typename... Inner> struct Constructor
std::shared_ptr<Class> operator()(Inner &&...inner) const { {
template<typename ... Inner>
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
return std::make_shared<Class>(std::forward<Inner>(inner)...); return std::make_shared<Class>(std::forward<Inner>(inner)...);
} }
}; };
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename ... Param>
struct Const_Caller { struct Const_Caller
explicit Const_Caller(Ret (Class::*t_func)(Param...) const) {
: m_func(t_func) { Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
}
template<typename... Inner> template<typename ... Inner>
Ret operator()(const Class &o, Inner &&...inner) const { Ret operator()(const Class &o, Inner&& ... inner) const {
return (o.*m_func)(std::forward<Inner>(inner)...); return (o.*m_func)(std::forward<Inner>(inner)...);
} }
Ret (Class::*m_func)(Param...) const; Ret (Class::*m_func)(Param...) const;
}; };
template<typename Ret, typename... Param> template<typename Ret, typename ... Param>
struct Fun_Caller { struct Fun_Caller
explicit Fun_Caller(Ret (*t_func)(Param...)) {
: m_func(t_func) { Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
}
template<typename... Inner> template<typename ... Inner>
Ret operator()(Inner &&...inner) const { Ret operator()(Inner&& ... inner) const {
return (m_func)(std::forward<Inner>(inner)...); return (m_func)(std::forward<Inner>(inner)...);
} }
Ret (*m_func)(Param...); Ret(*m_func)(Param...);
}; };
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename ... Param>
struct Caller { struct Caller
explicit Caller(Ret (Class::*t_func)(Param...)) {
: m_func(t_func) { Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
}
template<typename... Inner> template<typename ... Inner>
Ret operator()(Class &o, Inner &&...inner) const { Ret operator()(Class &o, Inner&& ... inner) const {
return (o.*m_func)(std::forward<Inner>(inner)...); return (o.*m_func)(std::forward<Inner>(inner)...);
} }
@ -63,37 +62,46 @@ namespace chaiscript {
}; };
template<typename T> template<typename T>
struct Arity { struct Arity
}; {
};
template<typename Ret, typename ... Params>
struct Arity<Ret (Params...)>
{
static const size_t arity = sizeof...(Params);
};
template<typename Ret, typename... Params>
struct Arity<Ret(Params...)> {
static const size_t arity = sizeof...(Params);
};
template<typename T> template<typename T>
struct Function_Signature { struct Function_Signature
}; {
};
template<typename Ret, typename... Params> template<typename Ret, typename ... Params>
struct Function_Signature<Ret(Params...)> { struct Function_Signature<Ret (Params...)>
using Return_Type = Ret; {
using 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 Ret, typename T, typename... Params>
struct Function_Signature<Ret (T::*)(Params...) const> {
using Return_Type = Ret;
using Signature = Ret()(Params...);
};
template<typename T> template<typename T>
struct Callable_Traits { struct Callable_Traits
using Signature = typename Function_Signature<decltype(&T::operator())>::Signature; {
using Return_Type = typename Function_Signature<decltype(&T::operator())>::Return_Type; typedef typename Function_Signature<decltype(&T::operator())>::Signature Signature;
}; typedef typename Function_Signature<decltype(&T::operator())>::Return_Type Return_Type;
} // namespace detail };
} // namespace dispatch }
} // namespace chaiscript }
}
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -17,82 +14,113 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions;
namespace dispatch { namespace dispatch {
class Proxy_Function_Base; class Proxy_Function_Base;
} // namespace dispatch } // namespace dispatch
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript { namespace chaiscript
namespace dispatch { {
namespace dispatch
{
struct option_explicit_set : std::runtime_error { struct option_explicit_set : std::runtime_error {
explicit option_explicit_set(const std::string &t_param_name) option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") { : std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
{
} }
option_explicit_set(const option_explicit_set &) = default; option_explicit_set(const option_explicit_set &) = default;
~option_explicit_set() noexcept override = default; virtual ~option_explicit_set() CHAISCRIPT_NOEXCEPT {}
}; };
class Dynamic_Object { class Dynamic_Object
public: {
explicit Dynamic_Object(std::string t_type_name) public:
: m_type_name(std::move(t_type_name)) Dynamic_Object(std::string t_type_name)
, m_option_explicit(false) { : m_type_name(std::move(t_type_name)), m_option_explicit(false)
} {
Dynamic_Object() = default;
bool is_explicit() const noexcept { return m_option_explicit; }
void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; }
const std::string &get_type_name() const noexcept { return m_type_name; }
const Boxed_Value &operator[](const std::string &t_attr_name) const { 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]; }
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); Dynamic_Object() : m_type_name(""), m_option_explicit(false)
} {
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); bool is_explicit() const
} {
return m_option_explicit;
}
std::map<std::string, Boxed_Value> get_attrs() const { return m_attrs; } void set_explicit(const bool t_explicit)
{
m_option_explicit = t_explicit;
}
private: std::string get_type_name() const
const std::string m_type_name = ""; {
bool m_option_explicit = false; return m_type_name;
}
std::map<std::string, Boxed_Value> m_attrs; const Boxed_Value &operator[](const std::string &t_attr_name) const
{
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");
}
}
Boxed_Value &get_attr(const std::string &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
{
return m_attrs;
}
private:
std::string m_type_name;
bool m_option_explicit;
std::map<std::string, Boxed_Value> m_attrs;
}; };
} // namespace dispatch }
} // namespace chaiscript }
#endif #endif

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
@ -19,185 +19,235 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp" #include "boxed_cast_helper.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "dynamic_object.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "dynamic_object.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions;
namespace dispatch { namespace dispatch {
class Proxy_Function_Base; class Proxy_Function_Base;
} // namespace dispatch } // namespace dispatch
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript { namespace chaiscript
namespace dispatch { {
namespace detail { namespace dispatch
{
namespace detail
{
/// A Proxy_Function implementation designed for calling a function /// A Proxy_Function implementation designed for calling a function
/// that is automatically guarded based on the first param based on the /// that is automatically guarded based on the first param based on the
/// param's type name /// param's type name
class Dynamic_Object_Function final : public Proxy_Function_Base { class Dynamic_Object_Function : public Proxy_Function_Base
public: {
Dynamic_Object_Function(std::string t_type_name, const Proxy_Function &t_func, bool t_is_attribute = false) public:
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()) Dynamic_Object_Function(
, m_type_name(std::move(t_type_name)) std::string t_type_name,
, m_func(t_func) const Proxy_Function &t_func,
, m_doti(user_type<Dynamic_Object>()) bool t_is_attribute = false)
, m_is_attribute(t_is_attribute) { : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
assert((t_func->get_arity() > 0 || t_func->get_arity() < 0) m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>()),
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); m_is_attribute(t_is_attribute)
} {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
Dynamic_Object_Function(std::string t_type_name, const Proxy_Function &t_func, const Type_Info &t_ti, bool t_is_attribute = false) && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
: 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 noexcept 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 noexcept override { return m_is_attribute; } Dynamic_Object_Function(
std::string t_type_name,
bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { const Proxy_Function &t_func,
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) { const Type_Info &t_ti,
return m_func->call_match(vals, t_conversions); bool t_is_attribute = false)
} else { : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
return false; 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)");
} }
}
std::vector<Const_Proxy_Function> get_contained_functions() const override { return {m_func}; } virtual ~Dynamic_Object_Function() {}
protected: Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Boxed_Value do_call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) const override { Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
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 noexcept override { virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); {
} if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
{
private: return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
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 noexcept {
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 { } else {
return false; return false;
} }
} }
}
bool dynamic_object_typename_match(const chaiscript::Function_Params &bvs, virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return m_is_attribute; }
const std::string &name,
const std::unique_ptr<Type_Info> &ti, virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
const Type_Conversions_State &t_conversions) const noexcept { {
if (!bvs.empty()) { if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions); {
} else { return m_func->call_match(vals, t_conversions);
return false; } else {
return false;
}
} }
}
std::string m_type_name; virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
Proxy_Function m_func; {
std::unique_ptr<Type_Info> m_ti; return {m_func};
const Type_Info m_doti; }
const bool m_is_attribute;
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_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();
}
}
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const CHAISCRIPT_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.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;
std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti;
bool m_is_attribute;
}; };
/** /**
* A Proxy_Function implementation designed for creating a new * A Proxy_Function implementation designed for creating a new
* Dynamic_Object * Dynamic_Object
* that is automatically guarded based on the first param based on the * that is automatically guarded based on the first param based on the
* param's type name * param's type name
*/ */
class Dynamic_Object_Constructor final : public Proxy_Function_Base { class Dynamic_Object_Constructor : public Proxy_Function_Base
public: {
Dynamic_Object_Constructor(std::string t_type_name, const Proxy_Function &t_func) public:
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1) Dynamic_Object_Constructor(
, m_type_name(std::move(t_type_name)) std::string t_type_name,
, m_func(t_func) { const Proxy_Function &t_func)
assert((t_func->get_arity() > 0 || t_func->get_arity() < 0) : Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); m_type_name(std::move(t_type_name)), m_func(t_func)
} {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl) { && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
auto begin = tl.begin();
auto end = tl.end();
if (begin != end) {
++begin;
} }
return std::vector<Type_Info>(begin, end); static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
} {
auto begin = tl.begin();
auto end = tl.end();
bool operator==(const Proxy_Function_Base &f) const noexcept override { if (begin != end)
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); ++begin;
} }
bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const override { return std::vector<Type_Info>(begin, end);
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(chaiscript::Function_Params{new_vals}, t_conversions); virtual ~Dynamic_Object_Constructor() {}
}
protected: virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
Boxed_Value do_call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) const override { {
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
std::vector<Boxed_Value> new_params{bv}; return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
new_params.insert(new_params.end(), params.begin(), params.end()); }
(*m_func)(chaiscript::Function_Params{new_params}, t_conversions); virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_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 bv; return m_func->call_match(new_vals, t_conversions);
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_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:
std::string m_type_name;
Proxy_Function m_func;
private:
const std::string m_type_name;
const Proxy_Function m_func;
}; };
} // namespace detail }
} // namespace dispatch }
} // namespace chaiscript }
#endif #endif

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -16,28 +13,93 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
namespace chaiscript { namespace chaiscript {
namespace detail { class Boxed_Value;
struct Exception_Handler_Base { namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript
{
namespace detail
{
/// \todo make this a variadic template
struct Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0; virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
virtual ~Exception_Handler_Base() = default; virtual ~Exception_Handler_Base() {}
protected: protected:
template<typename T> template<typename T>
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) { static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
try { {
T t = t_engine.boxed_cast<T>(bv); try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
throw t;
} catch (const chaiscript::exception::bad_boxed_cast &) {
} }
}
}; };
template<typename... T> template<typename T1>
struct Exception_Handler_Impl : Exception_Handler_Base { struct Exception_Handler_Impl1 : Exception_Handler_Base
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override { (throw_type<T>(bv, t_engine), ...); } {
}; virtual ~Exception_Handler_Impl1() {}
} // namespace detail
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
}
};
template<typename T1, typename T2>
struct Exception_Handler_Impl2 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl2() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3>
struct Exception_Handler_Impl3 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl3() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4>
struct Exception_Handler_Impl4 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl4() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4, typename T5>
struct Exception_Handler_Impl5 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl5() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
throw_type<T5>(bv, t_engine);
}
};
}
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation /// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
/// ///
@ -49,8 +111,7 @@ namespace chaiscript {
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// ///
/// try { /// try {
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const /// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
/// std::exception &>());
/// } catch (const double e) { /// } catch (const double e) {
/// } catch (int) { /// } catch (int) {
/// } catch (float) { /// } catch (float) {
@ -75,7 +136,7 @@ namespace chaiscript {
/// ///
/// Similarly, if you are using the ChaiScript::eval form that unboxes the return value, then chaiscript::exception::bad_boxed_cast /// Similarly, if you are using the ChaiScript::eval form that unboxes the return value, then chaiscript::exception::bad_boxed_cast
/// should be handled as well. /// should be handled as well.
/// ///
/// \code /// \code
/// try { /// try {
/// chai.eval<int>("1.0", chaiscript::exception_specification<const std::exception &>()); /// chai.eval<int>("1.0", chaiscript::exception_specification<const std::exception &>());
@ -90,14 +151,49 @@ 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
using Exception_Handler = std::shared_ptr<detail::Exception_Handler_Base>; typedef std::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>());
} }
} // namespace chaiscript
/// \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>());
}
}
#endif #endif

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -17,25 +14,20 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "function_call_detail.hpp" #include "function_call_detail.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "callable_traits.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Value; class Boxed_Value;
class Type_Conversions_State; class Type_Conversions_State;
namespace detail { namespace detail {
template<typename T> template <typename T> struct Cast_Helper;
struct Cast_Helper; } // namespace detail
} // namespace detail } // namespace chaiscript
} // namespace chaiscript
namespace chaiscript {
namespace dispatch {
namespace detail {
template<typename Ret, typename... Param>
constexpr auto arity(Ret (*)(Param...)) noexcept {
return sizeof...(Param);
}
} // namespace detail
namespace chaiscript
{
namespace dispatch
{
/// Build a function caller that knows how to dispatch on a set of functions /// Build a function caller that knows how to dispatch on a set of functions
/// example: /// example:
/// std::function<void (int)> f = /// std::function<void (int)> f =
@ -43,19 +35,22 @@ namespace chaiscript {
/// \returns A std::function object for dispatching /// \returns A std::function object for dispatching
/// \param[in] funcs the set of functions to dispatch on. /// \param[in] funcs the set of functions to dispatch on.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) { std::function<FunctionType>
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), [](const Const_Proxy_Function &f) { functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions)
return f->get_arity() == -1 || size_t(f->get_arity()) == detail::arity(static_cast<FunctionType *>(nullptr)); {
}); const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
[](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) { if (!has_arity_match) {
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>)); 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);
} }
FunctionType *p = nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions);
}
/// Build a function caller for a particular Proxy_Function object /// Build a function caller for a particular Proxy_Function object
/// useful in the case that a function is being pass out from scripting back /// useful in the case that a function is being pass out from scripting back
/// into code /// into code
@ -68,55 +63,75 @@ namespace chaiscript {
/// \returns A std::function object for dispatching /// \returns A std::function object for dispatching
/// \param[in] func A function to execute. /// \param[in] func A function to execute.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) { std::function<FunctionType>
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions); functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions)
} {
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
}
/// Helper for automatically unboxing a Boxed_Value that contains a function object /// Helper for automatically unboxing a Boxed_Value that contains a function object
/// and creating a typesafe C++ function caller from it. /// and creating a typesafe C++ function caller from it.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) { std::function<FunctionType>
return functor<FunctionType>(boxed_cast<Const_Proxy_Function>(bv, t_conversions), t_conversions); functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions)
} {
} // namespace dispatch 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 std::function &
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> &> { struct Cast_Helper<const std::function<Signature> &>
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) { typedef std::function<Signature> Result_Type;
return dispatch::functor<Signature>(ob, t_conversions);
} else { static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions); {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
}
} }
} };
};
/// Cast helper to handle automatic casting to std::function /// Cast helper to handle automatic casting to std::function
template<typename Signature> template<typename Signature>
struct Cast_Helper<std::function<Signature>> { struct Cast_Helper<std::function<Signature> >
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) { typedef std::function<Signature> Result_Type;
return dispatch::functor<Signature>(ob, t_conversions);
} else { static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
return Cast_Helper_Inner<std::function<Signature>>::cast(ob, t_conversions); {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions);
}
} }
} };
};
/// Cast helper to handle automatic casting to const std::function /// Cast helper to handle automatic casting to const std::function
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature>> { struct Cast_Helper<const std::function<Signature> >
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) { typedef std::function<Signature> Result_Type;
return dispatch::functor<Signature>(ob, t_conversions);
} else { static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
return Cast_Helper_Inner<const std::function<Signature>>::cast(ob, t_conversions); {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions);
}
} }
} };
}; }
} // namespace detail }
} // namespace chaiscript
#endif #endif

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
@ -19,79 +16,152 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_number.hpp" #include "boxed_number.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "proxy_functions.hpp"
#include "type_conversions.hpp" #include "type_conversions.hpp"
#include "proxy_functions.hpp"
namespace chaiscript::dispatch::detail { namespace chaiscript
/// used internally for unwrapping a function call's types {
template<typename Ret, typename... Param> namespace dispatch
struct Build_Function_Caller_Helper { {
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions) namespace detail
: m_funcs(std::move(t_funcs))
, m_conversions(t_conversions) {
}
Ret call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_state) {
if constexpr (std::is_arithmetic_v<Ret> && !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Ret>>, bool>) {
return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as<Ret>();
} else if constexpr (std::is_same_v<void, Ret>) {
dispatch::dispatch(m_funcs, params, t_state);
} else {
return boxed_cast<Ret>(dispatch::dispatch(m_funcs, params, t_state), &t_state);
}
}
template<typename... P>
Ret operator()(P &&...param) {
std::array<Boxed_Value, sizeof...(P)> params{box<P>(std::forward<P>(param))...};
if (m_conversions) {
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
return call(chaiscript::Function_Params{params}, state);
} else {
Type_Conversions conv;
Type_Conversions_State state(conv, conv.conversion_saves());
return call(chaiscript::Function_Params{params}, state);
}
}
template<typename P, typename Q>
static Boxed_Value box(Q &&q) {
if constexpr (std::is_same_v<chaiscript::Boxed_Value, std::decay_t<Q>>) {
return std::forward<Q>(q);
} else if constexpr (std::is_reference_v<P>) {
return Boxed_Value(std::ref(std::forward<Q>(q)));
} else {
return Boxed_Value(std::forward<Q>(q));
}
}
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)
{ {
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi = /// Internal helper class for handling the return
std::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (Params...)> > /// value of a build_function_caller
(funcs[0]); template<typename Ret, bool is_arithmetic>
struct Function_Caller_Ret
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{
if (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);
}
}
};
if (pfi) /**
{ * Specialization for arithmetic return types
return pfi->internal_function(); */
} template<typename Ret>
// looks like this either wasn't a Proxy_Function_Impl or the types didn't match struct Function_Caller_Ret<Ret, true>
// we cannot make any other guesses or assumptions really, so continuing {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{
if (t_conversions) {
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>();
}
}
};
/**
* Specialization for void return types
*/
template<>
struct Function_Caller_Ret<void, false>
{
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{
if (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);
}
}
};
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret, typename ... Param>
struct Build_Function_Caller_Helper
{
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)
{
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
std::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (Params...)> >
(funcs[0]);
if (pfi)
{
return pfi->internal_function();
}
// 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
}
*/
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?t_conversions->get():nullptr));
}
} }
*/
return std::function<Ret(Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions ? t_conversions->get() : nullptr));
} }
} // namespace chaiscript::dispatch::detail }
#endif #endif

View File

@ -1,67 +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_FUNCTION_PARAMS_HPP
#define CHAISCRIPT_FUNCTION_PARAMS_HPP
#include "boxed_value.hpp"
namespace chaiscript {
class Function_Params {
public:
constexpr Function_Params(const Boxed_Value *const t_begin, const Boxed_Value *const t_end)
: m_begin(t_begin)
, m_end(t_end) {
}
explicit Function_Params(const Boxed_Value &bv)
: m_begin(&bv)
, m_end(m_begin + 1) {
}
explicit Function_Params(const std::vector<Boxed_Value> &vec)
: m_begin(vec.empty() ? nullptr : &vec.front())
, m_end(vec.empty() ? nullptr : &vec.front() + vec.size()) {
}
template<size_t Size>
constexpr explicit Function_Params(const std::array<Boxed_Value, Size> &a)
: m_begin(&a.front())
, m_end(&a.front() + Size) {
}
[[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { return m_begin[t_i]; }
[[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { return m_begin; }
[[nodiscard]] constexpr const Boxed_Value &front() const noexcept { return *m_begin; }
[[nodiscard]] constexpr const Boxed_Value *end() const noexcept { return m_end; }
[[nodiscard]] constexpr std::size_t size() const noexcept { return std::size_t(m_end - m_begin); }
[[nodiscard]] std::vector<Boxed_Value> to_vector() const { return std::vector<Boxed_Value>{m_begin, m_end}; }
[[nodiscard]] constexpr bool empty() const noexcept { return m_begin == m_end; }
private:
const Boxed_Value *m_begin = nullptr;
const Boxed_Value *m_end = nullptr;
};
// Constructor specialization for array of size 0
template<>
constexpr Function_Params::Function_Params(const std::array<Boxed_Value, size_t{0}> & /* a */)
: m_begin(nullptr)
, m_end(nullptr) {
}
} // namespace chaiscript
#endif

View File

@ -1,149 +0,0 @@
#ifndef CHAISCRIPT_FUNCTION_SIGNATURE_HPP
#define CHAISCRIPT_FUNCTION_SIGNATURE_HPP
#include <type_traits>
namespace chaiscript::dispatch::detail {
template<typename... Param>
struct Function_Params {
};
template<typename Ret, typename Params, bool IsNoExcept = false, bool IsMember = false, bool IsMemberObject = false, bool IsObject = false>
struct Function_Signature {
using Param_Types = Params;
using Return_Type = Ret;
constexpr static const bool is_object = IsObject;
constexpr static const bool is_member_object = IsMemberObject;
constexpr static const bool is_noexcept = IsNoExcept;
template<typename T>
constexpr Function_Signature(T &&) noexcept {
}
constexpr Function_Signature() noexcept = default;
};
// Free functions
template<typename Ret, typename... Param>
Function_Signature(Ret (*f)(Param...)) -> Function_Signature<Ret, Function_Params<Param...>>;
template<typename Ret, typename... Param>
Function_Signature(Ret (*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Param...>, true>;
// no reference specifier
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile noexcept)
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const noexcept)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...)) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
// & reference specifier
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &noexcept)
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &noexcept)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
// && reference specifier
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &&) -> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &&noexcept)
-> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &&)
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &&noexcept)
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &&) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &&noexcept) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &&) -> Function_Signature<Ret, Function_Params<const Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &&noexcept)
-> Function_Signature<Ret, Function_Params<const Class &&, Param...>, true, true>;
template<typename Ret, typename Class>
Function_Signature(Ret Class::*f) -> Function_Signature<Ret, Function_Params<Class &>, true, true, true>;
// primary template handles types that have no nested ::type member:
template<class, class = std::void_t<>>
struct has_call_operator : std::false_type {
};
// specialization recognizes types that do have a nested ::type member:
template<class T>
struct has_call_operator<T, std::void_t<decltype(&T::operator())>> : std::true_type {
};
template<typename Func>
auto function_signature(const Func &f) {
if constexpr (has_call_operator<Func>::value) {
return Function_Signature<typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Return_Type,
typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Param_Types,
decltype(Function_Signature{&std::decay_t<Func>::operator()})::is_noexcept,
false,
false,
true>{};
} else {
return Function_Signature{f};
}
}
} // namespace chaiscript::dispatch::detail
#endif

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -18,178 +15,282 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Number; class Boxed_Number;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript { namespace chaiscript
namespace dispatch { {
template<class T, class U> namespace dispatch
class Proxy_Function_Callable_Impl; {
template<class T> template<class T, class U> class Proxy_Function_Callable_Impl;
class Assignable_Proxy_Function_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, typename = typename std::enable_if_t<std::is_trivial_v<typename std::decay_t<T>>>> {
static Boxed_Value handle(T r) { template<typename T,
return Boxed_Value(std::move(r), true); 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);
}
template<typename T, typename = typename std::enable_if_t<!(std::is_trivial_v<typename std::decay_t<T>>)>> template<typename T,
static Boxed_Value handle(T &&r) { typename = typename std::enable_if<!std::is_pod<typename std::decay<T>::type>::value>::type>
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true); static Boxed_Value handle(T &&r)
} {
}; return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::function<Ret> &> { struct Handle_Return<const std::function<Ret> &>
static Boxed_Value handle(const std::function<Ret> &f) { {
return Boxed_Value( static Boxed_Value handle(const std::function<Ret> &f) {
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)); return Boxed_Value(
} chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
}; );
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &> { struct Handle_Return<std::function<Ret>>
}; {
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>>> { struct Handle_Return<const std::shared_ptr<std::function<Ret>>>
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) { {
return Boxed_Value( static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f), f)); return Boxed_Value(
} chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
}; );
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>> { struct Handle_Return<const std::shared_ptr<std::function<Ret>> &>
}; {
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>> { struct Handle_Return<std::shared_ptr<std::function<Ret>>>
}; {
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<std::function<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>>( static Boxed_Value handle(std::function<Ret> &f) {
std::ref(f), std::shared_ptr<std::function<Ret>>())); 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) { static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value( return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)); chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
} );
}; }
};
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret *&> { struct Handle_Return<Ret *&>
static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); } {
}; static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret *&> { struct Handle_Return<const Ret *&>
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); } {
}; static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret *> { struct Handle_Return<Ret *>
static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); } {
}; static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret *> { struct Handle_Return<const Ret *>
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); } {
}; static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &> { struct Handle_Return<std::shared_ptr<Ret> &>
static Boxed_Value handle(const std::shared_ptr<Ret> &r) { return Boxed_Value(r, true); } {
}; static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> { struct Handle_Return<std::shared_ptr<Ret> >
}; {
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &> { struct Handle_Return<const std::shared_ptr<Ret> &>
}; {
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &> { struct Handle_Return<const Ret &>
static Boxed_Value handle(std::unique_ptr<Ret> &&r) { return Boxed_Value(std::move(r), true); } {
}; static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r), true);
}
};
template<typename Ret, bool Ptr>
struct Handle_Return_Ref {
template<typename T>
static Boxed_Value handle(T &&r) {
return Boxed_Value(std::cref(r), true);
}
};
template<typename Ret>
struct Handle_Return_Ref<Ret, true> {
template<typename T>
static Boxed_Value handle(T &&r) {
return Boxed_Value(typename std::remove_reference<decltype(r)>::type{r}, true);
}
};
template<typename Ret>
struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> {
};
template<typename Ret>
struct Handle_Return<const Ret> {
static Boxed_Value handle(Ret r) { return Boxed_Value(std::move(r)); }
};
template<typename Ret>
struct Handle_Return<Ret &> {
static Boxed_Value handle(Ret &r) { return Boxed_Value(std::ref(r)); }
};
template<>
struct Handle_Return<Boxed_Value> {
static Boxed_Value handle(const Boxed_Value &r) noexcept { return r; }
};
template<>
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> {
};
template<>
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> {
};
template<>
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value> {
};
/** /**
* 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<> template<typename Ret>
struct Handle_Return<Boxed_Number> { struct Handle_Return<Ret &>
static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; } {
}; static Boxed_Value handle(Ret &r)
{
return Boxed_Value(std::ref(r));
}
template<> static Boxed_Value handle(const Ret &r)
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number> { {
}; return Boxed_Value(std::cref(r));
}
};
/** /**
* 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<> template<>
struct Handle_Return<void> { struct Handle_Return<Boxed_Value>
static Boxed_Value handle() { return void_var(); } {
}; static Boxed_Value handle(const Boxed_Value &r)
} // namespace detail {
} // namespace dispatch return r;
} // namespace chaiscript }
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
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<>
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<>
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<>
struct Handle_Return<Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<const Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<void>
{
static Boxed_Value handle()
{
return Boxed_Value(Boxed_Value::Void_Type());
}
};
}
}
}
#endif #endif

View File

@ -1,184 +1,465 @@
// 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-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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 "../chaiscript_defines.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "register_function.hpp" #include "register_function.hpp"
namespace chaiscript::bootstrap::operators { namespace chaiscript
template<typename T> {
void assign(Module &m) { namespace bootstrap
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs = rhs; }), "="); {
} namespace operators
{
namespace detail
{
/// \todo make this return a decltype once we drop gcc 4.6
template<typename L, typename R>
auto assign(L l, R r) -> L&
{
return (l = r);
}
template<typename T> template<typename L, typename R>
void assign_bitwise_and(Module &m) { auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs &= rhs; }), "&="); {
} return (l &= r);
}
template<typename T> template<typename L, typename R>
void assign_xor(Module &m) { auto assign_xor(L l, R r) -> decltype((l^=r))
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs ^= rhs; }), "^="); {
} return (l ^= r);
}
template<typename T> template<typename L, typename R>
void assign_bitwise_or(Module &m) { auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs |= rhs; }), "|="); {
} return (l |= r);
}
template<typename T> template<typename L, typename R>
void assign_difference(Module &m) { auto assign_difference(L l, R r) -> decltype(( l -= r))
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs -= rhs; }), "-="); {
} return (l -= r);
}
template<typename T> template<typename L, typename R>
void assign_left_shift(Module &m) { auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "<<="); {
} return (l <<= r);
}
template<typename T> template<typename L, typename R>
void assign_product(Module &m) { auto assign_product(L l, R r) -> decltype(( l *= r ))
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "*="); {
} return (l *= r);
}
template<typename T> template<typename L, typename R>
void assign_quotient(Module &m) { auto assign_quotient(L l, R r) -> decltype(( l /= r ))
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs /= rhs; }), "/="); {
} return (l /= r);
}
template<typename T> template<typename L, typename R>
void assign_remainder(Module &m) { auto assign_remainder(L l, R r) -> decltype(( l %= r ))
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs %= rhs; }), "%="); {
} return (l %= r);
}
template<typename T> template<typename L, typename R>
void assign_right_shift(Module &m) { auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs >>= rhs; }), ">>="); {
} return (l >>= r);
}
template<typename T> /// \todo make this return a decltype once we drop gcc 4.6
void assign_sum(Module &m) { template<typename L, typename R>
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs += rhs; }), "+="); auto assign_sum(L l, R r) -> L&
} {
return (l += r);
}
template<typename T> template<typename L>
void prefix_decrement(Module &m) { auto prefix_decrement(L l) -> decltype(( --l ))
m.add(chaiscript::fun([](T &lhs) -> T & { return --lhs; }), "--"); {
} return (--l);
}
template<typename T> template<typename L>
void prefix_increment(Module &m) { auto prefix_increment(L l) -> decltype(( ++l ))
m.add(chaiscript::fun([](T &lhs) -> T & { return ++lhs; }), "++"); {
} return (++l);
}
template<typename T> template<typename L, typename R>
void equal(Module &m) { auto equal(L l, R r) -> decltype(( l == r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs == rhs; }), "=="); {
} return (l == r);
}
template<typename T> template<typename L, typename R>
void greater_than(Module &m) { auto greater_than(L l, R r) -> decltype(( l > r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs > rhs; }), ">"); {
} return (l > r);
}
template<typename T> template<typename L, typename R>
void greater_than_equal(Module &m) { auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >= rhs; }), ">="); {
} return (l >= r);
}
template<typename T> template<typename L, typename R>
void less_than(Module &m) { auto less_than(L l, R r) -> decltype(( l < r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs < rhs; }), "<"); {
} return (l < r);
}
template<typename T> template<typename L, typename R>
void less_than_equal(Module &m) { auto less_than_equal(L l, R r) -> decltype(( l <= r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs <= rhs; }), "<="); {
} return (l <= r);
}
template<typename T> template<typename L>
void logical_compliment(Module &m) { auto logical_compliment(L l) -> decltype(( !l ))
m.add(chaiscript::fun([](const T &lhs) { return !lhs; }), "!"); {
} return (!l);
}
template<typename T> template<typename L, typename R>
void not_equal(Module &m) { auto not_equal(L l, R r) -> decltype(( l != r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs != rhs; }), "!="); {
} return (l != r);
}
template<typename T> template<typename L, typename R>
void addition(Module &m) { auto addition(L l, R r) -> decltype(( l + r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs + rhs; }), "+"); {
} return (l + r);
}
template<typename T> template<typename L>
void unary_plus(Module &m) { auto unary_plus(L l) -> decltype(( +l ))
m.add(chaiscript::fun([](const T &lhs) { return +lhs; }), "+"); {
} return (+l);
}
template<typename T> template<typename L, typename R>
void subtraction(Module &m) { auto subtraction(L l, R r) -> decltype(( l - r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs - rhs; }), "-"); {
} return (l - r);
}
template<typename T> template<typename L>
void unary_minus(Module &m) { auto unary_minus(L l) -> decltype(( -l ))
m.add(chaiscript::fun([](const T &lhs) { return -lhs; }), "-"); {
} #ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4146)
return (-l);
#pragma warning(pop)
#else
return (-l);
#endif
}
template<typename T> template<typename L, typename R>
void bitwise_and(Module &m) { auto bitwise_and(L l, R r) -> decltype(( l & r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs & rhs; }), "&"); {
} return (l & r);
}
template<typename T> template<typename L>
void bitwise_compliment(Module &m) { auto bitwise_compliment(L l) -> decltype(( ~l ))
m.add(chaiscript::fun([](const T &lhs) { return ~lhs; }), "~"); {
} return (~l);
}
template<typename T> template<typename L, typename R>
void bitwise_xor(Module &m) { auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs ^ rhs; }), "^"); {
} return (l ^ r);
}
template<typename T> template<typename L, typename R>
void bitwise_or(Module &m) { auto bitwise_or(L l, R r) -> decltype(( l | r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs | rhs; }), "|"); {
} return (l | r);
}
template<typename T> template<typename L, typename R>
void division(Module &m) { auto division(L l, R r) -> decltype(( l / r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs / rhs; }), "/"); {
} return (l / r);
}
template<typename T> template<typename L, typename R>
void left_shift(Module &m) { auto left_shift(L l, R r) -> decltype(( l << r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs << rhs; }), "<<"); {
} return l << r;
}
template<typename T> template<typename L, typename R>
void multiplication(Module &m) { auto multiplication(L l, R r) -> decltype(( l * r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs * rhs; }), "*"); {
} return l * r;
}
template<typename T> template<typename L, typename R>
void remainder(Module &m) { auto remainder(L l, R r) -> decltype(( l % r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs % rhs; }), "%"); {
} return (l % r);
}
template<typename T> template<typename L, typename R>
void right_shift(Module &m) { auto right_shift(L l, R r) -> decltype(( l >> r ))
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >> rhs; }), ">>"); {
return (l >> r);
}
}
template<typename T>
ModulePtr assign(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
return m;
}
template<typename T>
ModulePtr assign_bitwise_and(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
return m;
}
template<typename T>
ModulePtr assign_xor(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
return m;
}
template<typename T>
ModulePtr assign_bitwise_or(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
return m;
}
template<typename T>
ModulePtr assign_difference(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
return m;
}
template<typename T>
ModulePtr assign_left_shift(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
return m;
}
template<typename T>
ModulePtr assign_product(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
return m;
}
template<typename T>
ModulePtr assign_quotient(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
return m;
}
template<typename T>
ModulePtr assign_remainder(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
return m;
}
template<typename T>
ModulePtr assign_right_shift(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
return m;
}
template<typename T>
ModulePtr assign_sum(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
return m;
}
template<typename T>
ModulePtr prefix_decrement(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
return m;
}
template<typename T>
ModulePtr prefix_increment(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
return m;
}
template<typename T>
ModulePtr equal(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
return m;
}
template<typename T>
ModulePtr greater_than(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
return m;
}
template<typename T>
ModulePtr greater_than_equal(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
return m;
}
template<typename T>
ModulePtr less_than(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
return m;
}
template<typename T>
ModulePtr less_than_equal(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
return m;
}
template<typename T>
ModulePtr logical_compliment(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
return m;
}
template<typename T>
ModulePtr not_equal(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
return m;
}
template<typename T>
ModulePtr addition(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
return m;
}
template<typename T>
ModulePtr unary_plus(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
return m;
}
template<typename T>
ModulePtr subtraction(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
return m;
}
template<typename T>
ModulePtr unary_minus(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
return m;
}
template<typename T>
ModulePtr bitwise_and(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
return m;
}
template<typename T>
ModulePtr bitwise_compliment(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
return m;
}
template<typename T>
ModulePtr bitwise_xor(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
return m;
}
template<typename T>
ModulePtr bitwise_or(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
return m;
}
template<typename T>
ModulePtr division(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
return m;
}
template<typename T>
ModulePtr left_shift(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
return m;
}
template<typename T>
ModulePtr multiplication(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
return m;
}
template<typename T>
ModulePtr remainder(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
return m;
}
template<typename T>
ModulePtr right_shift(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
return m;
}
}
} }
} // namespace chaiscript::bootstrap::operators }
#endif #endif

View File

@ -1,41 +1,38 @@
// 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-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
namespace chaiscript::dispatch::detail { namespace chaiscript
template<typename Class, typename... Params> {
Proxy_Function build_constructor_(Class (*)(Params...)) { namespace dispatch
if constexpr (!std::is_copy_constructible_v<Class>) { {
auto call = [](auto &&...param) { return std::make_shared<Class>(std::forward<decltype(param)>(param)...); }; namespace detail
{
return Proxy_Function( template<typename Class, typename ... Params >
chaiscript::make_shared<dispatch::Proxy_Function_Base, Proxy_Function build_constructor_(Class (*)(Params...))
dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class>(Params...), decltype(call)>>(call)); {
} else if constexpr (true) { auto call = dispatch::detail::Constructor<Class, Params...>();
auto call = [](auto &&...param) { return Class(std::forward<decltype(param)>(param)...); };
return Proxy_Function( return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Class(Params...), decltype(call)>>( chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
call)); }
} }
} }
} // namespace chaiscript::dispatch::detail
namespace chaiscript {
/// \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, ...)
/// ///
/// Example: /// Example:
/// \code /// \code
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
@ -44,10 +41,13 @@ namespace chaiscript {
/// chai.add(constructor<MyClass (int, float)>(), "MyClass"); /// chai.add(constructor<MyClass (int, float)>(), "MyClass");
/// \endcode /// \endcode
template<typename T> template<typename T>
Proxy_Function constructor() { Proxy_Function constructor()
T *f = nullptr; {
return (dispatch::detail::build_constructor_(f)); T *f = nullptr;
} return (dispatch::detail::build_constructor_(f));
} // namespace chaiscript }
}
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,12 @@
// 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-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#include <array>
#include <functional> #include <functional>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
@ -18,94 +14,262 @@
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "function_params.hpp"
#include "handle_return.hpp" #include "handle_return.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "callable_traits.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions_State; class Type_Conversions_State;
namespace exception { namespace exception {
class bad_boxed_cast; class bad_boxed_cast;
} // namespace exception } // namespace exception
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript { namespace chaiscript
namespace exception { {
namespace exception
{
/** /**
* Exception thrown when there is a mismatch in number of * Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution * parameters during Proxy_Function execution
*/ */
struct arity_error : std::range_error { struct arity_error : std::range_error
{
arity_error(int t_got, int t_expected) arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch") : std::range_error("Function dispatch arity mismatch"),
, got(t_got) got(t_got), expected(t_expected)
, expected(t_expected) { {
} }
arity_error(const arity_error &) = default; arity_error(const arity_error &) = default;
~arity_error() noexcept override = default; virtual ~arity_error() CHAISCRIPT_NOEXCEPT {}
int got; int got;
int expected; int expected;
}; };
} // namespace exception }
namespace dispatch { namespace dispatch
namespace detail { {
namespace detail
{
/** /**
* 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, typename ... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) { std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
/// \note somehow this is responsible for a large part of the code generation {
return {user_type<Ret>(), user_type<Params>()...}; /// \note somehow this is responsible for a large part of the code generation
} return { user_type<Ret>(), user_type<Params>()... };
}
#ifdef CHAISCRIPT_GCC_4_6
/// \todo REMOVE THIS WHEN WE DROP G++4.6
// Forward declaration
template<typename ... Rest>
struct Try_Cast;
template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...>
{
static void do_try(const std::vector<Boxed_Value> &params, size_t generation, const Type_Conversions_State &t_conversions)
{
boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
}
};
// 0th case
template<>
struct Try_Cast<>
{
static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions_State &)
{
}
};
/** /**
* Used by Proxy_Function_Impl to determine if it is equivalent to another * Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent * Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures * registration of two functions with the exact same signatures
*/ */
template<typename Ret, typename... Params> template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...), const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) noexcept { bool compare_types_cast(Ret (*)(Params...),
try { const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
std::vector<Boxed_Value>::size_type i = 0; {
(boxed_cast<Params>(params[i++], &t_conversions), ...); try {
Try_Cast<Params...>::do_try(params, 0, t_conversions);
} catch (const exception::bad_boxed_cast &) {
return false;
}
return true; return true;
} catch (const exception::bad_boxed_cast &) {
return false;
} }
}
template<typename Callable, typename Ret, typename... Params, size_t... I> template<typename Ret, int count, typename ... Params>
Ret call_func(Ret (*)(Params...), struct Call_Func
std::index_sequence<I...>, {
const Callable &f,
[[maybe_unused]] const chaiscript::Function_Params &params,
[[maybe_unused]] const Type_Conversions_State &t_conversions) {
return f(boxed_cast<Params>(params[I], &t_conversions)...);
}
/// Used by Proxy_Function_Impl to perform typesafe execution of a function. template<typename Callable, typename ... InnerParams>
/// The function attempts to unbox each parameter to the expected type. static Ret do_call(const Callable &f,
/// if any unboxing fails the execution of the function fails and const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions, InnerParams &&... innerparams)
/// the bad_boxed_cast is passed up to the caller. {
template<typename Callable, typename Ret, typename... Params> return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
Boxed_Value }
call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) { };
if constexpr (std::is_same_v<Ret, void>) {
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions); template<typename Ret, typename ... Params>
return Handle_Return<void>::handle(); struct Call_Func<Ret, 0, Params...>
} else { {
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions)); #ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4100) /// Disable unreferenced formal parameter warning, which only shows up in MSVC I don't think there's any way around it \todo evaluate this
#endif
template<typename Callable, typename ... InnerParams>
static Ret do_call(const Callable &f,
const std::vector<Boxed_Value> &, const Type_Conversions_State &t_conversions, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
};
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each parameter to the expected type.
* if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Callable, typename Ret, typename ... Params>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
if (params.size() == sizeof...(Params))
{
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params, t_conversions);
}
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
} }
}
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
#else
template<size_t ... I>
struct Indexes
{
};
template<size_t S, size_t ... I>
struct Make_Indexes
{
typedef typename Make_Indexes<S-1, I..., sizeof...(I)>::indexes indexes;
};
template<size_t ... I>
struct Make_Indexes<0, I...>
{
typedef Indexes<I...> indexes;
};
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret, typename ... Params, size_t ... I>
bool compare_types_cast(Indexes<I...>, Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
try {
(void)params; (void)t_conversions;
(void)std::initializer_list<int>{(boxed_cast<Params>(params[I], &t_conversions), 0)...};
return true;
} catch (const exception::bad_boxed_cast &) {
return false;
}
}
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*f)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
return compare_types_cast(indexes(), f, params, t_conversions);
}
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, Indexes<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>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
return call_func(sig, indexes(), f, params, t_conversions);
}
#endif
}
}
}
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
template<typename Ret>
struct Do_Call
{
template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions));
}
};
template<>
struct Do_Call<void>
{
template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
call_func(Function_Signature<Signature>(), fun, params, t_conversions);
return Handle_Return<void>::handle();
}
};
}
}
}
#endif #endif

View File

@ -1,61 +1,19 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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 <type_traits>
#include "bind_first.hpp" #include "bind_first.hpp"
#include "function_signature.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
namespace chaiscript { namespace chaiscript
namespace dispatch::detail { {
template<typename Obj, typename Param1, typename... Rest>
Param1 get_first_param(Function_Params<Param1, Rest...>, Obj &&obj) {
return static_cast<Param1>(std::forward<Obj>(obj));
}
template<typename Func, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject, bool Is_Object, typename Ret, typename... Param>
auto make_callable_impl(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) {
if constexpr (Is_MemberObject) {
// we now that the Param pack will have only one element, so we are safe expanding it here
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<Ret, std::decay_t<Param>...>>(
std::forward<Func>(func)));
} else if constexpr (Is_Member) {
// TODO some kind of bug is preventing forwarding of this noexcept for the lambda
auto call = [func = std::forward<Func>(func)](auto &&obj, auto &&...param) /* noexcept(Is_Noexcept) */ -> decltype(auto) {
return ((get_first_param(Function_Params<Param...>{}, obj).*func)(std::forward<decltype(param)>(param)...));
};
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), decltype(call)>>(
std::move(call)));
} else {
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), std::decay_t<Func>>>(
std::forward<Func>(func)));
}
}
// this version peels off the function object itself from the function signature, when used
// on a callable object
template<typename Func, typename Ret, typename Object, typename... Param, bool Is_Noexcept>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Object, Param...>, Is_Noexcept, false, false, true>) {
return make_callable_impl(std::forward<Func>(func), Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, false, false, true>{});
}
template<typename Func, typename Ret, typename... Param, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) {
return make_callable_impl(std::forward<Func>(func), fs);
}
} // namespace dispatch::detail
/// \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
@ -69,19 +27,62 @@ namespace chaiscript {
/// void memberfunction(); /// void memberfunction();
/// int memberdata; /// int memberdata;
/// }; /// };
/// ///
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(fun(&myfunction), "myfunction"); /// chai.add(fun(&myfunction), "myfunction");
/// chai.add(fun(&MyClass::memberfunction), "memberfunction"); /// chai.add(fun(&MyClass::memberfunction), "memberfunction");
/// chai.add(fun(&MyClass::memberdata), "memberdata"); /// chai.add(fun(&MyClass::memberdata), "memberdata");
/// \endcode /// \endcode
/// ///
/// \sa \ref adding_functions /// \sa \ref adding_functions
template<typename T> template<typename T>
Proxy_Function fun(T &&t) { Proxy_Function fun(const T &t)
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t)); {
} typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
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
@ -92,19 +93,48 @@ namespace chaiscript {
/// { /// {
/// void memberfunction(int); /// void memberfunction(int);
/// }; /// };
/// ///
/// 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, std::ref(obj)), "memberfunction");
/// \endcode /// \endcode
/// ///
/// \sa \ref adding_functions /// \sa \ref adding_functions
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(std::forward<T>(t), q));
}
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it
/// \param[in] t Function / member to expose
/// \param[in] q Value to bind to first parameter
/// \param[in] r Value to bind to second parameter
///
/// \b Example:
/// \code
/// struct MyClass
/// {
/// void memberfunction(int);
/// };
///
/// MyClass obj;
/// chaiscript::ChaiScript chai;
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
/// // memberfunction() will be equivalent to obj.memberfunction(1)
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
/// \endcode
///
/// \sa \ref adding_functions
template<typename T, typename Q, typename R>
Proxy_Function fun(T &&t, Q &&q, R &&r)
{
return fun(detail::bind_first(detail::bind_first(std::forward<T>(t), std::forward<Q>(q)), std::forward<R>(r)));
}
}
} // namespace chaiscript
#endif #endif

View File

@ -1,137 +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 <cassert>
#include <cstddef>
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

File diff suppressed because it is too large Load Diff

View File

@ -1,210 +1,260 @@
// 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-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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 <memory>
#include <string>
#include <type_traits> #include <type_traits>
#include <typeinfo> #include <typeinfo>
#include <string>
namespace chaiscript { namespace chaiscript
namespace detail { {
namespace detail
{
template<typename T> template<typename T>
struct Bare_Type { struct Bare_Type
using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type; {
}; typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
} // namespace detail };
}
/// \brief Compile time deduced information about a type /// \brief Compile time deduced information about a type
class Type_Info { class Type_Info
public: {
constexpr Type_Info(const bool t_is_const, public:
const bool t_is_reference, CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
const bool t_is_pointer, bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
const bool t_is_void, : m_type_info(t_ti), m_bare_type_info(t_bare_ti),
const bool t_is_arithmetic, m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag)
const std::type_info *t_ti, + (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
const std::type_info *t_bare_ti) noexcept + (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag)
: m_type_info(t_ti) + (static_cast<unsigned int>(t_is_void) << is_void_flag)
, m_bare_type_info(t_bare_ti) + (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag))
, m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag) + (static_cast<unsigned int>(t_is_reference) << is_reference_flag) {
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag) + (static_cast<unsigned int>(t_is_void) << is_void_flag)
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag)) {
}
constexpr Type_Info() noexcept = default;
bool operator<(const Type_Info &ti) const noexcept { return m_type_info->before(*ti.m_type_info); }
constexpr bool operator!=(const Type_Info &ti) const noexcept { return !(operator==(ti)); }
constexpr bool operator!=(const std::type_info &ti) const noexcept { return !(operator==(ti)); }
constexpr bool operator==(const Type_Info &ti) const noexcept {
return ti.m_type_info == m_type_info || *ti.m_type_info == *m_type_info;
}
constexpr bool operator==(const std::type_info &ti) const noexcept { return !is_undef() && (*m_type_info) == ti; }
constexpr bool bare_equal(const Type_Info &ti) const noexcept {
return 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 { return !is_undef() && (*m_bare_type_info) == ti; }
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; }
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; }
constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; }
constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; }
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; }
const char *name() const noexcept {
if (!is_undef()) {
return m_type_info->name();
} else {
return "";
} }
}
const char *bare_name() const noexcept { CHAISCRIPT_CONSTEXPR Type_Info()
if (!is_undef()) { : m_type_info(nullptr), m_bare_type_info(nullptr),
return m_bare_type_info->name(); m_flags(1 << is_undef_flag)
} else { {
return "";
} }
}
constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; } #if !defined(_MSC_VER) || _MSC_VER != 1800
Type_Info(Type_Info&&) = default;
Type_Info& operator=(Type_Info&&) = default;
#endif
private: Type_Info(const Type_Info&) = default;
struct Unknown_Type { Type_Info& operator=(const Type_Info&) = default;
};
const std::type_info *m_type_info = &typeid(Unknown_Type);
const std::type_info *m_bare_type_info = &typeid(Unknown_Type); CHAISCRIPT_CONSTEXPR bool operator<(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
static const int is_const_flag = 0; {
static const int is_reference_flag = 1; return m_type_info < ti.m_type_info;
static const int is_pointer_flag = 2; }
static const int is_void_flag = 3;
static const int is_arithmetic_flag = 4; CHAISCRIPT_CONSTEXPR bool operator!=(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
static const int is_undef_flag = 5; {
unsigned int m_flags = (1 << is_undef_flag); return !(operator==(ti));
}
CHAISCRIPT_CONSTEXPR bool operator!=(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{
return !(operator==(ti));
}
CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{
return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
}
CHAISCRIPT_CONSTEXPR bool operator==(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{
return m_type_info != nullptr && (*m_type_info) == ti;
}
CHAISCRIPT_CONSTEXPR bool bare_equal(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{
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);
}
CHAISCRIPT_CONSTEXPR bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{
return m_bare_type_info != nullptr
&& (*m_bare_type_info) == ti;
}
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_const_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_reference_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_void_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_undef_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_pointer_flag)) != 0; }
std::string name() const
{
if (m_type_info)
{
return m_type_info->name();
} else {
return "";
}
}
std::string bare_name() const
{
if (m_bare_type_info)
{
return m_bare_type_info->name();
} else {
return "";
}
}
CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const
{
return m_bare_type_info;
}
private:
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
unsigned int m_flags;
static const int is_const_flag = 0;
static const int is_reference_flag = 1;
static const int is_pointer_flag = 2;
static const int is_void_flag = 3;
static const int is_arithmetic_flag = 4;
static const int is_undef_flag = 5;
}; };
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
constexpr static Type_Info get() noexcept { {
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value, typedef T type;
std::is_reference<T>::value,
std::is_pointer<T>::value, static Type_Info get()
std::is_void<T>::value, {
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value) return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
&typeid(T), std::is_void<T>::value,
&typeid(typename Bare_Type<T>::type)); (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(typename Bare_Type<T>::type));
}
};
template<typename T> template<typename T>
struct Get_Type_Info<std::shared_ptr<T>> { struct Get_Type_Info<std::shared_ptr<T> >
constexpr static Type_Info get() noexcept { {
return Type_Info(std::is_const<T>::value, typedef T type;
std::is_reference<T>::value,
std::is_pointer<T>::value, static Type_Info get()
std::is_void<T>::value, {
std::is_arithmetic<T>::value return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_void<T>::value,
&typeid(std::shared_ptr<T>), std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(typename Bare_Type<T>::type)); &typeid(std::shared_ptr<T> ),
} &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<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>>
}; {
};
template<typename T> template<typename T>
struct Get_Type_Info<const std::shared_ptr<T> &> { struct Get_Type_Info<const std::shared_ptr<T> &>
constexpr static Type_Info get() noexcept { {
return Type_Info(std::is_const<T>::value, typedef T type;
std::is_reference<T>::value,
std::is_pointer<T>::value, static Type_Info get()
std::is_void<T>::value, {
std::is_arithmetic<T>::value return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_void<T>::value,
&typeid(const std::shared_ptr<T> &), std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(typename Bare_Type<T>::type)); &typeid(const std::shared_ptr<T> &),
} &typeid(typename Bare_Type<T>::type));
}; }
};
template<typename T> template<typename T>
struct Get_Type_Info<std::reference_wrapper<T>> { struct Get_Type_Info<std::reference_wrapper<T> >
constexpr static Type_Info get() noexcept { {
return Type_Info(std::is_const<T>::value, typedef T type;
std::is_reference<T>::value,
std::is_pointer<T>::value, static Type_Info get()
std::is_void<T>::value, {
std::is_arithmetic<T>::value return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_void<T>::value,
&typeid(std::reference_wrapper<T>), std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(typename Bare_Type<T>::type)); &typeid(std::reference_wrapper<T> ),
} &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 std::reference_wrapper<T> &>
constexpr static Type_Info get() noexcept { {
return Type_Info(std::is_const<T>::value, typedef T type;
std::is_reference<T>::value,
std::is_pointer<T>::value,
std::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,
&typeid(const std::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
} // namespace detail static Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
}
/// \brief Creates a Type_Info object representing the type passed in /// \brief Creates a Type_Info object representing the type passed in
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter /// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
/// \return Type_Info for T /// \return Type_Info for T
/// ///
/// \b Example: /// \b Example:
/// \code /// \code
/// int i; /// int i;
/// 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*/) noexcept { Type_Info user_type(const T &/*t*/)
{
return detail::Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }
/// \brief Creates a Type_Info object representing the templated type /// \brief Creates a Type_Info object representing the templated type
/// \tparam T Type of object to get a Type_Info for /// \tparam T Type of object to get a Type_Info for
/// \return Type_Info for T /// \return Type_Info for T
/// ///
/// \b Example: /// \b Example:
/// \code /// \code
/// 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() noexcept { Type_Info user_type()
{
return detail::Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }
} // namespace chaiscript }
#endif #endif

View File

@ -1,167 +1,130 @@
// 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-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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/hash.hpp"
#include <string> #include <string>
namespace chaiscript { namespace chaiscript
{
struct Operators { struct Operators {
enum class Opers { enum Opers
equals, {
less_than, boolean_flag,
greater_than, equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
less_than_equal, non_const_flag,
greater_than_equal, assign, pre_increment, pre_decrement, assign_product, assign_sum,
not_equal, assign_quotient, assign_difference,
assign, non_const_int_flag,
pre_increment, assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right,
pre_decrement, assign_remainder, assign_bitwise_xor,
assign_product, const_int_flag,
assign_sum, shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement,
assign_quotient, const_flag,
assign_difference, sum, quotient, product, difference, unary_plus, unary_minus,
assign_bitwise_and,
assign_bitwise_or,
assign_shift_left,
assign_shift_right,
assign_remainder,
assign_bitwise_xor,
shift_left,
shift_right,
remainder,
bitwise_and,
bitwise_or,
bitwise_xor,
bitwise_complement,
sum,
quotient,
product,
difference,
unary_plus,
unary_minus,
invalid invalid
}; };
constexpr static const char *to_string(Opers t_oper) noexcept { static const char *to_string(Opers t_oper) {
constexpr const char *opers[] const char *opers[] = {
= {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""}; "",
return opers[static_cast<int>(t_oper)]; "==", "<", ">", "<=", ">=", "!=",
"",
"=", "++", "--", "*=", "+=",
"/=", "-=",
"",
"&=", "|=", "<<=", ">>=",
"%=", "^=",
"",
"<<", ">>", "%", "&", "|", "^", "~",
"",
"+", "/", "*", "-", "+", "-",
""
};
return opers[t_oper];
} }
constexpr static Opers to_operator(std::string_view t_str, bool t_is_unary = false) noexcept { static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
#ifdef CHAISCRIPT_MSVC {
#pragma warning(push) if (t_str == "==")
#pragma warning(disable : 4307) {
#endif return equals;
} else if (t_str == "<") {
const auto op_hash = utility::hash(t_str); return less_than;
switch (op_hash) { } else if (t_str == ">") {
case utility::hash("=="): { return greater_than;
return Opers::equals; } else if (t_str == "<=") {
return less_than_equal;
} else if (t_str == ">=") {
return greater_than_equal;
} else if (t_str == "!=") {
return not_equal;
} else if (t_str == "=") {
return assign;
} else if (t_str == "++") {
return pre_increment;
} else if (t_str == "--") {
return pre_decrement;
} else if (t_str == "*=") {
return assign_product;
} else if (t_str == "+=") {
return assign_sum;
} else if (t_str == "-=") {
return assign_difference;
} else if (t_str == "&=") {
return assign_bitwise_and;
} else if (t_str == "|=") {
return assign_bitwise_or;
} else if (t_str == "<<=") {
return assign_shift_left;
} else if (t_str == ">>=") {
return assign_shift_right;
} else if (t_str == "%=") {
return assign_remainder;
} else if (t_str == "^=") {
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;
} }
case utility::hash("<"): { } else if (t_str == "-") {
return Opers::less_than; if (t_is_unary) {
return unary_minus;
} else {
return difference;
} }
case utility::hash(">"): { } else if (t_str == "/") {
return Opers::greater_than; return quotient;
} } else if (t_str == "*") {
case utility::hash("<="): { return product;
return Opers::less_than_equal; } else {
} return invalid;
case utility::hash(">="): { }
return Opers::greater_than_equal;
}
case utility::hash("!="): {
return Opers::not_equal;
}
case utility::hash("="): {
return Opers::assign;
}
case utility::hash("++"): {
return Opers::pre_increment;
}
case utility::hash("--"): {
return Opers::pre_decrement;
}
case utility::hash("*="): {
return Opers::assign_product;
}
case utility::hash("+="): {
return Opers::assign_sum;
}
case utility::hash("-="): {
return Opers::assign_difference;
}
case utility::hash("&="): {
return Opers::assign_bitwise_and;
}
case utility::hash("|="): {
return Opers::assign_bitwise_or;
}
case utility::hash("<<="): {
return Opers::assign_shift_left;
}
case utility::hash(">>="): {
return Opers::assign_shift_right;
}
case utility::hash("%="): {
return Opers::assign_remainder;
}
case utility::hash("^="): {
return Opers::assign_bitwise_xor;
}
case utility::hash("<<"): {
return Opers::shift_left;
}
case utility::hash(">>"): {
return Opers::shift_right;
}
case utility::hash("%"): {
return Opers::remainder;
}
case utility::hash("&"): {
return Opers::bitwise_and;
}
case utility::hash("|"): {
return Opers::bitwise_or;
}
case utility::hash("^"): {
return Opers::bitwise_xor;
}
case utility::hash("~"): {
return Opers::bitwise_complement;
}
case utility::hash("+"): {
return t_is_unary ? Opers::unary_plus : Opers::sum;
}
case utility::hash("-"): {
return t_is_unary ? Opers::unary_minus : Opers::difference;
}
case utility::hash("/"): {
return Opers::quotient;
}
case utility::hash("*"): {
return Opers::product;
}
default: {
return Opers::invalid;
}
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
} }
}; };
} // namespace chaiscript }
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */ #endif /* _CHAISCRIPT_ALGEBRAIC_HPP */

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -22,280 +19,88 @@
#include "../dispatchkit/dispatchkit.hpp" #include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp" #include "../dispatchkit/type_info.hpp"
#include <unordered_set>
namespace chaiscript { namespace chaiscript {
struct AST_Node; struct AST_Node;
struct AST_Node_Trace; } // namespace chaiscript
namespace exception {
struct eval_error;
}
} // namespace chaiscript
namespace chaiscript { namespace chaiscript
struct Name_Validator { {
template<typename T>
static bool is_reserved_word(const T &s) noexcept {
const static std::unordered_set<std::uint32_t>
words{utility::hash("def"), utility::hash("fun"), utility::hash("while"), utility::hash("for"), utility::hash("if"), utility::hash("else"), utility::hash("&&"), utility::hash("||"), utility::hash(","), utility::hash("auto"), utility::hash("return"), utility::hash("break"), utility::hash("true"), utility::hash("false"), utility::hash("class"), utility::hash("attr"), utility::hash("var"), utility::hash("global"), utility::hash("GLOBAL"), utility::hash("_"), utility::hash("__LINE__"), utility::hash("__FILE__"), utility::hash("__FUNC__"), utility::hash("__CLASS__")};
return words.count(utility::hash(s)) == 1;
}
template<typename T>
static bool valid_object_name(const T &name) noexcept {
return name.find("::") == std::string::npos && !is_reserved_word(name);
}
template<typename T>
static void validate_object_name(const T &name) {
if (is_reserved_word(name)) {
throw exception::reserved_word_error(std::string(name));
}
if (name.find("::") != std::string::npos) {
throw exception::illegal_name_error(std::string(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.
using Create_Module_Func = ModulePtr (*)(); 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 { class AST_Node_Type {
Id, public:
Fun_Call, enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
Unused_Return_Fun_Call, Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Arg_List, Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Equation, Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
Var_Decl, Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl
Assign_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
}; };
enum class Operator_Precedence { namespace
Ternary_Cond, {
Logical_Or,
Logical_And,
Bitwise_Or,
Bitwise_Xor,
Bitwise_And,
Equality,
Comparison,
Shift,
Addition,
Multiplication,
Prefix
};
namespace {
/// Helper lookup to get the name of each node type /// Helper lookup to get the name of each node type
constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept { const char *ast_node_type_to_string(int ast_node_type) {
constexpr const char *const ast_node_types[] = {"Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_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"}; const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg"};
return ast_node_types[static_cast<int>(ast_node_type)]; return ast_node_types[ast_node_type];
} }
} // namespace }
/// \brief Convenience type for file positions /// \brief Convenience type for file positions
struct File_Position { struct File_Position {
int line = 0; int line;
int column = 0; int column;
constexpr File_Position(int t_file_line, int t_file_column) noexcept File_Position(int t_file_line, int t_file_column)
: line(t_file_line) : line(t_file_line), column(t_file_column) { }
, column(t_file_column) {
}
constexpr File_Position() noexcept = default; File_Position() : line(0), column(0) { }
}; };
struct Parse_Location { 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) Parse_Location(std::string t_fname="", const int t_start_line=0, const int t_start_col=0,
: start(t_start_line, t_start_col) const int t_end_line=0, const int t_end_col=0)
, end(t_end_line, t_end_col) : start(t_start_line, t_start_col),
, filename(std::make_shared<std::string>(std::move(t_fname))) { 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, Parse_Location(std::shared_ptr<std::string> t_fname, const int t_start_line=0, const int t_start_col=0,
const int t_start_line = 0, const int t_end_line=0, const int t_end_col=0)
const int t_start_col = 0, : start(t_start_line, t_start_col),
const int t_end_line = 0, end(t_end_line, t_end_col),
const int t_end_col = 0) filename(std::move(t_fname))
: start(t_start_line, t_start_col) {
, end(t_end_line, t_end_col)
, filename(std::move(t_fname)) {
} }
File_Position start; File_Position start;
File_Position end; File_Position end;
std::shared_ptr<std::string> filename; std::shared_ptr<std::string> filename;
}; };
/// \brief Struct that doubles as both a parser ast_node and an AST node.
struct AST_Node {
public:
const AST_Node_Type identifier;
const std::string text;
Parse_Location location;
const std::string &filename() const noexcept { return *location.filename; }
const File_Position &start() const noexcept { return location.start; }
const File_Position &end() const noexcept { return location.end; }
std::string pretty_print() const {
std::ostringstream oss;
oss << text;
for (auto &elem : get_children()) {
oss << elem.get().pretty_print() << ' ';
}
return oss.str();
}
virtual std::vector<std::reference_wrapper<AST_Node>> 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
std::string to_string(const std::string &t_prepend = "") const {
std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " << this->text << " : " << this->location.start.line
<< ", " << this->location.start.column << '\n';
for (auto &elem : get_children()) {
oss << elem.get().to_string(t_prepend + " ");
}
return oss.str();
}
static inline bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss);
virtual ~AST_Node() noexcept = default;
AST_Node(AST_Node &&) = default;
AST_Node &operator=(AST_Node &&) = delete;
AST_Node(const AST_Node &) = delete;
AST_Node &operator=(const AST_Node &) = delete;
protected:
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
: identifier(t_id)
, text(std::move(t_ast_node_text))
, location(std::move(t_loc)) {
}
};
/// \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
using AST_NodePtr = std::unique_ptr<AST_Node>; typedef std::shared_ptr<AST_Node> AST_NodePtr;
using AST_NodePtr_Const = std::unique_ptr<const AST_Node>; typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const;
struct AST_Node_Trace {
const AST_Node_Type identifier;
const std::string text;
Parse_Location location;
const std::string &filename() const noexcept { return *location.filename; }
const File_Position &start() const noexcept { return location.start; }
const File_Position &end() const noexcept { return location.end; }
std::string pretty_print() const {
std::ostringstream oss;
oss << text;
for (const auto &elem : children) {
oss << elem.pretty_print() << ' ';
}
return oss.str();
}
std::vector<AST_Node_Trace> get_children(const AST_Node &node) {
const auto node_children = node.get_children();
return std::vector<AST_Node_Trace>(node_children.begin(), node_children.end());
}
AST_Node_Trace(const AST_Node &node)
: identifier(node.identifier)
, text(node.text)
, location(node.location)
, children(get_children(node)) {
}
std::vector<AST_Node_Trace> children;
};
/// \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)
: std::runtime_error(t_reason) {
}
load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
: std::runtime_error(format_error(t_name, t_errors)) {
}
load_module_error(const load_module_error &) = default;
~load_module_error() noexcept override = default;
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors) {
std::stringstream ss;
ss << "Error loading module '" << t_name << "'\n"
<< " The following locations were searched:\n";
for (const auto &err : t_errors) {
ss << " " << err.what() << "\n";
}
return ss.str();
}
};
/// Errors generated during parsing or evaluation /// Errors generated during parsing or evaluation
struct eval_error : std::runtime_error { struct eval_error : std::runtime_error {
@ -303,57 +108,50 @@ namespace chaiscript {
File_Position start_position; File_Position start_position;
std::string filename; std::string filename;
std::string detail; std::string detail;
std::vector<AST_Node_Trace> call_stack; std::vector<AST_NodePtr_Const> call_stack;
eval_error(const std::string &t_why, eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const File_Position &t_where, const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
const std::string &t_fname, bool t_dot_notation,
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT :
const std::vector<chaiscript::Const_Proxy_Function> &t_functions, std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
bool t_dot_notation, reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept {}
: 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)) {
}
eval_error(const std::string &t_why, eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
const std::vector<chaiscript::Const_Proxy_Function> &t_functions, bool t_dot_notation,
bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT :
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)),
: std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)) reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss))
, reason(t_why) {}
, detail(format_detail(t_functions, t_dot_notation, t_ss)) {
}
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept
: std::runtime_error(format(t_why, t_where, t_fname))
, reason(t_why)
, start_position(t_where)
, filename(t_fname) {
}
explicit eval_error(const std::string &t_why) noexcept eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) CHAISCRIPT_NOEXCEPT :
: std::runtime_error("Error: \"" + t_why + "\" ") std::runtime_error(format(t_why, t_where, t_fname)),
, reason(t_why) { reason(t_why), start_position(t_where), filename(t_fname)
} {}
eval_error(const std::string &t_why) CHAISCRIPT_NOEXCEPT
: std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why)
{}
eval_error(const eval_error &) = default; 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]) << ")\n";
ss << '\n' ss << '\n' << detail << '\n';
<< detail << '\n';
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'"; ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
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 && id(call_stack[j]) != chaiscript::AST_Node_Type::File) { if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{
ss << '\n'; ss << '\n';
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]) << "'";
} }
@ -363,42 +161,54 @@ namespace chaiscript {
return ss.str(); return ss.str();
} }
~eval_error() noexcept override = default; virtual ~eval_error() CHAISCRIPT_NOEXCEPT {}
private: private:
template<typename T>
static AST_Node_Type id(const T &t) noexcept {
return t.identifier;
}
template<typename T> template<typename T>
static std::string pretty(const T &t) { static int id(const T& t)
return t.pretty_print(); {
} return t->identifier;
}
template<typename T> template<typename T>
static const std::string &fname(const T &t) noexcept { static std::string pretty(const T& t)
return t.filename(); {
} return t->pretty_print();
}
template<typename T> template<typename T>
static std::string startpos(const T &t) { static const std::string &fname(const T& t)
std::ostringstream oss; {
oss << t.start().line << ", " << t.start().column; return t->filename();
return oss.str(); }
template<typename T>
static std::string startpos(const T& t)
{
std::ostringstream oss;
oss << t->start().line << ", " << t->start().column;
return oss.str();
}
static std::string format_why(const std::string &t_why)
{
return "Error: \"" + t_why + "\"";
} }
static std::string format_why(const std::string &t_why) { return "Error: \"" + t_why + "\""; } static std::string format_types(const Const_Proxy_Function &t_func,
bool t_dot_notation,
static std::string format_types(const Const_Proxy_Function &t_func, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) { const chaiscript::detail::Dispatch_Engine &t_ss)
assert(t_func); {
int arity = t_func->get_arity(); int arity = t_func->get_arity();
std::vector<Type_Info> types = t_func->get_param_types(); std::vector<Type_Info> types = t_func->get_param_types();
std::string retval; std::string retval;
if (arity == -1) { if (arity == -1)
{
retval = "(...)"; retval = "(...)";
if (t_dot_notation) { if (t_dot_notation)
{
retval = "(Object)." + retval; retval = "(Object)." + retval;
} }
} else if (types.size() <= 1) { } else if (types.size() <= 1) {
@ -409,13 +219,18 @@ namespace chaiscript {
std::string paramstr; std::string paramstr;
for (size_t index = 1; index != types.size(); ++index) { for (size_t index = 1;
paramstr += (types[index].is_const() ? "const " : ""); index != types.size();
++index)
{
paramstr += (types[index].is_const()?"const ":"");
paramstr += t_ss.get_type_name(types[index]); paramstr += t_ss.get_type_name(types[index]);
if (index == 1 && t_dot_notation) { if (index == 1 && t_dot_notation)
{
paramstr += ").("; paramstr += ").(";
if (types.size() == 2) { if (types.size() == 2)
{
paramstr += ", "; paramstr += ", ";
} }
} else { } else {
@ -429,70 +244,93 @@ namespace chaiscript {
retval = ss.str(); retval = ss.str();
} }
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
if (dynfun && dynfun->has_parse_tree()) { std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
if (dynfun)
{
Proxy_Function f = dynfun->get_guard(); Proxy_Function f = dynfun->get_guard();
if (f) { if (f)
{
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f); auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
if (dynfunguard && dynfunguard->has_parse_tree()) { if (dynfunguard)
{
retval += " : " + format_guard(dynfunguard->get_parse_tree()); retval += " : " + format_guard(dynfunguard->get_parse_tree());
} }
} }
retval += "\n Defined at " + format_location(dynfun->get_parse_tree()); retval += "\n Defined at " + format_location(dynfun->get_parse_tree());
} }
return retval; return retval;
} }
template<typename T> template<typename T>
static std::string format_guard(const T &t) { static std::string format_guard(const T &t)
return t.pretty_print(); {
} return t->pretty_print();
}
template<typename T> template<typename T>
static std::string format_location(const T &t) { static std::string format_location(const T &t)
std::ostringstream oss; {
oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")"; if (t) {
return oss.str(); std::ostringstream oss;
} oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")";
return oss.str();
} else {
return "(internal)";
}
}
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions, static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) { const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss; std::stringstream ss;
if (t_functions.size() == 1) { if (t_functions.size() == 1)
assert(t_functions[0]); {
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) << '\n';
} else { } else {
ss << " " << t_functions.size() << " overloads available:\n"; ss << " " << t_functions.size() << " overloads available:\n";
for (const auto &t_function : t_functions) { for (const auto & t_function : t_functions)
{
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n'; ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
} }
} }
return ss.str(); return ss.str();
} }
static std::string static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
format_parameters(const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) { bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss; std::stringstream ss;
ss << "("; ss << "(";
if (!t_parameters.empty()) { if (!t_parameters.empty())
{
std::string paramstr; std::string paramstr;
for (auto itr = t_parameters.begin(); itr != t_parameters.end(); ++itr) { for (auto itr = t_parameters.begin();
paramstr += (itr->is_const() ? "const " : ""); itr != t_parameters.end();
++itr)
{
paramstr += (itr->is_const()?"const ":"");
paramstr += t_ss.type_name(*itr); paramstr += t_ss.type_name(*itr);
if (itr == t_parameters.begin() && t_dot_notation) { if (itr == t_parameters.begin() && t_dot_notation)
{
paramstr += ").("; paramstr += ").(";
if (t_parameters.size() == 1) { if (t_parameters.size() == 1)
{
paramstr += ", "; paramstr += ", ";
} }
} else { } else {
@ -507,10 +345,12 @@ namespace chaiscript {
return ss.str(); return ss.str();
} }
static std::string format_filename(const std::string &t_fname) { static std::string format_filename(const std::string &t_fname)
{
std::stringstream ss; std::stringstream ss;
if (t_fname != "__EVAL__") { if (t_fname != "__EVAL__")
{
ss << "in '" << t_fname << "' "; ss << "in '" << t_fname << "' ";
} else { } else {
ss << "during evaluation "; ss << "during evaluation ";
@ -519,18 +359,16 @@ namespace chaiscript {
return ss.str(); return ss.str();
} }
static std::string format_location(const File_Position &t_where) { static std::string format_location(const File_Position &t_where)
{
std::stringstream ss; std::stringstream ss;
ss << "at (" << t_where.line << ", " << t_where.column << ")"; ss << "at (" << t_where.line << ", " << t_where.column << ")";
return ss.str(); return ss.str();
} }
static std::string format(const std::string &t_why, static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const File_Position &t_where, const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss)
const std::string &t_fname, {
const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) {
std::stringstream ss; std::stringstream ss;
ss << format_why(t_why); ss << format_why(t_why);
@ -547,10 +385,11 @@ namespace chaiscript {
return ss.str(); return ss.str();
} }
static std::string format(const std::string &t_why, static std::string format(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) { const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss; std::stringstream ss;
ss << format_why(t_why); ss << format_why(t_why);
@ -562,7 +401,8 @@ namespace chaiscript {
return ss.str(); return ss.str();
} }
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) { static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname)
{
std::stringstream ss; std::stringstream ss;
ss << format_why(t_why); ss << format_why(t_why);
@ -577,125 +417,218 @@ namespace chaiscript {
} }
}; };
/// Errors generated when loading a file /// Errors generated when loading a file
struct file_not_found_error : std::runtime_error { struct file_not_found_error : std::runtime_error {
explicit file_not_found_error(const std::string &t_filename) file_not_found_error(const std::string &t_filename) CHAISCRIPT_NOEXCEPT
: std::runtime_error("File Not Found: " + t_filename) : std::runtime_error("File Not Found: " + t_filename)
, filename(t_filename) { { }
}
file_not_found_error(const file_not_found_error &) = default; file_not_found_error(const file_not_found_error &) = default;
~file_not_found_error() noexcept override = default; virtual ~file_not_found_error() CHAISCRIPT_NOEXCEPT {}
std::string filename;
}; };
} // namespace exception
//static
bool AST_Node::get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
try {
return t_ss->boxed_cast<bool>(t_bv);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("Condition not boolean");
}
} }
namespace parser {
class ChaiScript_Parser_Base { /// \brief Struct that doubles as both a parser ast_node and an AST node.
struct AST_Node : std::enable_shared_from_this<AST_Node> {
public: public:
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0; const int identifier; //< \todo shouldn't this be a strongly typed enum value?
virtual void debug_print(const AST_Node &t, std::string prepend = "") const = 0; const std::string text;
virtual void *get_tracer_ptr() = 0; Parse_Location location;
virtual ~ChaiScript_Parser_Base() = default; std::vector<AST_NodePtr> children;
ChaiScript_Parser_Base() = default; AST_NodePtr annotation;
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> const std::string &filename() const {
T &get_tracer() noexcept { return *location.filename;
// to do type check this somehow?
return *static_cast<T *>(get_tracer_ptr());
} }
protected: const File_Position &start() const {
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default; return location.start;
}; }
} // namespace parser
namespace eval { const File_Position &end() const {
namespace detail { return location.end;
}
virtual std::string pretty_print() const
{
std::ostringstream oss;
oss << text;
for (auto & elem : this->children) {
oss << elem->pretty_print();
}
return oss.str();
}
/// Prints the contents of an AST node, including its children, recursively
std::string to_string(const std::string &t_prepend = "") const {
std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
for (auto & elem : this->children) {
oss << elem->to_string(t_prepend + " ");
}
return oss.str();
}
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const
{
try {
return eval_internal(t_e);
} catch (exception::eval_error &ee) {
ee.call_stack.push_back(shared_from_this());
throw;
}
}
static bool get_bool_condition(const Boxed_Value &t_bv) {
try {
return boxed_cast<bool>(t_bv);
}
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("Condition not boolean");
}
}
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
{
std::replace(children.begin(), children.end(), t_child, t_new_child);
}
virtual ~AST_Node() {}
protected:
AST_Node(std::string t_ast_node_text, int t_id, Parse_Location t_loc,
std::vector<AST_NodePtr> t_children = std::vector<AST_NodePtr>()) :
identifier(t_id), text(std::move(t_ast_node_text)),
location(std::move(t_loc)),
children(std::move(t_children))
{
}
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
{
throw std::runtime_error("Undispatched ast_node (internal error)");
}
private:
// Copy and assignment explicitly unimplemented
AST_Node(const AST_Node &) = delete;
AST_Node& operator=(const AST_Node &) = delete;
};
namespace eval
{
namespace detail
{
/// Special type for returned values /// Special type for returned values
struct Return_Value { struct Return_Value {
Boxed_Value retval; Boxed_Value retval;
Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
}; };
/// Special type indicating a call to 'break' /// Special type indicating a call to 'break'
struct Break_Loop { struct Break_Loop {
Break_Loop() { }
}; };
/// Special type indicating a call to 'continue' /// Special type indicating a call to 'continue'
struct Continue_Loop { struct Continue_Loop {
Continue_Loop() { }
}; };
/// Creates a new scope then pops it on destruction
struct Scope_Push_Pop {
Scope_Push_Pop(Scope_Push_Pop &&) = default;
Scope_Push_Pop &operator=(Scope_Push_Pop &&) = delete;
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) /// Creates a new scope then pops it on destruction
: m_ds(t_ds) { struct Scope_Push_Pop
m_ds->new_scope(m_ds.stack_holder()); {
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds)
{
m_ds.get()->new_scope(m_ds.get().stack_holder());
} }
~Scope_Push_Pop() { m_ds->pop_scope(m_ds.stack_holder()); } ~Scope_Push_Pop()
{
m_ds.get()->pop_scope(m_ds.get().stack_holder());
}
private:
const chaiscript::detail::Dispatch_State &m_ds; private:
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
}; };
/// Creates a new function call and pops it on destruction /// Creates a new function call and pops it on destruction
struct Function_Push_Pop { struct Function_Push_Pop
Function_Push_Pop(Function_Push_Pop &&) = default; {
Function_Push_Pop &operator=(Function_Push_Pop &&) = delete;
Function_Push_Pop(const Function_Push_Pop &) = delete; Function_Push_Pop(const Function_Push_Pop &) = delete;
Function_Push_Pop &operator=(const Function_Push_Pop &) = delete; Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) { : m_ds(t_ds)
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); {
m_ds.get()->new_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
} }
~Function_Push_Pop() { m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); } ~Function_Push_Pop()
{
m_ds.get()->pop_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
}
void save_params(const Function_Params &t_params) { m_ds->save_function_params(t_params); } void save_params(const std::vector<Boxed_Value> &t_params)
{
m_ds.get()->save_function_params(t_params);
}
private: void save_params(std::initializer_list<Boxed_Value> t_params)
const chaiscript::detail::Dispatch_State &m_ds; {
m_ds.get()->save_function_params(std::move(t_params));
}
private:
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
}; };
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Stack_Push_Pop { struct Stack_Push_Pop
Stack_Push_Pop(Stack_Push_Pop &&) = default; {
Stack_Push_Pop &operator=(Stack_Push_Pop &&) = delete;
Stack_Push_Pop(const Stack_Push_Pop &) = delete; Stack_Push_Pop(const Stack_Push_Pop &) = delete;
Stack_Push_Pop &operator=(const Stack_Push_Pop &) = delete; Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) { : m_ds(t_ds)
m_ds->new_stack(m_ds.stack_holder()); {
m_ds.get()->new_stack(m_ds.get().stack_holder());
} }
~Stack_Push_Pop() { m_ds->pop_stack(m_ds.stack_holder()); } ~Stack_Push_Pop()
{
m_ds.get()->pop_stack(m_ds.get().stack_holder());
}
private:
const chaiscript::detail::Dispatch_State &m_ds; private:
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
}; };
} // namespace detail }
} // namespace eval }
} // namespace chaiscript }
#endif /* _CHAISCRIPT_COMMON_HPP */ #endif /* _CHAISCRIPT_COMMON_HPP */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,433 +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-2018, 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) {
((p = static_cast<T &>(*this).optimize(std::move(p))), ...);
return p;
}
};
template<typename T>
eval::AST_Node_Impl<T> &child_at(eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
return *(dynamic_cast<eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
} else {
return *node.children[offset];
}
}
template<typename T>
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
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<T> &node) noexcept {
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(eval::AST_Node_Impl_Ptr<T> original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable) {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(std::move(original_node),
std::move(children),
std::move(callable));
}
struct Return {
template<typename T>
auto optimize(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() = std::move(block_last_child->children[0]);
}
}
}
}
return p;
}
};
template<typename T>
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node) noexcept {
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl
|| node.identifier == AST_Node_Type::Reference) {
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
&& child.identifier != AST_Node_Type::Ranged_For && contains_var_decl_in_scope(child)) {
return true;
}
}
return false;
}
struct Block {
template<typename T>
auto optimize(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 std::move(node->children[0]);
} else {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text,
node->location,
std::move(node->children));
}
}
}
return node;
}
};
struct Dead_Code {
template<typename T>
auto optimize(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) {
const 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 {
const auto new_children = [&]() {
std::vector<eval::AST_Node_Impl_Ptr<T>> retval;
for (const auto x : keepers) {
retval.push_back(std::move(node->children[x]));
}
return retval;
};
return chaiscript::make_unique<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(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].get();
if (child->identifier == AST_Node_Type::Fun_Call) {
node->children[i]
= chaiscript::make_unique<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_unique<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 Assign_Decl {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if ((node->identifier == AST_Node_Type::Equation) && node->text == "=" && node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Var_Decl) {
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
new_children.push_back(std::move(node->children[0]->children[0]));
new_children.push_back(std::move(node->children[1]));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Assign_Decl_AST_Node<T>>(node->text,
node->location,
std::move(new_children));
}
return node;
}
};
struct If {
template<typename T>
auto optimize(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 = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[0].get())->m_value;
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
if (boxed_cast<bool>(condition)) {
return std::move(node->children[1]);
} else if (node->children.size() == 3) {
return std::move(node->children[2]);
}
}
}
return node;
}
};
struct Partial_Fold {
template<typename T>
auto optimize(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 = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[1].get())->m_value;
if (rhs.get_type_info().is_arithmetic()) {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(
node->text, node->location, std::move(node->children), rhs);
}
}
} catch (const std::exception &) {
// failure to fold, that's OK
}
}
return node;
}
};
struct Constant_Fold {
template<typename T>
auto optimize(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 = dynamic_cast<const eval::Constant_AST_Node<T> *>(node->children[0].get())->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_unique<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_unique<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 = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
const auto rhs = dynamic_cast<const 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_unique<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 = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
const auto rhs = dynamic_cast<const 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_unique<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 = dynamic_cast<const 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_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
const_var(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(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 (child_count(*for_node) == 4 && eq_node.identifier == AST_Node_Type::Assign_Decl && child_count(eq_node) == 2
&& child_at(eq_node, 0).identifier == AST_Node_Type::Id && 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(eq_node, 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(eq_node, 0).text) {
const Boxed_Value &begin = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(eq_node, 1)).m_value;
const Boxed_Value &end = dynamic_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);
// note that we are moving the last element out, then popping the empty shared_ptr
// from the vector
std::vector<eval::AST_Node_Impl_Ptr<T>> body_vector;
auto body_child = std::move(for_node->children[3]);
for_node->children.pop_back();
body_vector.emplace_back(std::move(body_child));
return make_compiled_node(std::move(for_node),
std::move(body_vector),
[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;
}
}
};
using Optimizer_Default = Optimizer<optimizer::Partial_Fold,
optimizer::Unused_Return,
optimizer::Constant_Fold,
optimizer::If,
optimizer::Return,
optimizer::Dead_Code,
optimizer::Block,
optimizer::For_Loop,
optimizer::Assign_Decl>;
} // namespace optimizer
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,53 +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-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_POSIX_HPP_
#define CHAISCRIPT_POSIX_HPP_
namespace chaiscript::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(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str()))) {
if (!m_symbol) {
throw chaiscript::exception::load_module_error(dlerror());
}
}
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;
};
} // namespace chaiscript::detail
#endif

View File

@ -0,0 +1,539 @@
// 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_PRELUDE_HPP_
#define CHAISCRIPT_PRELUDE_HPP_
namespace chaiscript {
struct ChaiScript_Prelude {
static std::string chaiscript_prelude() { return R""(
def lt(l, r) {
if (call_exists(`<`, l, r)) {
l < r
} else {
type_name(l) < type_name(r)
}
}
def gt(l, r) {
if (call_exists(`>`, l, r)) {
l > r
} else {
type_name(l) > type_name(r)
}
}
def eq(l, r) {
if (call_exists(`==`, l, r)) {
l == r
} else {
false
}
}
def new(x) {
eval(type_name(x))();
}
def clone(double x) {
double(x).clone_var_attrs(x)
}
def clone(string x) {
string(x).clone_var_attrs(x)
}
def clone(vector x) {
vector(x).clone_var_attrs(x)
}
def clone(int x) {
int(x).clone_var_attrs(x)
}
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
{
eval(type_name(x))(x).clone_var_attrs(x);
}
# to_string for Pair()
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
"<" + x.first.to_string() + ", " + x.second.to_string() + ">";
}
# to_string for containers
def to_string(x) : call_exists(range, x) && !x.is_type("string"){
"[" + x.join(", ") + "]";
}
# Prints to console with no carriage return
def puts(x) {
print_string(x.to_string());
}
# Prints to console with carriage return
def print(x) {
println_string(x.to_string());
}
# Returns the maximum value of two numbers
def max(a, b) {
if (a>b) {
a
} else {
b
}
}
# Returns the minimum value of two numbers
def min(a, b)
{
if (a<b)
{
a
} else {
b
}
}
# Returns true if the value is odd
def odd(x) {
if (x % 2 == 1)
{
true
} else {
false
}
}
# Returns true if the value is even
def even(x)
{
if (x % 2 == 0)
{
true
} else {
false
}
}
# Inserts the third value at the position of the second value into the container of the first
# while making a clone.
def insert_at(container, pos, x)
{
container.insert_ref_at(pos, clone(x));
}
# Returns the reverse of the given container
def reverse(container) {
auto retval := new(container);
auto r := range(container);
while (!r.empty()) {
retval.push_back(r.back());
r.pop_back();
}
retval;
}
def range(r) : call_exists(range_internal, r)
{
var ri := range_internal(r);
ri.get_var_attr("internal_obj") := r;
ri;
}
# Return a range from a range
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)
{
clone(r);
}
# The retro attribute that contains the underlying range
attr retro::m_range;
# Creates a retro from a retro by returning the original range
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
{
clone(r.m_range)
}
# Creates a retro range from a range
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;
}
# Returns the first value of a retro
def retro::front()
{
back(this.m_range)
}
# Returns the last value of a retro
def retro::back()
{
front(this.m_range)
}
# Moves the back iterator of a retro towards the front by one
def retro::pop_back()
{
pop_front(this.m_range)
}
# Moves the front iterator of a retro towards the back by one
def retro::pop_front()
{
pop_back(this.m_range)
}
# returns true if the retro is out of elements
def retro::empty()
{
empty(this.m_range);
}
# Performs the second value function over the container first value
def for_each(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
func(t_range.front());
t_range.pop_front();
}
}
def back_inserter(container) {
bind(push_back, container, _);
}
def contains(container, item, compare_func) : call_exists(range, container) {
auto t_range := range(container);
while (!t_range.empty()) {
if ( compare_func(t_range.front(), item) ) {
return true;
}
t_range.pop_front();
}
false;
}
def contains(container, item) {
contains(container, item, eq)
}
def map(container, func, inserter) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
inserter(func(range.front()));
range.pop_front();
}
}
# Performs the second value function over the container first value. Creates a new container with the results
def map(container, func) {
auto retval := new(container);
map(container, func, back_inserter(retval));
retval;
}
# Performs the second value function over the container first value. Starts with initial and continues with each element.
def foldl(container, func, initial) : call_exists(range, container){
auto retval = initial;
auto range := range(container);
while (!range.empty()) {
retval = (func(range.front(), retval));
range.pop_front();
}
retval;
}
# Returns the sum of the elements of the given value
def sum(container) {
foldl(container, `+`, 0.0)
}
# Returns the product of the elements of the given value
def product(container) {
foldl(container, `*`, 1.0)
}
# Returns a new container with the elements of the first value concatenated with the elements of the second value
def concat(x, y) : call_exists(clone, x) {
auto retval = x;
auto inserter := back_inserter(retval);
auto range := range(y);
while (!range.empty()) {
inserter(range.front());
range.pop_front();
}
retval;
}
def take(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
inserter(r.front());
r.pop_front();
--i;
}
}
# Returns a new container with the given number of elements taken from the container
def take(container, num) {
auto retval := new(container);
take(container, num, back_inserter(retval));
retval;
}
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)
}
)"";
}
};
}
#endif /* CHAISCRIPT_PRELUDE_HPP_ */

View File

@ -1,562 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_
#define CHAISCRIPT_PRELUDE_HPP_
namespace chaiscript {
struct ChaiScript_Prelude {
static std::string chaiscript_prelude() {
return R"chaiscript(
def lt(l, r) {
if (call_exists(`<`, l, r)) {
l < r
} else {
type_name(l) < type_name(r)
}
}
def gt(l, r) {
if (call_exists(`>`, l, r)) {
l > r
} else {
type_name(l) > type_name(r)
}
}
def eq(l, r) {
if (call_exists(`==`, l, r)) {
l == r
} else {
false
}
}
def new(x) {
eval(type_name(x))();
}
def clone(double x) {
double(x).clone_var_attrs(x)
}
def clone(string x) {
string(x).clone_var_attrs(x)
}
def clone(vector x) {
vector(x).clone_var_attrs(x)
}
def clone(int x) {
int(x).clone_var_attrs(x)
}
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
{
eval(type_name(x))(x).clone_var_attrs(x);
}
# to_string for Pair()
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
"<" + x.first.to_string() + ", " + x.second.to_string() + ">";
}
# to_string for containers
def to_string(x) : call_exists(range, x) && !x.is_type("string"){
"[" + x.join(", ") + "]";
}
# Prints to console with no carriage return
def puts(x) {
print_string(x.to_string());
}
# Prints to console with carriage return
def print(x) {
println_string(x.to_string());
}
# Returns the maximum value of two numbers
def max(a, b) {
if (a>b) {
a
} else {
b
}
}
# Returns the minimum value of two numbers
def min(a, b)
{
if (a<b)
{
a
} else {
b
}
}
# Returns true if the value is odd
def odd(x) {
if (x % 2 == 1)
{
true
} else {
false
}
}
# Returns true if the value is even
def even(x)
{
if (x % 2 == 0)
{
true
} else {
false
}
}
# Inserts the third value at the position of the second value into the container of the first
# while making a clone.
def insert_at(container, pos, x)
{
container.insert_ref_at(pos, clone(x));
}
# Returns the reverse of the given container
def reverse(container) {
auto retval := new(container);
auto r := range(container);
while (!r.empty()) {
retval.push_back(r.back());
r.pop_back();
}
retval;
}
def range(r) : call_exists(range_internal, r)
{
var ri := range_internal(r);
ri.get_var_attr("internal_obj") := r;
ri;
}
# Return a range from a range
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)
{
clone(r);
}
# The retro attribute that contains the underlying range
attr retro::m_range;
# Creates a retro from a retro by returning the original range
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
{
clone(r.m_range)
}
# Creates a retro range from a range
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;
}
# Returns the first value of a retro
def retro::front()
{
back(this.m_range)
}
# Returns the last value of a retro
def retro::back()
{
front(this.m_range)
}
# Moves the back iterator of a retro towards the front by one
def retro::pop_back()
{
pop_front(this.m_range)
}
# Moves the front iterator of a retro towards the back by one
def retro::pop_front()
{
pop_back(this.m_range)
}
# returns true if the retro is out of elements
def retro::empty()
{
empty(this.m_range);
}
# Performs the second value function over the container first value
def for_each(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
func(t_range.front());
t_range.pop_front();
}
}
def any_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (func(t_range.front())) {
return true;
}
t_range.pop_front();
}
false;
}
def all_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (!func(t_range.front())) {
return false;
}
t_range.pop_front();
}
true;
}
def back_inserter(container) {
bind(push_back, container, _);
}
def contains(container, item, compare_func) : call_exists(range, container) {
auto t_range := range(container);
while (!t_range.empty()) {
if ( compare_func(t_range.front(), item) ) {
return true;
}
t_range.pop_front();
}
false;
}
def contains(container, item) {
contains(container, item, eq)
}
def map(container, func, inserter) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
inserter(func(range.front()));
range.pop_front();
}
}
# Performs the second value function over the container first value. Creates a new container with the results
def map(container, func) {
auto retval := new(container);
map(container, func, back_inserter(retval));
retval;
}
# Performs the second value function over the container first value. Starts with initial and continues with each element.
def foldl(container, func, initial) : call_exists(range, container){
auto retval = initial;
auto range := range(container);
while (!range.empty()) {
retval = (func(range.front(), retval));
range.pop_front();
}
retval;
}
# Returns the sum of the elements of the given value
def sum(container) {
foldl(container, `+`, 0.0)
}
# Returns the product of the elements of the given value
def product(container) {
foldl(container, `*`, 1.0)
}
# Returns a new container with the elements of the first value concatenated with the elements of the second value
def concat(x, y) : call_exists(clone, x) {
auto retval = x;
auto inserter := back_inserter(retval);
auto range := range(y);
while (!range.empty()) {
inserter(range.front());
range.pop_front();
}
retval;
}
def take(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
inserter(r.front());
r.pop_front();
--i;
}
}
# Returns a new container with the given number of elements taken from the container
def take(container, num) {
auto retval := new(container);
take(container, num, back_inserter(retval));
retval;
}
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";
}
};
} // namespace chaiscript
#endif /* CHAISCRIPT_PRELUDE_HPP_ */

File diff suppressed because it is too large Load Diff

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-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_TRACER_HPP_
#define CHAISCRIPT_TRACER_HPP_
namespace chaiscript::eval {
struct Noop_Tracer_Detail {
template<typename T>
constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *) noexcept {
}
};
template<typename... T>
struct Tracer : T... {
Tracer() = default;
constexpr explicit Tracer(T... t)
: T(std::move(t))... {
}
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(static_cast<T &>(*this).trace(ds, node), ...);
}
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);
}
};
using Noop_Tracer = Tracer<Noop_Tracer_Detail>;
} // namespace chaiscript::eval
#endif

View File

@ -1,25 +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-2018, 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;
};
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -1,113 +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-2018, 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) {
using StringType = LPTSTR;
#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;
};
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -1,38 +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-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include "../chaiscript_defines.hpp"
#include <cstdint>
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
}
} // namespace utility
} // namespace chaiscript
#endif

View File

@ -1,94 +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 "../chaiscript_defines.hpp"
#include <cstdint>
namespace chaiscript {
namespace utility {
namespace fnv1a {
template<typename Itr>
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
std::uint32_t h = 0x811c9dc5;
while (begin != end) {
h = (h ^ (*begin)) * 0x01000193;
++begin;
}
return h;
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str) - 1);
}
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
return hash(sv.begin(), sv.end());
}
static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end());
}
} // namespace fnv1a
namespace jenkins_one_at_a_time {
template<typename Itr>
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
std::uint32_t hash = 0;
while (begin != end) {
hash += std::uint32_t(*begin);
hash += hash << 10;
hash ^= hash >> 6;
++begin;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;
}
template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str) - 1);
}
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
return hash(sv.begin(), sv.end());
}
static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end());
}
} // namespace jenkins_one_at_a_time
using fnv1a::hash;
} // namespace utility
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -3,129 +3,156 @@
#include "json.hpp" #include "json.hpp"
namespace chaiscript { namespace chaiscript
class json_wrap { {
public: class json_wrap
static Module &library(Module &m) { {
m.add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json"); public:
m.add(chaiscript::fun(&json_wrap::to_json), "to_json");
return m; static ModulePtr library(ModulePtr m = std::make_shared<Module>())
} {
private: m->add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
static Boxed_Value from_json(const json::JSON &t_json) { m->add(chaiscript::fun(&json_wrap::to_json), "to_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()) { return m;
m.insert(std::make_pair(p.first, from_json(p.second)));
}
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.ObjectRange())
{
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.ArrayRange())
{
vec.emplace_back(from_json(p));
}
return Boxed_Value(vec);
}
case json::JSON::Class::String:
return Boxed_Value(t_json.ToString());
case json::JSON::Class::Floating:
return Boxed_Value(t_json.ToFloat());
case json::JSON::Class::Integral:
return Boxed_Value(t_json.ToInt());
case json::JSON::Class::Boolean:
return Boxed_Value(t_json.ToBool());
}
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;
return Boxed_Value(m); } catch (const chaiscript::exception::bad_boxed_cast &) {
// not a map
} }
case json::JSON::Class::Array: {
std::vector<Boxed_Value> vec;
for (const auto &p : t_json.array_range()) { try {
vec.emplace_back(from_json(p)); 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;
return Boxed_Value(vec); } catch (const chaiscript::exception::bad_boxed_cast &) {
// not a vector
} }
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) { try {
try { Boxed_Number bn(t_bv);
return from_json(json::JSON::Load(t_json)); json::JSON obj;
} catch (const std::out_of_range &) { if (Boxed_Number::is_floating_point(t_bv))
throw std::runtime_error("Unparsed JSON input"); {
} obj = bn.get_as<double>();
} } else {
obj = bn.get_as<long>();
static std::string to_json(const Boxed_Value &t_bv) { return to_json_object(t_bv).dump(); } }
return obj;
static json::JSON to_json_object(const Boxed_Value &t_bv) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
try { // not a number
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv);
json::JSON obj(json::JSON::Class::Object);
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 { try {
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv); bool b = boxed_cast<bool>(t_bv);
json::JSON obj;
json::JSON obj(json::JSON::Class::Array); obj = b;
for (size_t i = 0; i < v.size(); ++i) { return obj;
obj[i] = to_json_object(v[i]); } catch (const chaiscript::exception::bad_boxed_cast &) {
// not a bool
} }
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a vector
}
try { try {
Boxed_Number bn(t_bv); std::string s = boxed_cast<std::string>(t_bv);
if (Boxed_Number::is_floating_point(t_bv)) { json::JSON obj;
return json::JSON(bn.get_as<double>()); obj = s;
} else { return obj;
return json::JSON(bn.get_as<std::int64_t>()); } catch (const chaiscript::exception::bad_boxed_cast &) {
// not a string
} }
} 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 { try {
return json::JSON(boxed_cast<std::string>(t_bv)); const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a string
}
try { json::JSON obj;
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv); for (const auto &attr : o.get_attrs())
{
json::JSON obj(json::JSON::Class::Object); obj[attr.first] = to_json_object(attr.second);
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
} }
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) { throw std::runtime_error("Unknown object type to convert to JSON");
// not a dynamic object
} }
if (t_bv.is_null())
return json::JSON(); // a null value
throw std::runtime_error("Unknown object type to convert to JSON");
}
}; };
} // namespace chaiscript
}
#endif #endif

View File

@ -1,133 +0,0 @@
#ifndef CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP
#define CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP
namespace chaiscript::utility {
template<typename Key, typename Value, typename Comparator = std::equal_to<>>
struct QuickFlatMap {
Comparator comparator;
template<typename Lookup>
auto find(const Lookup &s) noexcept {
return std::find_if(std::begin(data), std::end(data), [&s, this](const auto &d) { return comparator(d.first, s); });
}
template<typename Lookup>
auto find(const Lookup &s) const noexcept {
return std::find_if(std::cbegin(data), std::cend(data), [&s, this](const auto &d) { return comparator(d.first, s); });
}
template<typename Lookup>
auto find(const Lookup &s, const std::size_t t_hint) const noexcept {
if (data.size() > t_hint && comparator(data[t_hint].first, s)) {
const auto begin = std::cbegin(data);
return std::next(begin, static_cast<typename std::iterator_traits<std::decay_t<decltype(begin)>>::difference_type>(t_hint));
} else {
return find(s);
}
}
auto size() const noexcept { return data.size(); }
auto begin() const noexcept { return data.begin(); }
auto end() const noexcept { return data.end(); }
auto begin() noexcept { return data.begin(); }
auto end() noexcept { return data.end(); }
auto &back() noexcept { return data.back(); }
const auto &back() const noexcept { return data.back(); }
Value &operator[](const Key &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
grow();
return data.emplace_back(s, Value()).second;
}
}
Value &at_index(const std::size_t idx) noexcept { return data[idx].second; }
const Value &at_index(const std::size_t idx) const noexcept { return data[idx].second; }
bool empty() const noexcept { return data.empty(); }
template<typename Itr>
void assign(Itr begin, Itr end) {
data.assign(begin, end);
}
Value &at(const Key &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
template<typename M>
auto insert_or_assign(Key &&key, M &&m) {
if (auto itr = find(key); itr != data.end()) {
*itr = std::forward<M>(m);
return std::pair{itr, false};
} else {
grow();
return std::pair{data.emplace(data.end(), std::move(key), std::forward<M>(m)), true};
}
}
template<typename M>
auto insert_or_assign(const Key &key, M &&m) {
if (auto itr = find(key); itr != data.end()) {
itr->second = std::forward<M>(m);
return std::pair{itr, false};
} else {
grow();
return std::pair{data.emplace(data.end(), key, std::forward<M>(m)), true};
}
}
const Value &at(const Key &s) const {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
template<typename Lookup>
size_t count(const Lookup &s) const noexcept {
return (find(s) != data.end()) ? 1 : 0;
}
std::vector<std::pair<Key, Value>> data;
using value_type = std::pair<Key, Value>;
using iterator = typename decltype(data)::iterator;
using const_iterator = typename decltype(data)::const_iterator;
std::pair<iterator, bool> insert(value_type &&value) {
if (const auto itr = find(value.first); itr != data.end()) {
return std::pair{itr, false};
} else {
grow();
return std::pair{data.insert(data.end(), std::move(value)), true};
}
}
void grow() {
if ((data.capacity() - data.size()) == 0) {
data.reserve(data.size() + 2);
}
}
};
} // namespace chaiscript::utility
#endif

View File

@ -1,49 +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_STACK_VECTOR_HPP_
#define CHAISCRIPT_STACK_VECTOR_HPP_
#include <cstdint>
#include <string>
#include <type_traits>
template<typename T, std::size_t MaxSize>
struct Stack_Vector {
constexpr static auto aligned_size = sizeof(T) + (sizeof(T) & std::alignment_of_v<T>) > 0 ? std::alignment_of_v<T> : 0;
alignas(std::alignment_of_v<T>) char data[aligned_size * MaxSize];
[[nodiscard]] T &operator[](const std::size_t idx) noexcept { return *reinterpret_cast<T *>(&data + aligned_size * idx); }
[[nodiscard]] const T &operator[](const std::size_t idx) const noexcept {
return *reinterpret_cast<const T *>(&data + aligned_size * idx);
}
template<typename... Param>
T &emplace_back(Param &&...param) {
auto *p = new (&(*this)[m_size++]) T(std::forward<Param>(param)...);
return *p;
};
auto size() const noexcept { return m_size; };
void pop_back() noexcept(std::is_nothrow_destructible_v<T>) { (*this)[--m_size].~T(); }
~Stack_Vector() noexcept(std::is_nothrow_destructible_v<T>) {
auto loc = m_size - 1;
for (std::size_t pos = 0; pos < m_size; ++pos) {
(*this)[loc--].~T();
}
}
std::size_t m_size{0};
};
#endif CHAISCRIPT_STACK_VECTOR_HPP_

View File

@ -1,54 +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-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
namespace chaiscript::utility {
struct Static_String {
template<size_t N>
constexpr Static_String(const char (&str)[N]) noexcept
: m_size(N - 1)
, data(&str[0]) {
}
constexpr size_t size() const noexcept { return m_size; }
constexpr const char *c_str() const noexcept { return data; }
constexpr auto begin() const noexcept { return data; }
constexpr auto end() const noexcept { return data + m_size; }
constexpr bool operator==(std::string_view other) const noexcept {
// return std::string_view(data, m_size) == other;
auto b1 = begin();
const auto e1 = end();
auto b2 = other.begin();
const auto e2 = other.end();
if (e1 - b1 != e2 - b2) {
return false;
}
while (b1 != e1) {
if (*b1 != *b2) {
return false;
}
++b1;
++b2;
}
return true;
}
bool operator==(const std::string &t_str) const noexcept { return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str)); }
const size_t m_size;
const char *data = nullptr;
};
} // namespace chaiscript::utility
#endif

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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_
@ -15,90 +12,96 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "../chaiscript.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp"
#include "../dispatchkit/operators.hpp" #include "../dispatchkit/operators.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../language/chaiscript_common.hpp"
namespace chaiscript::utility {
/// Single step command for registering a class with ChaiScript
///
/// \param[in,out] t_module Model to add class to
/// \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);
for (const chaiscript::Proxy_Function &ctor : t_constructors) { namespace chaiscript
t_module.add(ctor, t_class_name); {
} namespace utility
{
for (const auto &fun : t_funcs) { /// Single step command for registering a class with ChaiScript
t_module.add(fun.first, fun.second); ///
} /// \param[in,out] t_module Model to add class to
/// \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);
for(const chaiscript::Proxy_Function &ctor: t_constructors)
{
t_module.add(ctor, t_class_name);
}
for(const auto &fun: t_funcs)
{
t_module.add(fun.first, fun.second);
}
}
template<typename Enum, typename ModuleType>
typename std::enable_if<std::is_enum<Enum>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
#ifdef CHAISCRIPT_GCC_4_6
const std::vector<std::pair<int, std::string>> &t_constants
#else
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants
#endif
)
{
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;
t_module.add([](){
// add some comparison and assignment operators
return assign<Enum>(not_equal<Enum>(equal<Enum>()));
}());
#ifdef CHAISCRIPT_GCC_4_6
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; }), "==");
#else
t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type<Enum>::type &i) { return e == i; }), "==");
t_module.add(chaiscript::fun([](const typename std::underlying_type<Enum>::type &i, const Enum &e) { return i == e; }), "==");
#endif
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
}
}
} }
}
template<typename Enum, typename ModuleType>
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);
}
}
} // namespace chaiscript::utility
#endif #endif

View File

@ -1,7 +1,5 @@
BSD-3-Clause License Copyright 2009-2016 Jason Turner
Copyright 2009-2012 Jonathan Turner.
Copyright 2009-2018 Jason Turner
Copyright 2009-2012 Jonathan Turner.
All Rights Reserved. All Rights Reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -1,11 +0,0 @@
def var_test(int n)
{
for (var i = 0; i < n; ++i) {
var j = 0
}
}
var n = 500000
var_test(n) // takes 2.6 s

View File

@ -5,8 +5,9 @@ double f(const std::string &, double, bool) noexcept {
return .0; return .0;
} }
int main() { int main()
chaiscript::ChaiScript chai; {
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&f), "f"); chai.add(chaiscript::fun(&f), "f");
@ -15,4 +16,5 @@ int main() {
f("str", 1.2, false); f("str", 1.2, false);
} }
)"); )");
} }

View File

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

121
readme.md
View File

@ -1,18 +1,18 @@
<a href="https://www.patreon.com/bePatron?u=2977989&redirect_uri=https%3A%2F%2Fwww.patreon.com%2Flefticus">
<img height="40" width="204" src="https://s3-us-west-1.amazonaws.com/widget-images/become-patron-widget-medium%402x.png">
</a>
Master Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=master)](http://codecov.io/github/ChaiScript/ChaiScript?branch=master) Master Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=master)](http://codecov.io/github/ChaiScript/ChaiScript?branch=master)
Develop Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=develop)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw/branch/develop?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript/branch/develop) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=develop)](http://codecov.io/github/ChaiScript/ChaiScript?branch=develop) Develop Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=develop)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw/branch/develop?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript/branch/develop) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=develop)](http://codecov.io/github/ChaiScript/ChaiScript?branch=develop)
<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-2016 Jason Turner
Release under the BSD license, see "license.txt" for details. Release under the BSD license, see "license.txt" for details.
@ -20,56 +20,46 @@ Release under the BSD license, see "license.txt" for details.
Introduction Introduction
============ ============
[![Gitter](https://badges.gitter.im/JoinChat.svg)](https://gitter.im/ChaiScript/ChaiScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![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 how they would expect 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++17 compiler to build with support for variadic ChaiScript requires a C++11 compiler to build with support for variadic
templates. It has been tested with gcc 7 and clang 6 (with libcxx). templates. It has been tested with gcc 4.6 and clang 3.1 (with libcxx). MacOS
10.8 (Mountain Lion) is also known to support the C++11 build with Apple's
Installation using vcpkg clang 4.0. MSVC 2013 or newer is supports also. For more information see the build
======================== [dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
You can download and install ChaiScript using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install chaiscript
The ChaiScript port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
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 a
new engine with the name `chai` like so: `chaiscript::ChaiScript chai` new engine with the name `chai` like so: `chaiscript::ChaiScript chai`
* The default behavior is to load the ChaiScript standard library from a * 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, loadable module. A second option is to compile the library into your code,
see below for an example. 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
`chai.eval(string)` and a file at a time using `chai.eval_file(fname)` `chai.eval(string)` and a file at a time using `chai.eval_file(fname)`
To make functions in your C++ code visible to scripts, they must be registered To make functions in your C++ code visible to scripts, they must be registered
with the scripting engine. To do so, call add: with the scripting engine. To do so, call add:
chai.add(chaiscript::fun(&my_function), "my_function_name"); chai.add(chaiscript::fun(&my_function), "my_function_name");
@ -79,35 +69,58 @@ Once registered the function will be visible to scripts as "my_function_name"
Examples Examples
======== ========
ChaiScript is similar to ECMAScript (aka JavaScript(tm)), but with some ChaiScript is similar to ECMAScript (aka JavaScript(tm)), but with some
modifications to make it easier to use. For usage examples see the "samples" modifications to make it easier to use. For usage examples see the "samples"
directory, and for more in-depth look at the language, the unit tests in the 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.
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);");
}
Or, if you want to compile the std lib into your code, which reduces
runtime requirements.
/// main.cpp
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
double function(int i, double j)
{
return i * j;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}
```

View File

@ -1,75 +1,6 @@
Notes: Notes:
======= =======
Current Version: 6.1.1 Current Version: 5.8.5
### Changes since 6.1.0
* Handle the returning of `&` to `*` types. This specifically comes up with `std::vector<int *>` and similar containers
* Update CMake to use `LIBDIR` instead of `lib` #502 by @guoyunhe
* Add documentation for installing ChaiScript with vcpkg #500 by @grdowns
* Fix warning for implicit 'this' lambda capture in C++20 #495 by @Josh-Thompson
### Changes since 6.0.0
* Add namespacing support #290 @stephenberry
* Add utf parsing support
* cheatsheet.md updates
* `add_class` utility support for scoped enums #306 @StanEpp
* Parser optimizations #300 @niXman
* Various JSON fixes #377 #400 #409 #371 @totalgee @dinghram @arcoRocks
* Various cleanups, bugfixes and warning fixes and minor performance improvements
* Support for C++17 compilers!
* Support for UTF8 BOM #439 @AlekMosingiewicz @MarioLiebisch
### 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 ### Changes since 5.8.4
* Fix order of operations for prefix operators * Fix order of operations for prefix operators

View File

@ -1,12 +0,0 @@
cxx_binary(
name = 'example',
srcs = [
'example.cpp',
],
compiler_flags = [
'-std=c++14',
],
deps = [
'//:chaiscript',
],
)

View File

@ -4,52 +4,64 @@
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// NOT TO BE USED AS A SOURCE OF BEST PRACTICES
// FOR CHAISCRIPT
#include <ctime>
#include <iostream> #include <iostream>
#include <ctime>
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp> #include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp> #include <chaiscript/dispatchkit/function_call.hpp>
void log(const std::string &msg) { void log(const std::string &msg)
{
std::cout << "[" << time(nullptr) << "] " << msg << '\n'; std::cout << "[" << time(nullptr) << "] " << msg << '\n';
} }
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 << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n';
} }
void bound_log(const std::string &msg) { void bound_log(const std::string &msg)
{
log(msg); log(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\n";
} }
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\n";
} }
struct System {
std::map<std::string, std::function<std::string(const std::string &)>> m_callbacks;
void add_callback(const std::string &t_name, const std::function<std::string(const std::string &)> &t_func) { struct System
{
std::map<std::string, std::function<std::string (const std::string &) > > m_callbacks;
void add_callback(const std::string &t_name,
const std::function<std::string (const std::string &)> &t_func)
{
m_callbacks[t_name] = t_func; m_callbacks[t_name] = t_func;
} }
void do_callbacks(const std::string &inp) {
void do_callbacks(const std::string &inp)
{
log("Running Callbacks: " + inp); log("Running Callbacks: " + inp);
for (auto &m_callback : m_callbacks) { for (std::map<std::string, std::function<std::string (const std::string &)> >::iterator itr = m_callbacks.begin();
log("Callback: " + m_callback.first, m_callback.second(inp)); itr != m_callbacks.end();
++itr)
{
log("Callback: " + itr->first, itr->second(inp));
} }
} }
}; };
void take_shared_ptr(const std::shared_ptr<const std::string> &p) { void take_shared_ptr(const std::shared_ptr<const std::string> &p)
{
std::cout << *p << '\n'; std::cout << *p << '\n';
} }
@ -57,105 +69,109 @@ int main(int /*argc*/, char * /*argv*/[]) {
using namespace chaiscript; using namespace chaiscript;
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, std::ref(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");
chai.add(fun(&System::do_callbacks), "do_callbacks"); chai.add(fun(&System::do_callbacks), "do_callbacks");
chai.add(fun(&take_shared_ptr), "take_shared_ptr"); chai.add(fun(&take_shared_ptr), "take_shared_ptr");
// 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 // std::function, so it can be handled and called easily and type-safely
chai.eval(R"(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
// access to it both from within chaiscript and from C++ code // access to it both from within chaiscript and from C++ code
system.do_callbacks("TestString"); system.do_callbacks("TestString");
chai.eval(R"(system.do_callbacks("TestString");)"); chai.eval("system.do_callbacks(\"TestString\");");
// The log function is overloaded, therefore we have to give the C++ compiler a hint as to which // The log function is overloaded, therefore we have to give the C++ compiler a hint as to which
// version we want to register. One way to do this is to create a typedef of the function pointer // version we want to register. One way to do this is to create a typedef of the function pointer
// then cast your function to that typedef. // then cast your function to that typedef.
using PlainLog = void (*)(const std::string &); typedef void (*PlainLog)(const std::string &);
using ModuleLog = void (*)(const std::string &, const std::string &); typedef void (*ModuleLog)(const std::string &, const std::string &);
chai.add(fun(PlainLog(&log)), "log"); chai.add(fun(PlainLog(&log)), "log");
chai.add(fun(ModuleLog(&log)), "log"); chai.add(fun(ModuleLog(&log)), "log");
chai.eval(R"(log("Test Message"))"); chai.eval("log(\"Test Message\")");
// 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(R"(log("Test Module", "Test Message");)"); chai("log(\"Test Module\", \"Test Message\");");
// Finally, it is possible to register a lambda as a system function, in this //Finally, it is possible to register any std::function as a system function, in this
// way, we can, for instance add a bound member function to the system //way, we can, for instance add a bound member function to the system
chai.add(fun([&system]() { return system.do_callbacks("Bound Test"); }), "do_callbacks"); chai.add(fun(&System::do_callbacks, std::ref(system), std::string("Bound Test")), "do_callbacks");
// Call bound version of do_callbacks //Call bound version of do_callbacks
chai("do_callbacks()"); chai("do_callbacks()");
std::function<void()> caller = chai.eval<std::function<void()>>(R"(fun() { system.do_callbacks("From Functor"); })"); std::function<void ()> caller = chai.eval<std::function<void ()> >("fun() { system.do_callbacks(\"From Functor\"); }");
caller(); caller();
// If we would like a type-safe return value from all call, we can use
// the templated version of eval: //If we would like a type-safe return value from all call, we can use
//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 << '\n';
// Add a new variable //Add a new variable
chai("var scripti = 15"); chai("var scripti = 15");
// 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 << '\n';
scripti *= 2; scripti *= 2;
std::cout << "scripti (updated): " << scripti << '\n'; std::cout << "scripti (updated): " << scripti << '\n';
chai(R"(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 immediately
int x = chai.eval<std::function<int(int, int)>>("fun (x, y) { return x + y; }")(5, 6); int x = chai.eval<std::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(std::shared_ptr<int>()), "nullvar");
chai(R"(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
chai.add_global_const(const_var(1), "constvar"); chai.add_global_const(const_var(1), "constvar");
chai("def getvar() { return constvar; }"); chai("def getvar() { return constvar; }");
chai("print( getvar() )"); chai("print( getvar() )");
// Ability to create our own container types when needed. std::vector and std::map are
// mostly supported currently //Ability to create our own container types when needed. std::vector and std::map are
// chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector")); //mostly supported currently
chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
// Test ability to register a function that excepts a shared_ptr version of a type // Test ability to register a function that excepts a shared_ptr version of a type
chai(R"(take_shared_ptr("Hello World as a shared_ptr");)"); chai("take_shared_ptr(\"Hello World as a shared_ptr\");");
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun"); chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
// 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, // chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr");
// "TestType", "attr", std::placeholders::_1))), "attr");
chai.eval("var x = TestType()"); chai.eval("var x = TestType()");
// chai.eval("x.attr = \"hi\""); // chai.eval("x.attr = \"hi\"");
// chai.eval("print(x.attr)"); // chai.eval("print(x.attr)");
chai.eval("x.hello_world()"); chai.eval("x.hello_world()");
} }

View File

@ -1,54 +1,63 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
class Entity { class Entity
public: {
int width; public:
int height; int width;
int x; int height;
int y; int x;
std::string name; int y;
std::string name;
std::function<void(Entity &)> updater; 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) Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name)
: width(t_width) : width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name))
, height(t_height) {
, x(t_x) }
, y(t_y)
, name(std::move(t_name)) {
}
}; };
class Factory { class Factory
public: {
// we may as well pass the parameters for the entity to the factory method, this does the initialization public:
// in one step. // we may as well pass the parameters for the entity to the factory method, this does the initialization
Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name) { // in one step.
auto entity = entities.insert({name, Entity{width, height, x, y, name}}); Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name)
return &(entity.first->second); {
} 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); } 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() { // loop over all entities and all their updater function (if it exists)
for (auto &entity : entities) { void update_entities()
if (entity.second.updater) { {
entity.second.updater(entity.second); 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, private:
// because a vector automatically resizing itself can invalidate the pointer that was returned. // we cannot store the entities in a std::vector if we want to return a pointer to them,
// using a map guarantees that the memory assigned to the entity will never change, plus // because a vector automatically resizing itself can invalidate the pointer that was returned.
// lets us easily look up an entity by name // using a map guarantees that the memory assigned to the entity will never change, plus
std::map<std::string, Entity> entities; // lets us easily look up an entity by name
std::map<std::string, Entity> entities;
}; };
int main() { int main()
chaiscript::ChaiScript chai; {
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&Entity::width), "width"); chai.add(chaiscript::fun(&Entity::width), "width");
chai.add(chaiscript::fun(&Entity::height), "height"); chai.add(chaiscript::fun(&Entity::height), "height");
@ -63,6 +72,7 @@ int main() {
chai.add(chaiscript::fun(&Factory::update_entities), "update_entities"); 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 chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer
Factory f; Factory f;
chai.add(chaiscript::var(&f), "f"); chai.add(chaiscript::var(&f), "f");
@ -83,5 +93,11 @@ int main() {
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
)""; )"";
chai.eval(script); chai.eval(script);
} }

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <regex> #include <regex>
@ -16,40 +13,46 @@
#endif #endif
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/history.h>
#include <readline/readline.h> #include <readline/readline.h>
#include <readline/history.h>
#else #else
char *mystrdup(const char *s) { char *mystrdup(const char *s) {
size_t len = strlen(s); // Space for length plus nul size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char *>(malloc(len + 1)); char *d = static_cast<char*>(malloc(len + 1));
if (d == nullptr) if (d == nullptr) return nullptr; // No memory
return nullptr; // No memory
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
strcpy_s(d, len + 1, s); // Copy the characters strcpy_s(d, len + 1, s); // Copy the characters
#else #else
strncpy(d, s, len); // Copy the characters strncpy(d, s, len); // Copy the characters
#endif #endif
d[len] = '\0'; d[len] = '\0';
return d; // Return the new string return d; // Return the new string
} }
char *readline(const char *p) { char* readline(const char* p)
{
std::string retval; std::string retval;
std::cout << p; std::cout << p;
std::getline(std::cin, retval); std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str()); return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
} }
void add_history(const char *) {}
void using_history() {} void add_history(const char*){}
void using_history(){}
#endif #endif
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
union cast_union {
std::vector<std::string> (*in_ptr)(); void *cast_module_symbol(std::vector<std::string>(*t_path)())
{
union cast_union
{
std::vector<std::string>(*in_ptr)();
void *out_ptr; void *out_ptr;
}; };
@ -58,11 +61,11 @@ void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
return c.out_ptr; return c.out_ptr;
} }
std::vector<std::string> default_search_paths() { std::vector<std::string> default_search_paths()
{
std::vector<std::string> paths; std::vector<std::string> paths;
#ifndef CHAISCRIPT_NO_DYNLOAD #ifdef CHAISCRIPT_WINDOWS // force no unicode
#ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096]; CHAR path[4096];
int size = GetModuleFileNameA(0, path, sizeof(path) - 1); int size = GetModuleFileNameA(0, path, sizeof(path) - 1);
@ -70,12 +73,14 @@ std::vector<std::string> default_search_paths() {
size_t lastslash = exepath.rfind('\\'); size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1); size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos) { if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash)); paths.push_back(exepath.substr(0, lastslash));
} }
if (secondtolastslash != std::string::npos) { if (secondtolastslash != std::string::npos)
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"}; {
return{ exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\" };
} }
#else #else
@ -84,23 +89,29 @@ std::vector<std::string> default_search_paths() {
std::vector<char> buf(2048); std::vector<char> buf(2048);
ssize_t size = -1; ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0) { if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
if (exepath.empty()) { if (exepath.empty())
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0) { {
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) { if (exepath.empty())
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0) { {
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) { if (exepath.empty())
{
Dl_info rInfo; Dl_info rInfo;
memset(&rInfo, 0, sizeof(rInfo)); memset(&rInfo, 0, sizeof(rInfo));
if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) { if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) {
@ -113,55 +124,62 @@ std::vector<std::string> default_search_paths() {
size_t lastslash = exepath.rfind('/'); size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1); size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos) { if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash)); paths.push_back(exepath.substr(0, lastslash));
} }
if (secondtolastslash != std::string::npos) { if (secondtolastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/"); paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
} }
#endif #endif
#endif // ifndef CHAISCRIPT_NO_DYNLOAD
return paths; return paths;
} }
void help(int n) { void help(int n) {
if (n >= 0) { if (n >= 0) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n"; 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:\n"; std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
std::cout << " dump_system() - outputs all functions registered to the system\n"; std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
std::cout << " dump_object(x) - dumps information about the given symbol\n"; std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
} else { }
std::cout << "usage : chai [option]+\n"; else {
std::cout << "option:\n"; std::cout << "usage : chai [option]+" << std::endl;
std::cout << " -h | --help\n"; std::cout << "option:" << std::endl;
std::cout << " -i | --interactive\n"; std::cout << " -h | --help" << std::endl;
std::cout << " -c | --command cmd\n"; std::cout << " -i | --interactive" << std::endl;
std::cout << " -v | --version\n"; std::cout << " -c | --command cmd" << std::endl;
std::cout << " - --stdin\n"; std::cout << " -v | --version" << std::endl;
std::cout << " filepath\n"; std::cout << " - --stdin" << std::endl;
std::cout << " filepath" << std::endl;
} }
} }
std::string helloWorld(const std::string &t_name) { std::string helloWorld(const std::string &t_name)
{
return "Hello " + t_name + "!"; return "Hello " + t_name + "!";
} }
bool throws_exception(const std::function<void()> &f) { bool throws_exception(const std::function<void()> &f)
{
try { try {
f(); f();
} catch (...) { }
catch (...) {
return true; return true;
} }
return false; return false;
} }
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) { chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f)
{
try { try {
f(); f();
} catch (const chaiscript::exception::eval_error &e) { }
catch (const chaiscript::exception::eval_error &e) {
return e; return e;
} }
@ -177,11 +195,13 @@ std::string get_next_command() {
std::string val(input_raw); std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n"); size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos) { if (pos != std::string::npos)
{
val.erase(0, pos); val.erase(0, pos);
} }
pos = val.find_last_not_of("\t \n"); pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos) { if (pos != std::string::npos)
{
val.erase(pos + 1, std::string::npos); val.erase(pos + 1, std::string::npos);
} }
@ -190,7 +210,11 @@ std::string get_next_command() {
::free(input_raw); ::free(input_raw);
} }
} }
if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") { if (retval == "quit"
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
retval += "(0)"; retval += "(0)";
} }
return retval; return retval;
@ -202,7 +226,8 @@ void myexit(int return_val) {
exit(return_val); exit(return_val);
} }
void interactive(chaiscript::ChaiScript &chai) { void interactive(chaiscript::ChaiScript& chai)
{
using_history(); using_history();
for (;;) { for (;;) {
@ -211,28 +236,32 @@ void interactive(chaiscript::ChaiScript &chai) {
// evaluate input // evaluate input
chaiscript::Boxed_Value val = chai.eval(input); chaiscript::Boxed_Value val = chai.eval(input);
// Then, we try to print the result of the evaluation to the user //Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) { if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try { try {
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)>>("to_string")(val) << '\n'; 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 (...) {} //If we can't, do nothing
} }
} catch (const chaiscript::exception::eval_error &ee) { }
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what(); std::cout << ee.what();
if (ee.call_stack.size() > 0) { 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 << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
} }
std::cout << '\n'; std::cout << std::endl;
} catch (const std::exception &e) { }
catch (const std::exception &e) {
std::cout << e.what(); std::cout << e.what();
std::cout << std::endl; std::cout << std::endl;
} }
} }
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
// Disable deprecation warning for getenv call. {
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
@ -247,7 +276,8 @@ int main(int argc, char *argv[]) {
std::vector<std::string> usepaths; std::vector<std::string> usepaths;
usepaths.push_back(""); usepaths.push_back("");
if (usepath) { if (usepath)
{
usepaths.push_back(usepath); usepaths.push_back(usepath);
} }
@ -255,12 +285,13 @@ int main(int argc, char *argv[]) {
std::vector<std::string> searchpaths = default_search_paths(); std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end()); modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.push_back(""); modulepaths.push_back("");
if (modulepath) { if (modulepath)
{
modulepaths.push_back(modulepath); modulepaths.push_back(modulepath);
} }
// chaiscript::ChaiScript chai(modulepaths, usepaths); //chaiscript::ChaiScript chai(modulepaths, usepaths);
chaiscript::ChaiScript chai(usepaths); chaiscript::ChaiScript chai(chaiscript::Std_Lib::library(), usepaths);
chai.add(chaiscript::fun(&myexit), "exit"); chai.add(chaiscript::fun(&myexit), "exit");
chai.add(chaiscript::fun(&myexit), "quit"); chai.add(chaiscript::fun(&myexit), "quit");
@ -272,7 +303,8 @@ int main(int argc, char *argv[]) {
clock_t begin = clock(); clock_t begin = clock();
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++)
{
std::string str = helloWorld("Bob12345"); std::string str = helloWorld("Bob12345");
fwrite(str.c_str(), 1, str.size(), stdout); fwrite(str.c_str(), 1, str.size(), stdout);
} }
@ -280,17 +312,17 @@ int main(int argc, char *argv[]) {
clock_t end = clock(); clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
// begin = clock(); //begin = clock();
////for (int i = 0; i < 1000; i++) ////for (int i = 0; i < 1000; i++)
////{ ////{
//// chai.eval("puts(helloWorld(\"Bob12345\"));"); //// chai.eval("puts(helloWorld(\"Bob12345\"));");
////} ////}
// chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai"); //chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai");
// end = clock(); //end = clock();
// elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; //elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
// printf("**MyProgram::time= %lf\n", elapsed_secs); //printf("**MyProgram::time= %lf\n", elapsed_secs);
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
if (i == 0 && argc > 1) { if (i == 0 && argc > 1) {
@ -300,64 +332,69 @@ int main(int argc, char *argv[]) {
std::string arg(i ? argv[i] : "--interactive"); std::string arg(i ? argv[i] : "--interactive");
enum { enum {
eInteractive, eInteractive
eCommand, , eCommand
eFile , eFile
} mode } mode = eCommand;
= eCommand;
if (arg == "-c" || arg == "--command") { if (arg == "-c" || arg == "--command") {
if ((i + 1) >= argc) { if ((i + 1) >= argc) {
std::cout << "insufficient input following " << arg << std::endl; std::cout << "insufficient input following " << arg << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} else { }
else {
arg = argv[++i]; arg = argv[++i];
} }
} else if (arg == "-" || arg == "--stdin") { }
else if (arg == "-" || arg == "--stdin") {
arg = ""; arg = "";
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
arg += line + '\n'; arg += line + '\n';
} }
} else if (arg == "-v" || arg == "--version") { }
else if (arg == "-v" || arg == "--version") {
arg = "version()"; arg = "version()";
} else if (arg == "-h" || arg == "--help") { }
else if (arg == "-h" || arg == "--help") {
arg = "help(-1)"; arg = "help(-1)";
} else if (arg == "-i" || arg == "--interactive") { }
else if (arg == "-i" || arg == "--interactive") {
mode = eInteractive; mode = eInteractive;
} else if (arg.find('-') == 0) { }
else if (arg.find('-') == 0) {
std::cout << "unrecognised argument " << arg << std::endl; std::cout << "unrecognised argument " << arg << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} else { }
else {
mode = eFile; mode = eFile;
} }
chaiscript::Boxed_Value val; chaiscript::Boxed_Value val;
try { try {
switch (mode) { switch (mode) {
case eInteractive: case eInteractive: interactive(chai); break;
interactive(chai); case eCommand: val = chai.eval(arg); break;
break;
case eCommand:
val = chai.eval(arg);
break;
case eFile: { case eFile: {
begin = clock(); begin = clock();
val = chai.eval_file(arg); 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;
}
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) { }
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print(); std::cout << ee.pretty_print();
std::cout << std::endl; std::cout << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (std::exception &e) { }
catch (std::exception &e) {
std::cout << e.what() << std::endl; std::cout << e.what() << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -365,3 +402,4 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -1,66 +1,80 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
class BaseClass { class BaseClass
public: {
BaseClass() = default; public:
BaseClass()
BaseClass(const BaseClass &) = default; {
virtual ~BaseClass() = default;
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; } BaseClass(const BaseClass &) = default;
protected: virtual ~BaseClass() {}
virtual bool validateValue(const std::string &t_val) = 0;
private: virtual std::string doSomething(float, double) const = 0;
std::string m_value;
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 { class ChaiScriptDerived : public BaseClass
public: {
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs) { public:
// using the range-checked .at() methods to give us an exception ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs)
// instead of a crash if the user passed in too-few params {
tie(t_funcs.at(0), m_doSomethingImpl); // using the range-checked .at() methods to give us an exception
tie(t_funcs.at(1), m_validateValueImpl); // 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 { std::string doSomething(float f, double d) const CHAISCRIPT_OVERRIDE
assert(m_doSomethingImpl); {
return m_doSomethingImpl(*this, f, d); assert(m_doSomethingImpl);
} return m_doSomethingImpl(*this, f, d);
}
protected: protected:
bool validateValue(const std::string &t_val) override { bool validateValue(const std::string &t_val) CHAISCRIPT_OVERRIDE
assert(m_validateValueImpl); {
return m_validateValueImpl(*this, t_val); assert(m_validateValueImpl);
} return m_validateValueImpl(*this, t_val);
}
private: private:
template<typename Param> template<typename Param>
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param) { void tie(const chaiscript::Boxed_Value &t_func, Param &t_param)
t_param = chaiscript::boxed_cast<Param>(t_func); {
} t_param = chaiscript::boxed_cast<Param>(t_func);
}
std::function<std::string(const ChaiScriptDerived &, float, double)> m_doSomethingImpl; std::function<std::string (const ChaiScriptDerived&, float, double)> m_doSomethingImpl;
std::function<bool(ChaiScriptDerived &, const std::string &t_val)> m_validateValueImpl; std::function<bool (ChaiScriptDerived&, const std::string &t_val)> m_validateValueImpl;
}; };
int main() { int main()
chaiscript::ChaiScript chai; {
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething"); chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue"); chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue"); chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
chai.add(chaiscript::constructor<ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived"); chai.add(chaiscript::constructor<ChaiScriptDerived (const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>()); chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>());
chai.add(chaiscript::user_type<BaseClass>(), "BaseClass"); chai.add(chaiscript::user_type<BaseClass>(), "BaseClass");
chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived"); chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived");
@ -92,8 +106,8 @@ int main() {
)""; )"";
chai.eval(script); chai.eval(script);
BaseClass &myderived = chai.eval<ChaiScriptDerived &>("myderived"); 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 // 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 // it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors
@ -108,7 +122,8 @@ int main() {
myderived.setValue("12345"); myderived.setValue("12345");
assert(myderived.getValue() == "1234"); assert(myderived.getValue() == "1234");
chai.eval(R"(myderived.setValue("new"))"); // set the value via chaiscript
chai.eval("myderived.setValue(\"new\")"); // set the value via chaiscript
assert(myderived.getValue() == "new"); assert(myderived.getValue() == "new");
// call the other derived method via chaiscript and return the value to c++ land: // call the other derived method via chaiscript and return the value to c++ land:
@ -117,3 +132,5 @@ int main() {
// The whole process is fully orthogonal // The whole process is fully orthogonal
} }

View File

@ -1,12 +1,15 @@
#include <iostream> #include <iostream>
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/history.h>
#include <readline/readline.h> #include <readline/readline.h>
#include <readline/history.h>
#endif #endif
std::string get_next_command() { std::string get_next_command() {
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
char *input_raw; char *input_raw;
@ -21,32 +24,49 @@ std::string get_next_command() {
#endif #endif
} }
void function(void) { void function(void)
{
// do nothing // do nothing
} }
class test { class test
{
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chaiscript::ChaiScript::State backupState = chai.get_state(); chaiscript::ChaiScript::State backupState;
public: public:
void ResetState() { test()
: chai(chaiscript::Std_Lib::library())
{
backupState = chai.get_state();
}
~test(){}
void ResetState()
{
chai.set_state(backupState); chai.set_state(backupState);
chai.add(chaiscript::fun(&function), "Whatever()"); chai.add(chaiscript::fun(&function),"Whatever()");
} }
void RunFile(std::string sFile) { void RunFile(std::string sFile)
{
try { try {
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() << '\n';
} }
} }
}; };
int main(int /*argc*/, char * /*argv*/[]) { int main(int /*argc*/, char * /*argv*/[]) {
test myChai; test myChai;
std::string command = ""; std::string command = "";
// //
@ -58,11 +78,12 @@ int main(int /*argc*/, char * /*argv*/[]) {
// scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as // scenario3 - RunFile gets in changing intervals: memory usage 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")
for (int i = 1; i < 200; i++) {
for(int i = 1; i < 200; i++)
myChai.ResetState(); myChai.ResetState();
if (command == "runfile") if(command == "runfile")
myChai.RunFile("Test.chai"); myChai.RunFile("Test.chai");
command = get_next_command(); command = get_next_command();

View File

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

View File

@ -1,6 +1,7 @@
#include <chaiscript/chaiscript_stdlib.hpp> #include <chaiscript/chaiscript_stdlib.hpp>
// MSVC doesn't like that we are using C++ return types from our C declared module // MSVC doesn't like that we are using C++ return types from our C declared module
// but this is the best way to do it for cross platform compatibility // but this is the best way to do it for cross platform compatibility
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
@ -13,10 +14,13 @@
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif #endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib() {
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib()
{
return chaiscript::Std_Lib::library(); return chaiscript::Std_Lib::library();
} }
#ifdef __llvm__ #ifdef __llvm__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif

View File

@ -1,325 +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-2018, 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 "../static_libs/chaiscript_parser.hpp"
#include "../static_libs/chaiscript_stdlib.hpp"
#include <chaiscript/chaiscript.hpp>
#include "sha3.h"
#ifdef READLINE_AVAILABLE
#include <readline/history.h>
#include <readline/readline.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 * /*unused*/) {}
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(nullptr, 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) == 0 || rInfo.dli_fname == nullptr) {
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 + 1));
}
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>.\n";
std::cout << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system\n";
std::cout << " dump_object(x) - dumps information about the given symbol\n";
} else {
std::cout << "usage : chai [option]+\n";
std::cout << "option:" << '\n';
std::cout << " -h | --help" << '\n';
std::cout << " -i | --interactive" << '\n';
std::cout << " -c | --command cmd" << '\n';
std::cout << " -v | --version" << '\n';
std::cout << " - --stdin" << '\n';
std::cout << " filepath" << '\n';
}
}
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 != nullptr) {
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_Basic &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) << '\n';
} catch (...) {
} // If we can't, do nothing
}
} catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what();
if (!ee.call_stack.empty()) {
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
}
std::cout << '\n';
} catch (const std::exception &e) {
std::cout << e.what();
std::cout << '\n';
}
}
}
double now() {
using namespace std::chrono;
auto now = high_resolution_clock::now();
return duration_cast<duration<double>>(now.time_since_epoch()).count();
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
chaiscript::ChaiScript chai;
chai.eval(R"chaiscript(
def assert_equal(x, y)
{
if (x == y)
{
// Passes
} else {
// Fails
print("assert_equal failure: got '" + to_string(y) + "' expected '" + to_string(x) + "'");
// exit(-1);
}
}
def assert_false(f)
{
if (f)
{
print("assert_false failure");
// exit(-1);
}
}
def assert_true(f)
{
if (!f)
{
print("assert_true failure");
// exit(-1);
}
}
def assert_not_equal(x, y)
{
if (!(x == y))
{
// Passes
} else {
// Fails
print("assert_not_equal failure: got " + to_string(y) + " which was not expected.");
// exit(-1);
}
}
def assert_throws(desc, x)
{
if (throws_exception(x))
{
// Passes
} else {
// Fails
print("assert_throws failure, function did not throw exception: " + to_string(desc));
// exit(-1);
}
})chaiscript");
SHA3 sha3;
std::string sha = sha3(data, size);
std::string input(reinterpret_cast<const char *>(data), size);
try {
chai.eval(std::string(reinterpret_cast<const char *>(data), size));
std::ofstream ofs("VALID/" + sha);
ofs << input;
} catch (const chaiscript::exception::eval_error &) {
std::ofstream ofs("EVAL_ERROR/" + sha);
ofs << input;
} catch (const chaiscript::Boxed_Value &) {
std::ofstream ofs("BOXED_VALUE/" + sha);
ofs << input;
} catch (const chaiscript::exception::load_module_error &e) {
std::cout << "Unhandled module load error\n"
<< e.what() << '\n';
} catch (const std::exception &) {
std::ofstream ofs("STD_EXCEPTION/" + sha);
ofs << input;
} catch (...) {
std::ofstream ofs("UNKOWN_EXCEPTION/" + sha);
ofs << input;
}
return 0;
}

View File

@ -1,12 +1,9 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <regex> #include <regex>
@ -15,43 +12,45 @@
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
#include "../static_libs/chaiscript_parser.hpp" #include <chaiscript/chaiscript.hpp>
#include "../static_libs/chaiscript_stdlib.hpp"
#include <chaiscript/chaiscript_basic.hpp>
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/history.h>
#include <readline/readline.h> #include <readline/readline.h>
#include <readline/history.h>
#else #else
char *mystrdup(const char *s) { char *mystrdup (const char *s) {
size_t len = strlen(s); // Space for length plus nul size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char *>(malloc(len + 1)); char *d = static_cast<char*>(malloc (len+1));
if (d == nullptr) { if (d == nullptr) return nullptr; // No memory
return nullptr;
} // No memory
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
strcpy_s(d, len + 1, s); // Copy the characters strcpy_s(d, len+1, s); // Copy the characters
#else #else
strncpy(d, s, len); // Copy the characters strncpy(d,s,len); // Copy the characters
#endif #endif
d[len] = '\0'; d[len] = '\0';
return d; // Return the new string return d; // Return the new string
} }
char *readline(const char *p) { char* readline(const char* p)
{
std::string retval; std::string retval;
std::cout << p; std::cout << p ;
std::getline(std::cin, retval); std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str()); return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
} }
void add_history(const char * /*unused*/) {}
void using_history() {} void add_history(const char*){}
void using_history(){}
#endif #endif
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
union cast_union {
void *cast_module_symbol(std::vector<std::string> (*t_path)())
{
union cast_union
{
std::vector<std::string> (*in_ptr)(); std::vector<std::string> (*in_ptr)();
void *out_ptr; void *out_ptr;
}; };
@ -61,23 +60,25 @@ void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
return c.out_ptr; return c.out_ptr;
} }
std::vector<std::string> default_search_paths() { std::vector<std::string> default_search_paths()
{
std::vector<std::string> paths; std::vector<std::string> paths;
#ifndef CHAISCRIPT_NO_DYNLOAD #ifdef CHAISCRIPT_WINDOWS // force no unicode
#ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096]; CHAR path[4096];
int size = GetModuleFileNameA(nullptr, path, sizeof(path) - 1); int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
std::string exepath(path, size); std::string exepath(path, size);
size_t lastslash = exepath.rfind('\\'); size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1); size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos) { if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash)); paths.push_back(exepath.substr(0, lastslash));
} }
if (secondtolastslash != std::string::npos) { if (secondtolastslash != std::string::npos)
{
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"}; return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
} }
#else #else
@ -87,26 +88,32 @@ std::vector<std::string> default_search_paths() {
std::vector<char> buf(2048); std::vector<char> buf(2048);
ssize_t size = -1; ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0) { if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
if (exepath.empty()) { if (exepath.empty())
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) { {
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) { if (exepath.empty())
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) { {
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) { if (exepath.empty())
{
Dl_info rInfo; Dl_info rInfo;
memset(&rInfo, 0, sizeof(rInfo)); memset( &rInfo, 0, sizeof(rInfo) );
if (dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr) { if ( !dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname ) {
return paths; return paths;
} }
@ -116,48 +123,51 @@ std::vector<std::string> default_search_paths() {
size_t lastslash = exepath.rfind('/'); size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1); size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos) { if (lastslash != std::string::npos)
paths.push_back(exepath.substr(0, lastslash + 1)); {
paths.push_back(exepath.substr(0, lastslash));
} }
if (secondtolastslash != std::string::npos) { if (secondtolastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/"); paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
} }
#endif #endif
#endif // ifndef CHAISCRIPT_NO_DYNLOAD
return paths; return paths;
} }
void help(int n) { void help(int n) {
if (n >= 0) { if ( n >= 0 ) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n"; std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
std::cout << "Additionally, you can inspect the runtime system using:\n"; std::cout << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system\n"; std::cout << " dump_system() - outputs all functions registered to the system\n";
std::cout << " dump_object(x) - dumps information about the given symbol\n"; std::cout << " dump_object(x) - dumps information about the given symbol\n";
} else { } else {
std::cout << "usage : chai [option]+\n"; std::cout << "usage : chai [option]+\n";
std::cout << "option:" << '\n'; std::cout << "option:" << '\n';
std::cout << " -h | --help" << '\n'; std::cout << " -h | --help" << '\n';
std::cout << " -i | --interactive" << '\n'; std::cout << " -i | --interactive" << '\n';
std::cout << " -c | --command cmd" << '\n'; std::cout << " -c | --command cmd" << '\n';
std::cout << " -v | --version" << '\n'; std::cout << " -v | --version" << '\n';
std::cout << " - --stdin" << '\n'; std::cout << " - --stdin" << '\n';
std::cout << " filepath" << '\n'; std::cout << " filepath" << '\n';
} }
} }
std::string throws_exception(const std::function<void()> &f) { bool throws_exception(const std::function<void ()> &f)
{
try { try {
f(); f();
} catch (const std::exception &e) { } catch (...) {
return e.what(); return true;
} }
return ""; return false;
} }
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) { chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
{
try { try {
f(); f();
} catch (const chaiscript::exception::eval_error &e) { } catch (const chaiscript::exception::eval_error &e) {
@ -169,19 +179,21 @@ chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f)
std::string get_next_command() { std::string get_next_command() {
std::string retval("quit"); std::string retval("quit");
if (!std::cin.eof()) { if ( ! std::cin.eof() ) {
char *input_raw = readline("eval> "); char *input_raw = readline("eval> ");
if (input_raw != nullptr) { if ( input_raw ) {
add_history(input_raw); add_history(input_raw);
std::string val(input_raw); std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n"); size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos) { if (pos != std::string::npos)
{
val.erase(0, pos); val.erase(0, pos);
} }
pos = val.find_last_not_of("\t \n"); pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos) { if (pos != std::string::npos)
val.erase(pos + 1, std::string::npos); {
val.erase(pos+1, std::string::npos);
} }
retval = val; retval = val;
@ -189,7 +201,11 @@ std::string get_next_command() {
::free(input_raw); ::free(input_raw);
} }
} }
if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") { if( retval == "quit"
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
retval += "(0)"; retval += "(0)";
} }
return retval; return retval;
@ -201,7 +217,8 @@ void myexit(int return_val) {
exit(return_val); exit(return_val);
} }
void interactive(chaiscript::ChaiScript_Basic &chai) { void interactive(chaiscript::ChaiScript& chai)
{
using_history(); using_history();
for (;;) { for (;;) {
@ -210,34 +227,39 @@ void interactive(chaiscript::ChaiScript_Basic &chai) {
// evaluate input // evaluate input
chaiscript::Boxed_Value val = chai.eval(input); chaiscript::Boxed_Value val = chai.eval(input);
// Then, we try to print the result of the evaluation to the user //Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) { if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try { try {
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)>>("to_string")(val) << '\n'; std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
} catch (...) { }
} // If we can't, do nothing catch (...) {} //If we can't, do nothing
} }
} catch (const chaiscript::exception::eval_error &ee) { }
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what(); std::cout << ee.what();
if (!ee.call_stack.empty()) { 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 << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
} }
std::cout << '\n'; std::cout << '\n';
} catch (const std::exception &e) { }
catch (const std::exception &e) {
std::cout << e.what(); std::cout << e.what();
std::cout << '\n'; std::cout << '\n';
} }
} }
} }
double now() { double now()
{
using namespace std::chrono; using namespace std::chrono;
auto now = high_resolution_clock::now(); auto now = high_resolution_clock::now();
return duration_cast<duration<double>>(now.time_since_epoch()).count(); return duration_cast<duration<double>>(now.time_since_epoch()).count();
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
// Disable deprecation warning for getenv call. {
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
@ -251,20 +273,22 @@ int main(int argc, char *argv[]) {
#endif #endif
std::vector<std::string> usepaths; std::vector<std::string> usepaths;
usepaths.emplace_back(""); usepaths.push_back("");
if (usepath != nullptr) { if (usepath)
usepaths.emplace_back(usepath); {
usepaths.push_back(usepath);
} }
std::vector<std::string> modulepaths; std::vector<std::string> modulepaths;
std::vector<std::string> searchpaths = default_search_paths(); std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end()); modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.emplace_back(""); modulepaths.push_back("");
if (modulepath != nullptr) { if (modulepath)
modulepaths.emplace_back(modulepath); {
modulepaths.push_back(modulepath);
} }
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser(), modulepaths, usepaths); chaiscript::ChaiScript chai(modulepaths,usepaths);
chai.add(chaiscript::fun(&myexit), "exit"); chai.add(chaiscript::fun(&myexit), "exit");
chai.add(chaiscript::fun(&myexit), "quit"); chai.add(chaiscript::fun(&myexit), "quit");
@ -275,51 +299,45 @@ int main(int argc, char *argv[]) {
bool eval_error_ok = false; bool eval_error_ok = false;
bool boxed_exception_ok = false; bool boxed_exception_ok = false;
bool any_exception_ok = false;
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
if (i == 0 && argc > 1) { if ( i == 0 && argc > 1 ) {
++i; ++i;
} }
std::string arg(i != 0 ? argv[i] : "--interactive"); std::string arg( i ? argv[i] : "--interactive" );
enum { enum { eInteractive
eInteractive, , eCommand
eCommand, , eFile
eFile } mode = eCommand ;
} mode
= eCommand;
if (arg == "-c" || arg == "--command") { if ( arg == "-c" || arg == "--command" ) {
if ((i + 1) >= argc) { if ( (i+1) >= argc ) {
std::cout << "insufficient input following " << arg << '\n'; std::cout << "insufficient input following " << arg << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} else {
arg = argv[++i];
} }
arg = argv[++i]; } else if ( arg == "-" || arg == "--stdin" ) {
arg = "" ;
} else if (arg == "-" || arg == "--stdin") {
arg = "";
std::string line; std::string line;
while (std::getline(std::cin, line)) { while ( std::getline(std::cin, line) ) {
arg += line + '\n'; arg += line + '\n' ;
} }
} else if (arg == "-v" || arg == "--version") { } else if ( arg == "-v" || arg == "--version" ) {
arg = "print(version())"; arg = "print(version())" ;
} else if (arg == "-h" || arg == "--help") { } else if ( arg == "-h" || arg == "--help" ) {
arg = "help(-1)"; arg = "help(-1)";
} else if (arg == "-e" || arg == "--evalerrorok") { } else if ( arg == "-e" || arg == "--evalerrorok" ) {
eval_error_ok = true; eval_error_ok = true;
continue; continue;
} else if (arg == "--exception") { } else if ( arg == "--exception" ) {
boxed_exception_ok = true; boxed_exception_ok = true;
continue; continue;
} else if (arg == "--any-exception") { } else if ( arg == "-i" || arg == "--interactive" ) {
any_exception_ok = true; mode = eInteractive ;
continue; } else if ( arg.find('-') == 0 ) {
} else if (arg == "-i" || arg == "--interactive") {
mode = eInteractive;
} else if (arg.find('-') == 0) {
std::cout << "unrecognised argument " << arg << '\n'; std::cout << "unrecognised argument " << arg << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} else { } else {
@ -327,7 +345,7 @@ int main(int argc, char *argv[]) {
} }
try { try {
switch (mode) { switch ( mode ) {
case eInteractive: case eInteractive:
interactive(chai); interactive(chai);
break; break;
@ -337,33 +355,27 @@ int main(int argc, char *argv[]) {
case eFile: case eFile:
chai.eval_file(arg); chai.eval_file(arg);
} }
} catch (const chaiscript::exception::eval_error &ee) { }
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print(); std::cout << ee.pretty_print();
std::cout << '\n'; std::cout << '\n';
if (!eval_error_ok) { if (!eval_error_ok) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} catch (const chaiscript::Boxed_Value &e) { }
catch (const chaiscript::Boxed_Value &e) {
std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n'; std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n';
if (!boxed_exception_ok) { if (!boxed_exception_ok) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} catch (const chaiscript::exception::load_module_error &e) {
std::cout << "Unhandled module load error\n"
<< e.what() << '\n';
} catch (std::exception &e) {
std::cout << "Unhandled standard exception: " << e.what() << '\n';
if (!any_exception_ok) {
throw;
}
} catch (...) {
std::cout << "Unhandled unknown exception" << '\n';
if (!any_exception_ok) {
throw;
}
} }
// catch (std::exception &e) {
// std::cout << e.what() << '\n';
// return EXIT_FAILURE;
// }
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -1,289 +0,0 @@
// //////////////////////////////////////////////////////////
// sha3.cpp
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
// see http://create.stephan-brumme.com/disclaimer.html
//
#include "sha3.h"
// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN
#ifndef _MSC_VER
#include <endian.h>
#endif
/// same as reset()
SHA3::SHA3(Bits bits)
: m_blockSize(200 - 2 * (bits / 8))
, m_bits(bits) {
reset();
}
/// restart
void SHA3::reset() {
for (size_t i = 0; i < StateSize; i++)
m_hash[i] = 0;
m_numBytes = 0;
m_bufferSize = 0;
}
/// constants and local helper functions
namespace {
const unsigned int Rounds = 24;
const uint64_t XorMasks[Rounds]
= {0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL};
/// rotate left and wrap around to the right
inline uint64_t rotateLeft(uint64_t x, uint8_t numBits) {
return (x << numBits) | (x >> (64 - numBits));
}
/// convert litte vs big endian
inline uint64_t swap(uint64_t x) {
#if defined(__GNUC__) || defined(__clang__)
return __builtin_bswap64(x);
#endif
#ifdef _MSC_VER
return _byteswap_uint64(x);
#endif
return (x >> 56) | ((x >> 40) & 0x000000000000FF00ULL) | ((x >> 24) & 0x0000000000FF0000ULL) | ((x >> 8) & 0x00000000FF000000ULL)
| ((x << 8) & 0x000000FF00000000ULL) | ((x << 24) & 0x0000FF0000000000ULL) | ((x << 40) & 0x00FF000000000000ULL) | (x << 56);
}
/// return x % 5 for 0 <= x <= 9
unsigned int mod5(unsigned int x) {
if (x < 5)
return x;
return x - 5;
}
} // namespace
/// process a full block
void SHA3::processBlock(const void *data) {
#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
#define LITTLEENDIAN(x) swap(x)
#else
#define LITTLEENDIAN(x) (x)
#endif
const uint64_t *data64 = (const uint64_t *)data;
// mix data into state
for (unsigned int i = 0; i < m_blockSize / 8; i++)
m_hash[i] ^= LITTLEENDIAN(data64[i]);
// re-compute state
for (unsigned int round = 0; round < Rounds; round++) {
// Theta
uint64_t coefficients[5];
for (unsigned int i = 0; i < 5; i++)
coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20];
for (unsigned int i = 0; i < 5; i++) {
uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1);
m_hash[i] ^= one;
m_hash[i + 5] ^= one;
m_hash[i + 10] ^= one;
m_hash[i + 15] ^= one;
m_hash[i + 20] ^= one;
}
// temporary
uint64_t one;
// Rho Pi
uint64_t last = m_hash[1];
one = m_hash[10];
m_hash[10] = rotateLeft(last, 1);
last = one;
one = m_hash[7];
m_hash[7] = rotateLeft(last, 3);
last = one;
one = m_hash[11];
m_hash[11] = rotateLeft(last, 6);
last = one;
one = m_hash[17];
m_hash[17] = rotateLeft(last, 10);
last = one;
one = m_hash[18];
m_hash[18] = rotateLeft(last, 15);
last = one;
one = m_hash[3];
m_hash[3] = rotateLeft(last, 21);
last = one;
one = m_hash[5];
m_hash[5] = rotateLeft(last, 28);
last = one;
one = m_hash[16];
m_hash[16] = rotateLeft(last, 36);
last = one;
one = m_hash[8];
m_hash[8] = rotateLeft(last, 45);
last = one;
one = m_hash[21];
m_hash[21] = rotateLeft(last, 55);
last = one;
one = m_hash[24];
m_hash[24] = rotateLeft(last, 2);
last = one;
one = m_hash[4];
m_hash[4] = rotateLeft(last, 14);
last = one;
one = m_hash[15];
m_hash[15] = rotateLeft(last, 27);
last = one;
one = m_hash[23];
m_hash[23] = rotateLeft(last, 41);
last = one;
one = m_hash[19];
m_hash[19] = rotateLeft(last, 56);
last = one;
one = m_hash[13];
m_hash[13] = rotateLeft(last, 8);
last = one;
one = m_hash[12];
m_hash[12] = rotateLeft(last, 25);
last = one;
one = m_hash[2];
m_hash[2] = rotateLeft(last, 43);
last = one;
one = m_hash[20];
m_hash[20] = rotateLeft(last, 62);
last = one;
one = m_hash[14];
m_hash[14] = rotateLeft(last, 18);
last = one;
one = m_hash[22];
m_hash[22] = rotateLeft(last, 39);
last = one;
one = m_hash[9];
m_hash[9] = rotateLeft(last, 61);
last = one;
one = m_hash[6];
m_hash[6] = rotateLeft(last, 20);
last = one;
m_hash[1] = rotateLeft(last, 44);
// Chi
for (unsigned int j = 0; j < 25; j += 5) {
// temporaries
uint64_t one = m_hash[j];
uint64_t two = m_hash[j + 1];
m_hash[j] ^= m_hash[j + 2] & ~two;
m_hash[j + 1] ^= m_hash[j + 3] & ~m_hash[j + 2];
m_hash[j + 2] ^= m_hash[j + 4] & ~m_hash[j + 3];
m_hash[j + 3] ^= one & ~m_hash[j + 4];
m_hash[j + 4] ^= two & ~one;
}
// Iota
m_hash[0] ^= XorMasks[round];
}
}
/// add arbitrary number of bytes
void SHA3::add(const void *data, size_t numBytes) {
const uint8_t *current = (const uint8_t *)data;
// copy data to buffer
if (m_bufferSize > 0) {
while (numBytes > 0 && m_bufferSize < m_blockSize) {
m_buffer[m_bufferSize++] = *current++;
numBytes--;
}
}
// full buffer
if (m_bufferSize == m_blockSize) {
processBlock((void *)m_buffer);
m_numBytes += m_blockSize;
m_bufferSize = 0;
}
// no more data ?
if (numBytes == 0)
return;
// process full blocks
while (numBytes >= m_blockSize) {
processBlock(current);
current += m_blockSize;
m_numBytes += m_blockSize;
numBytes -= m_blockSize;
}
// keep remaining bytes in buffer
while (numBytes > 0) {
m_buffer[m_bufferSize++] = *current++;
numBytes--;
}
}
/// process everything left in the internal buffer
void SHA3::processBuffer() {
// add padding
size_t offset = m_bufferSize;
// add a "1" byte
m_buffer[offset++] = 0x06;
// fill with zeros
while (offset < m_blockSize)
m_buffer[offset++] = 0;
// and add a single set bit
m_buffer[offset - 1] |= 0x80;
processBlock(m_buffer);
}
/// return latest hash as 16 hex characters
std::string SHA3::getHash() {
// process remaining bytes
processBuffer();
// convert hash to string
static const char dec2hex[16 + 1] = "0123456789abcdef";
// number of significant elements in hash (uint64_t)
unsigned int hashLength = m_bits / 64;
std::string result;
result.reserve(m_bits / 4);
for (unsigned int i = 0; i < hashLength; i++)
for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes
{
// convert a byte to hex
unsigned char oneByte = (unsigned char)(m_hash[i] >> (8 * j));
result += dec2hex[oneByte >> 4];
result += dec2hex[oneByte & 15];
}
// SHA3-224's last entry in m_hash provides only 32 bits instead of 64 bits
unsigned int remainder = m_bits - hashLength * 64;
unsigned int processed = 0;
while (processed < remainder) {
// convert a byte to hex
unsigned char oneByte = (unsigned char)(m_hash[hashLength] >> processed);
result += dec2hex[oneByte >> 4];
result += dec2hex[oneByte & 15];
processed += 8;
}
return result;
}
/// compute SHA3 of a memory block
std::string SHA3::operator()(const void *data, size_t numBytes) {
reset();
add(data, numBytes);
return getHash();
}
/// compute SHA3 of a string, excluding final zero
std::string SHA3::operator()(const std::string &text) {
reset();
add(text.c_str(), text.size());
return getHash();
}

View File

@ -1,81 +0,0 @@
// //////////////////////////////////////////////////////////
// sha3.h
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
// see http://create.stephan-brumme.com/disclaimer.html
//
#pragma once
//#include "hash.h"
#include <string>
// define fixed size integer types
#ifdef _MSC_VER
// Windows
typedef unsigned __int8 uint8_t;
typedef unsigned __int64 uint64_t;
#else
// GCC
#include <stdint.h>
#endif
/// compute SHA3 hash
/** Usage:
SHA3 sha3;
std::string myHash = sha3("Hello World"); // std::string
std::string myHash2 = sha3("How are you", 11); // arbitrary data, 11 bytes
// or in a streaming fashion:
SHA3 sha3;
while (more data available)
sha3.add(pointer to fresh data, number of new bytes);
std::string myHash3 = sha3.getHash();
*/
class SHA3 //: public Hash
{
public:
/// algorithm variants
enum Bits { Bits224 = 224, Bits256 = 256, Bits384 = 384, Bits512 = 512 };
/// same as reset()
explicit SHA3(Bits bits = Bits256);
/// compute hash of a memory block
std::string operator()(const void* data, size_t numBytes);
/// compute hash of a string, excluding final zero
std::string operator()(const std::string& text);
/// add arbitrary number of bytes
void add(const void* data, size_t numBytes);
/// return latest hash as hex characters
std::string getHash();
/// restart
void reset();
private:
/// process a full block
void processBlock(const void* data);
/// process everything left in the internal buffer
void processBuffer();
/// 1600 bits, stored as 25x64 bit, BlockSize is no more than 1152 bits (Keccak224)
enum { StateSize = 1600 / (8 * 8),
MaxBlockSize = 200 - 2 * (224 / 8) };
/// hash
uint64_t m_hash[StateSize];
/// size of processed data in bytes
uint64_t m_numBytes;
/// block size (less or equal to MaxBlockSize)
size_t m_blockSize;
/// valid bytes in m_buffer
size_t m_bufferSize;
/// bytes not processed yet
uint8_t m_buffer[MaxBlockSize];
/// variant
Bits m_bits;
};

View File

@ -1,13 +1,10 @@
// 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-2018, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, 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 <chaiscript/chaiscript.hpp>
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <chaiscript/chaiscript_basic.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp> #include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <list> #include <list>
#include <string> #include <string>
@ -24,10 +21,11 @@
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif #endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra() { CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
auto module = std::make_shared<chaiscript::Module>(); {
chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value>>("List", *module);
chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t>>("u16vector", *module); auto module = chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List");
module->add(chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t> >("u16vector"));
module->add(chaiscript::vector_conversion<std::vector<uint16_t>>()); module->add(chaiscript::vector_conversion<std::vector<uint16_t>>());
return module; return module;
} }

View File

@ -1,123 +1,138 @@
#include <chaiscript/chaiscript_basic.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap.hpp> #include <chaiscript/dispatchkit/bootstrap.hpp>
#include <string> #include <string>
class TestBaseType {
public:
TestBaseType() noexcept
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(int) noexcept
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(int *) noexcept
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(const TestBaseType &other) noexcept
: val(other.val)
, const_val(other.const_val)
, const_val_ptr(&const_val)
, func_member(other.func_member) {
}
TestBaseType(TestBaseType &&other) noexcept class TestBaseType
: val(other.val) {
, const_val(other.const_val) public:
, const_val_ptr(&const_val) #ifdef CHAISCRIPT_MSVC_12
, func_member(std::move(other.func_member)) { #pragma warning(push)
} #pragma warning(disable : 4351)
#endif
// MSVC 12 warns that we are using new (correct) behavior
TestBaseType() : val(10), const_val(15), mdarray{} { }
TestBaseType(int) : val(10), const_val(15), mdarray{} { }
TestBaseType(int *) : val(10), const_val(15), mdarray{} { }
#ifdef CHAISCRIPT_MSVC_12
#pragma warning(pop)
#endif
TestBaseType(const TestBaseType &) = default;
virtual ~TestBaseType() {}
virtual int func() { return 0; }
TestBaseType &operator=(TestBaseType &&) = delete; int base_only_func() { return -9; }
TestBaseType &operator=(const TestBaseType &) = delete;
virtual ~TestBaseType() = default; const TestBaseType &constMe() const { return *this; }
virtual int func() { return 0; }
int base_only_func() { return -9; } int val;
const int const_val;
const TestBaseType &constMe() const { return *this; } int mdarray[2][3][5];
std::function<int (int)> func_member;
int val; void set_string_val(std::string &t_str)
const int const_val; {
const int *const_val_ptr = &const_val; t_str = "42";
}
const int *get_const_val_ptr() { return const_val_ptr; } private:
TestBaseType &operator=(const TestBaseType &) = delete;
int mdarray[2][3][5];
std::function<int(int)> func_member;
void set_string_val(std::string &t_str) { t_str = "42"; }
}; };
class Type2 { class Type2
public: {
Type2(TestBaseType t_bt) noexcept public:
: m_bt(std::move(t_bt)) Type2(TestBaseType t_bt)
, m_str("Hello World") { : m_bt(std::move(t_bt)),
} m_str("Hello World")
{
}
int get_val() const { return m_bt.val; } int get_val() const
{
return m_bt.val;
}
const char *get_str() const { return m_str.c_str(); }
private: const char *get_str() const
TestBaseType m_bt; {
std::string m_str; return m_str.c_str();
}
private:
TestBaseType m_bt;
std::string m_str;
}; };
enum TestEnum { enum TestEnum
{
TestValue1 = 1 TestValue1 = 1
}; };
int to_int(TestEnum t) { int to_int(TestEnum t)
{
return t; return t;
} }
class TestDerivedType : public TestBaseType { class TestDerivedType : public TestBaseType
public: {
int func() override { return 1; } public:
int derived_only_func() { return 19; } virtual ~TestDerivedType() {}
TestDerivedType(const TestDerivedType &) = default;
TestDerivedType() = default;
virtual int func() CHAISCRIPT_OVERRIDE { return 1; }
int derived_only_func() { return 19; }
private:
TestDerivedType &operator=(const TestDerivedType &) = delete;
}; };
class TestMoreDerivedType : public TestDerivedType { class TestMoreDerivedType : public TestDerivedType
public: {
public:
TestMoreDerivedType(const TestMoreDerivedType &) = default;
TestMoreDerivedType() = default;
virtual ~TestMoreDerivedType() {}
}; };
std::shared_ptr<TestBaseType> derived_type_factory() { std::shared_ptr<TestBaseType> derived_type_factory()
{
return std::make_shared<TestDerivedType>(); return std::make_shared<TestDerivedType>();
} }
std::shared_ptr<TestBaseType> more_derived_type_factory() { std::shared_ptr<TestBaseType> more_derived_type_factory()
{
return std::make_shared<TestMoreDerivedType>(); return std::make_shared<TestMoreDerivedType>();
} }
std::shared_ptr<TestBaseType> null_factory() { std::shared_ptr<TestBaseType> null_factory()
{
return std::shared_ptr<TestBaseType>(); return std::shared_ptr<TestBaseType>();
} }
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr) { void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
{
ptr = std::make_shared<TestDerivedType>(); ptr = std::make_shared<TestDerivedType>();
} }
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr) { void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
{
ptr = nullptr; ptr = nullptr;
} }
std::string hello_world() { std::string hello_world()
{
return "Hello World"; return "Hello World";
} }
static int global_i = 1; static int global_i = 1;
int *get_new_int() { int *get_new_int()
{
return &global_i; return &global_i;
} }
@ -133,7 +148,8 @@ int *get_new_int() {
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif #endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module() { CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module()
{
chaiscript::ModulePtr m(new chaiscript::Module()); chaiscript::ModulePtr m(new chaiscript::Module());
m->add(chaiscript::fun(hello_world), "hello_world"); m->add(chaiscript::fun(hello_world), "hello_world");
@ -143,16 +159,16 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mod
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType"); m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::user_type<Type2>(), "Type2"); m->add(chaiscript::user_type<Type2>(), "Type2");
m->add(chaiscript::constructor<TestBaseType()>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType"); // m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType(const TestBaseType &)>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType (const TestBaseType &)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType(int *)>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType (int *)>(), "TestBaseType");
m->add(chaiscript::constructor<TestDerivedType()>(), "TestDerivedType"); m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType(const TestDerivedType &)>(), "TestDerivedType"); m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType()>(), "TestMoreDerivedType"); m->add(chaiscript::constructor<TestMoreDerivedType ()>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType(const TestMoreDerivedType &)>(), "TestMoreDerivedType"); m->add(chaiscript::constructor<TestMoreDerivedType (const TestMoreDerivedType &)>(), "TestMoreDerivedType");
/// \todo automatic chaining of base classes? /// \todo automatic chaining of base classes?
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>()); m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
@ -170,20 +186,25 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mod
m->add(chaiscript::fun(&TestBaseType::func), "func"); m->add(chaiscript::fun(&TestBaseType::func), "func");
m->add(chaiscript::fun(&TestBaseType::val), "val"); m->add(chaiscript::fun(&TestBaseType::val), "val");
m->add(chaiscript::fun(&TestBaseType::const_val), "const_val"); m->add(chaiscript::fun(&TestBaseType::const_val), "const_val");
m->add(chaiscript::fun(&TestBaseType::const_val_ptr), "const_val_ptr");
m->add(chaiscript::fun(&TestBaseType::get_const_val_ptr), "get_const_val_ptr");
m->add(chaiscript::fun(&TestBaseType::base_only_func), "base_only_func"); m->add(chaiscript::fun(&TestBaseType::base_only_func), "base_only_func");
m->add(chaiscript::fun(&TestBaseType::set_string_val), "set_string_val"); m->add(chaiscript::fun(&TestBaseType::set_string_val), "set_string_val");
#ifndef CHAISCRIPT_MSVC_12
// we cannot support these in MSVC_12 because of a bug in the implementation of
// std::reference_wrapper
// Array types
m->add(chaiscript::fun(&TestBaseType::mdarray), "mdarray"); m->add(chaiscript::fun(&TestBaseType::mdarray), "mdarray");
chaiscript::bootstrap::array<int[2][3][5]>("IntArray_2_3_5", *m); m->add(chaiscript::bootstrap::array<int[2][3][5]>("IntArray_2_3_5"));
chaiscript::bootstrap::array<int[3][5]>("IntArray_3_5", *m); m->add(chaiscript::bootstrap::array<int[3][5]>("IntArray_3_5"));
chaiscript::bootstrap::array<int[5]>("IntArray_5", *m); m->add(chaiscript::bootstrap::array<int[5]>("IntArray_5"));
// end array types
#endif
// member that is a function // member that is a function
m->add(chaiscript::fun(&TestBaseType::func_member), "func_member"); m->add(chaiscript::fun(&TestBaseType::func_member), "func_member");
m->add(chaiscript::fun(&get_new_int), "get_new_int"); m->add(chaiscript::fun(&get_new_int), "get_new_int");
m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1"); m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1");
m->add(chaiscript::user_type<TestEnum>(), "TestEnum"); m->add(chaiscript::user_type<TestEnum>(), "TestEnum");
@ -196,14 +217,16 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mod
m->add(chaiscript::fun(&Type2::get_val), "get_val"); m->add(chaiscript::fun(&Type2::get_val), "get_val");
m->add(chaiscript::fun(&Type2::get_str), "get_str"); m->add(chaiscript::fun(&Type2::get_str), "get_str");
m->add(chaiscript::type_conversion<const char *, std::string>()); m->add(chaiscript::type_conversion<const char *, std::string>());
m->add(chaiscript::constructor<Type2(const TestBaseType &)>(), "Type2"); m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr"); m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr");
m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr"); m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr");
return m; return m;
} }
#ifdef __llvm__ #ifdef __llvm__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif

View File

@ -1,6 +0,0 @@
#include "../include/chaiscript/language/chaiscript_parser.hpp"
#include "chaiscript_parser.hpp"
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser() {
return std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>();
}

View File

@ -1,15 +0,0 @@
#ifndef CHAISCRIPT_PARSER_LIB
#define CHAISCRIPT_PARSER_LIB
#include <memory>
namespace chaiscript {
namespace parser {
class ChaiScript_Parser_Base;
}
} // namespace chaiscript
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser();
#endif

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