Compare commits

..

No commits in common. "develop" and "Release-5.2.0" have entirely different histories.

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

View File

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

View File

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

View File

@ -1,4 +0,0 @@
results_repository : ChaiScript/ChaiScript-BuildResults
results_path : _posts
results_base_url : https://chaiscript.github.io/ChaiScript-BuildResults
aging_pull_requests_notification: true

View File

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

View File

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

View File

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

6
.gitignore vendored
View File

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

View File

@ -1,82 +0,0 @@
language: cpp
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:
global:
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
- secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM="
before_install:
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
#- if [ "${CLANG_VER}" != "" ]; then export CXX="clang++-$CLANG_VER"; fi
- pip install --user cpp-coveralls
script:
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS .
- cmake --build . -- -j2
- if [ "${BUILD_ONLY}" != "1" ]; then ctest; 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:
# - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
notifications:
email:
recipients:
- jason@emptycrate.com
on_success: always
on_failure: always
webhooks:
urls:
- https://webhooks.gitter.im/e/4be9a2720eaa1bb2a6c9
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false

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,93 +1,16 @@
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0054 NEW)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# required since cmake 3.4 at least for libc++
set(CMAKE_ENABLE_EXPORTS ON)
cmake_minimum_required(VERSION 2.8)
project(chaiscript)
# MINGW does not yet support C++11's concurrency features
if (MINGW)
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" FALSE)
else()
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
endif()
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE)
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
mark_as_advanced(USE_STD_MAKE_SHARED)
if(USE_STD_MAKE_SHARED)
add_definitions(-DCHAISCRIPT_USE_STD_MAKE_SHARED)
endif()
if(CMAKE_COMPILER_IS_GNUCC)
option(ENABLE_COVERAGE "Enable Coverage Reporting in GCC" FALSE)
if(ENABLE_COVERAGE)
add_definitions(--coverage -O0)
set(LINKER_FLAGS "${LINKER_FLAGS} --coverage")
endif()
endif()
if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(ENABLE_THREAD_SANITIZER "Enable thread sanitizer testing in gcc/clang" FALSE)
if(ENABLE_THREAD_SANITIZER)
add_definitions(-fsanitize=thread -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=thread")
endif()
option(ENABLE_ADDRESS_SANITIZER "Enable address sanitizer testing in gcc/clang" FALSE)
if(ENABLE_ADDRESS_SANITIZER)
add_definitions(-fsanitize=address -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
option(BUILD_LIBFUZZ_TESTER "Build libfuzzer tool" FALSE)
endif()
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -fsanitize-memory-track-origins -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins ")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
if(ENABLE_UNDEFINED_SANITIZER)
add_definitions(-fsanitize=undefined -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined")
endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if(ENABLE_LTO)
check_ipo_supported()
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
option(GPROF_OUTPUT "Generate profile data" FALSE)
if(GPROF_OUTPUT)
add_definitions(-pg)
set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE)
if(PROFILE_GENERATE)
add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif()
option(PROFILE_USE "Use profile data" FALSE)
if(PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
endif()
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn")
@ -99,8 +22,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
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_VERSION_MAJOR 7)
set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 2)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
@ -120,14 +43,17 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest)
include(CPack)
include(cmake/Catch.cmake)
include(cmake/CheckCXX11Features.cmake)
if(NOT MINGW)
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
endif()
if(UNIX AND NOT APPLE)
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
if(HAS_CXX11_VARIADIC_TEMPLATES)
message(STATUS "Variadic Template support detected")
else()
message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.")
endif()
enable_testing()
@ -138,262 +64,185 @@ if(READLINE_LIBRARY)
message(STATUS "Found: ${READLINE_LIBRARY}")
set (READLINE_LIB readline)
add_definitions(/DREADLINE_AVAILABLE)
else()
else(READLINE_LIBRARY)
message(STATUS "Not Found")
set (READLINE_LIB )
set (READLINE_FLAG )
endif()
endif(READLINE_LIBRARY)
if(MSVC)
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")
# VS2013 doesn't have magic statics
add_definitions(/w44640)
else()
# enum warnings are too noisy on MSVC2013
add_definitions(/w34062)
add_definitions(/W4)
if(CMAKE_CL_64)
add_definitions(/bigobj)
endif()
add_definitions(/bigobj /permissive- /utf-8)
# Note on MSVC compiler flags.
# The code base selective disables warnings as necessary when the compiler is complaining too much
# about something that is perfectly valid, or there is simply no technical way around it
# This particular warning, C4503 is in regards to the decorated names that MSVC generates internally.
# The error did not come up until the move to C++11, but the compiler doesn't give enough information
# to determine where the error is coming from, and the internet provides no real information for
# how to workaround or fix the error. So I'm disabling it globally.
add_definitions(/wd4503)
else()
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)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
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)
else()
add_definitions(-Wnoexcept)
endif()
add_definitions(-Wall -Wextra -Wshadow -pedantic -std=c++0x)
if (APPLE)
add_definitions(-Wno-sign-compare)
endif()
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" FALSE)
if (CMAKE_CXX_COMPILER MATCHES ".*clang")
option(USE_LIBCXX "Use clang's libcxx" TRUE)
if (USE_LIBCXX)
add_definitions(-stdlib=libc++)
set(LINKER_FLAGS "${LINKER_FLAGS} -stdlib=libc++")
set (EXTRA_LINKER_FLAGS -std=c++0x -stdlib=libc++)
else ()
set (EXTRA_LINKER_FLAGS -std=c++0x )
endif()
else()
set (EXTRA_LINKER_FLAGS )
endif()
# limitations in MinGW require us to make an optimized build
# for the sake of object sizes or something
if(MINGW OR CYGWIN)
if (MINGW)
add_definitions(-O3)
endif()
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/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
if(NOT MULTITHREAD_SUPPORT_ENABLED)
if (MULTITHREAD_SUPPORT_ENABLED)
else()
add_definitions(-DCHAISCRIPT_NO_THREADS)
endif()
if(NOT DYNLOAD_ENABLED)
add_definitions(-DCHAISCRIPT_NO_DYNLOAD)
endif()
if (CMAKE_HOST_UNIX)
if(DYNLOAD_ENABLED)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
list(APPEND LIBS "dl")
endif()
endif()
if (MULTITHREAD_SUPPORT_ENABLED)
if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE GCC_FULL_VERSION)
if(GCC_FULL_VERSION MATCHES "4.8.1.*ubuntu")
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--no-as-needed -pthread")
else()
set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
endif()
else()
set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
endif()
list(APPEND LIBS "pthread")
add_definitions(-pthread)
endif()
endif()
endif(CMAKE_HOST_UNIX)
list(APPEND LIBS ${READLINE_LIB})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_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}")
add_library(stdlib STATIC static_libs/chaiscript_stdlib.cpp)
add_library(parser STATIC static_libs/chaiscript_parser.cpp)
if (CMAKE_COMPILER_2005)
# vs2005 is a bit too loud about possible loss of data warnings
# ADD_DEFINITIONS(/wd4244)
endif()
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp)
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
set(CHAISCRIPT_LIBS stdlib parser)
add_library(chaiscript_stdlib MODULE src/chaiscript_stdlib.cpp)
target_link_libraries(chaiscript_stdlib ${LIBS} ${EXTRA_LINKER_FLAGS})
add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
add_library(chaiscript INTERFACE)
target_include_directories(chaiscript INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(chai ${LIBS} ${EXTRA_LINKER_FLAGS})
add_dependencies(chai chaiscript_stdlib)
if (BUILD_SAMPLES)
add_executable(sanity_checks src/sanity_checks.cpp)
target_link_libraries(sanity_checks ${LIBS})
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(example samples/example.cpp)
target_link_libraries(example ${LIBS} ${EXTRA_LINKER_FLAGS})
add_executable(memory_leak_test samples/memory_leak_test.cpp)
target_link_libraries(memory_leak_test ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(factory samples/factory.cpp)
target_link_libraries(factory ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(fun_call_performance samples/fun_call_performance.cpp)
target_link_libraries(fun_call_performance ${LIBS} ${CHAISCRIPT_LIBS})
target_link_libraries(memory_leak_test ${LIBS} ${EXTRA_LINKER_FLAGS})
endif()
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)
target_link_libraries(stl_extra ${LIBS})
target_link_libraries(stl_extra ${LIBS} ${EXTRA_LINKER_FLAGS})
set(MODULES stl_extra)
add_library(reflection MODULE src/reflection.cpp)
target_link_libraries(reflection ${LIBS} ${EXTRA_LINKER_FLAGS})
set(MODULES stl_extra reflection)
endif()
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)
file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/*.chai)
list(SORT PERFORMANCE_TESTS)
if(RUN_FUZZY_TESTS)
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2017-07-20.tar.bz2
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
)
file(GLOB FUZZY_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/MINIMIZED/*)
list(SORT FUZZY_TESTS)
foreach(filename ${FUZZY_TESTS})
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})
endforeach()
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
endif()
if(BUILD_TESTING)
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }")
set_property(TEST version_check
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
add_test(version_check_2 chai --version )
set_property(TEST version_check_2
PROPERTY ENVIRONMENT
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
PROPERTY PASS_REGULAR_EXPRESSION "${CHAI_VERSION}"
)
add_test(help chai --help )
set_property(TEST help
PROPERTY ENVIRONMENT
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
set(TESTS "")
foreach(filename ${UNIT_TESTS})
message(STATUS "Adding unit test ${filename}")
add_test(unit.${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
list(APPEND TESTS unit.${filename})
endforeach()
message(STATUS "Adding test ${filename}")
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
endforeach(filename)
if(RUN_PERFORMANCE_TESTS)
foreach(filename ${PERFORMANCE_TESTS})
message(STATUS "Adding performance test ${filename}")
add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $<TARGET_FILE:chai> ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename})
list(APPEND TESTS performance.${filename})
endforeach()
add_executable(profile_cpp_calls_2 performance_tests/profile_cpp_calls_2.cpp)
target_link_libraries(profile_cpp_calls_2 ${LIBS})
add_test(NAME performance.profile_cpp_calls_2 COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_cpp_calls_2 $<TARGET_FILE:profile_cpp_calls_2>)
add_executable(profile_fun_wrappers performance_tests/profile_fun_wrappers.cpp)
target_link_libraries(profile_fun_wrappers ${LIBS})
add_test(NAME performance.profile_fun_wrappers COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_fun_wrappers $<TARGET_FILE:profile_fun_wrappers>)
endif()
set_property(TEST ${TESTS}
set_property(TEST ${UNIT_TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
if (NOT UNIT_TEST_LIGHT)
add_executable(compiled_tests unittests/compiled_tests.cpp)
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS})
catch_discover_tests(compiled_tests TEST_PREFIX "compiled.")
add_executable(utility_test unittests/utility_test.cpp)
target_link_libraries(utility_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Utility_Test COMMAND utility_test)
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(dynamic_object_test unittests/dynamic_object_test.cpp)
target_link_libraries(dynamic_object_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Dynamic_Object_Test COMMAND dynamic_object_test)
add_executable(functor_creation_test unittests/functor_creation_test.cpp)
target_link_libraries(functor_creation_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Functor_Creation_Test COMMAND functor_creation_test)
add_executable(functor_cast_test unittests/functor_cast_test.cpp)
target_link_libraries(functor_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Functor_Cast_Test COMMAND functor_cast_test)
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
target_link_libraries(boxed_cast_test ${LIBS})
target_link_libraries(boxed_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
add_executable(object_lifetime_test unittests/object_lifetime_test.cpp)
target_link_libraries(object_lifetime_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Object_Lifetime_Test COMMAND object_lifetime_test)
add_executable(function_ordering_test unittests/function_ordering_test.cpp)
target_link_libraries(function_ordering_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Function_Ordering_Test COMMAND function_ordering_test)
add_executable(type_info_test unittests/type_info_test.cpp)
target_link_libraries(type_info_test ${LIBS})
target_link_libraries(type_info_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Type_Info_Test COMMAND type_info_test)
add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp)
target_link_libraries(eval_catch_exception_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)
add_executable(short_comparison_test unittests/short_comparison_test.cpp)
target_link_libraries(short_comparison_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Short_Comparison_Test COMMAND short_comparison_test)
add_executable(cpp_lambda_test unittests/cpp_lambda_test.cpp)
target_link_libraries(cpp_lambda_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME cpp_lambda_test COMMAND cpp_lambda_test)
add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp)
target_link_libraries(expected_eval_errors_test ${LIBS})
add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test)
add_executable(set_state_test unittests/set_state_test.cpp)
target_link_libraries(set_state_test ${LIBS})
add_test(NAME Set_State_Test COMMAND set_state_test)
add_executable(simultaneous_chaiscript_test unittests/simultaneous_chaiscript_test.cpp)
target_link_libraries(simultaneous_chaiscript_test ${LIBS})
add_test(NAME Simultaneous_Chaiscript_Test COMMAND simultaneous_chaiscript_test)
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_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_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp)
target_link_libraries(arithmetic_conversions_test ${LIBS})
add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test)
if (MULTITHREAD_SUPPORT_ENABLED)
add_executable(multithreaded_test unittests/multithreaded_test.cpp)
target_link_libraries(multithreaded_test ${LIBS})
@ -403,30 +252,23 @@ if(BUILD_TESTING)
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
endif()
add_executable(multifile_test
unittests/multifile_test_main.cpp
unittests/multifile_test_chai.cpp
unittests/multifile_test_module.cpp
)
target_link_libraries(multifile_test ${LIBS})
add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp
unittests/multifile_test_module.cpp)
target_link_libraries(multifile_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME MultiFile_Test COMMAND multifile_test)
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
endif()
add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${LIBS} ${EXTRA_LINKER_FLAGS})
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
endif()
endif(BUILD_TESTING)
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(TARGETS chai ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript )
install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp"
PATTERN "*/.svn*" EXCLUDE
@ -446,6 +288,5 @@ install(DIRECTORY samples DESTINATION share/chaiscript
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
DESTINATION lib/pkgconfig)

View File

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

File diff suppressed because it is too large Load Diff

31
LICENSE
View File

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

View File

@ -1,23 +0,0 @@
version: 6.1.x.{build}
image:
- Visual Studio 2019
environment:
matrix:
- VS_VERSION: "Visual Studio 16"
build_script:
- cmd: >-
mkdir build
cd build
cmake c:\Projects\chaiscript -G "%VS_VERSION%" -DBUILD_TESTING:BOOL=ON -DBUILD_MODULES:BOOL=ON
cmake --build . --config Debug
test_script:
- cmd: ctest -C Debug
notifications:
- provider: Webhook
url: https://webhooks.gitter.im/e/9ff725a985b5679d1d5d
on_build_success: true
on_build_failure: true
on_build_status_changed: false

View File

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

View File

@ -1,3 +0,0 @@
{
"name": "ChaiScript"
}

View File

@ -1,602 +0,0 @@
# ChaiScript Versioning
ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme. This basically means:
* Major Version Number: API changes / breaking changes
* Minor Version Number: New Features
* Patch Version Number: Minor changes / enhancements
# Initializing ChaiScript
```
chaiscript::ChaiScript chai; // initializes ChaiScript, adding the standard ChaiScript types (map, string, ...)
```
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 a Function / Method / Member
### General
```cpp
chai.add(chaiscript::fun(&function_name), "function_name");
chai.add(chaiscript::fun(&Class::method_name), "method_name");
chai.add(chaiscript::fun(&Class::member_name), "member_name");
```
### Bound Member Functions
```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
```cpp
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
```
#### 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
```cpp
struct Base
{
int data;
};
struct Derived : public Base
{};
chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
```
### Lambda
```cpp
chai.add(
chaiscript::fun<std::function<std::string (bool)>>(
[](bool type) {
if (type) { return "x"; }
else { return "y"; }
}), "function_name");
```
### Constructors
```cpp
chai.add(chaiscript::constructor<MyType ()>(), "MyType");
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
```
## Adding Types
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
```cpp
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
```
## Adding Type Conversions
User-defined type conversions are possible, defined in either script or in C++.
### ChaiScript Defined Conversions
Function objects (including lambdas) can be used to add type conversions
from inside of ChaiScript:
```
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
```
### C++ Defined Conversions
Invoking a C++ type conversion possible with `static_cast`
```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:
```
chai.add(chaiscript::vector_conversion<std::vector<int>>());
```
A helper function also exists for strongly typed and ChaiScript `Map` function conversion definition:
```
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
```
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
## Adding Objects
```
chai.add(chaiscript::var(somevar), "somevar"); // copied in
chai.add(chaiscript::var(std::ref(somevar)), "somevar"); // by reference, shared between C++ and chai
auto shareddouble = std::make_shared<double>(4.3);
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const, throws if object exists
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
```
## 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
ChaiScript recognizes many types from STL, but you have to add specific instantiation yourself.
```cpp
typedef std::vector<std::pair<int, std::string>> data_list;
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
chai.add(chaiscript::bootstrap::standard_library::pair_type<data_list::value_type>("DataElement"));
chai.add(chaiscript::var(&my_list), "data_list");
chai.eval(R"_(
for(var i=0; i<data_list.size(); ++i)
{
print(to_string(data_list[i].first) + " " + data_list[i].second)
}
)_");
```
# Executing Script
## General
```cpp
chai.eval("print(\"Hello World\")");
chai.eval(R"(print("Hello World"))");
```
## Unboxing Return Values
Returns values are of the type `Boxed_Value` which is meant to be opaque to the programmer. Use one of the unboxing methods to access the internal data.
### Prefered
```cpp
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
```
### Alternative
```cpp
auto v = chai.eval("5.3 + 2.1");
chai.boxed_cast<double>(v); // extracts double value from boxed_value and applies known conversions
chaiscript::boxed_cast<double>(v); // free function version, does not know about conversions
```
### Converting Between Algebraic Types
```cpp
chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with any number type
// which is equivalent to, but much more automatic than:
static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
```
### Conversion Caveats
Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you attempt to keep a reference to a `shared_ptr<>` you might invoke undefined behavior
```cpp
// ok this is supported, you can register it with chaiscript engine
void nullify_shared_ptr(std::shared_ptr<int> &t) {
t = nullptr
}
```
```cpp
int main()
{
// do some stuff and create a chaiscript instance
std::shared_ptr<int> &ptr = chai.eval<std::shared_ptr<int> &>(somevalue);
// DO NOT do this. Taking a non-const reference to a shared_ptr is not
// supported and causes undefined behavior in the chaiscript engine
}
```
## Sharing Values
```cpp
double &d = chai.eval("var i = 5.2; i"); // d is now a reference to i in the script
std::shared_ptr<double> d = chai.eval("var i = 5.2; i"); // same result but reference counted
d = 3;
chai.eval("print(i)"); // prints 3
```
## Catching Eval Errors
```cpp
try {
chai.eval("2.3 + \"String\"");
} catch (const chaiscript::exception::eval_error &e) {
std::cout << "Error\n" << e.pretty_print() << '\n';
}
```
## Catching Errors Thrown From Script
```cpp
try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double e) {
} catch (int) {
} catch (float) {
} catch (const std::string &) {
} catch (const std::exception &e) {
// This is the one that will be called in the specific throw() above
}
```
## Sharing Functions
```cpp
auto p = chai.eval<std::function<std::string (double)>>("to_string");
p(5); // calls chaiscript's 'to_string' function, returning std::string("5")
```
Note: backtick treats operators as normal functions
```cpp
auto p = chai.eval<std::function<int (int, int)>>("`+`");
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); }");
p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
```
# Language Reference
## Variables
```
var i; // uninitialized variable, can take any value on first assignment;
auto j; // equiv to var
var k = 5; // initialized to 5 (integer)
var l := k; // reference to k
auto &m = k; // reference to k
global g = 5; // creates a global variable. If global already exists, it is not re-added
global g = 2; // global 'g' now equals 2
global g2;
if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hit more than once
GLOBAL g3; // all upper case version also accepted
```
## Looping
```
// c-style for loops
for (var i = 0; i < 100; ++i) { print(i); }
```
```
// while
while (some_condition()) { /* do something */ }
```
```
// ranged for
for (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 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
such as `f`, `ll`, `u` as well as scientific notation are supported
```
1.0 // double
1.0f // float
1.0l // long double
1 // int
1u // unsigned int
1ul // unsigned long
1ull // unsigned long long
```
Literals are automatically sized, just as in C++. For example: `10000000000` is > 32bits and the appropriate type is used to hold it
on your platform.
## Functions
Note that any type of ChaiScript function can be passed freely to C++ and automatically
converted into a `std::function` object.
### General
```
def myfun(x, y) { x + y; } // last statement in body is the return value
def myfun(x, y) { return x + y; } // equiv
```
### Optionally Typed
```
def myfun(x, int y) { x + y; } // requires y to be an int
```
### With Guards
```
def myfun(x, int y) : y > 5 { x - y; } // only called if y > 5
```
### Methods
Methods and functions are mostly equivalent
```
def string::add(int y) { this + to_string(y); }
def add(string s, int y) { s + to_string(y); } //equiv functionality
// calling new function/method
"a".add(1); // returns a1
add("a", 1); // returns a1, either calling syntax works with either def above
```
### Lambdas
```
var l = fun(x) { x * 15; }
l(2) // returns 30
var a = 13
var m = fun[a](x) { x * a; }
m(3); // a was captured (by reference), returns 39
var n = bind(fun(x,y) { x * y; }, _, 10);
n(2); // returns 20
```
## ChaiScript Defined Types
Define a type called "MyType" with one member value "a" and a getter
### Preferred
```
class MyType {
var value;
def MyType() { this.value = "a"; }
def get_value() { "Value Is: " + this.value; }
};
```
### Alternative
```
attr MyType::value;
def MyType::MyType() { this.value = "a"; }
def MyType::get_value() { "Value Is: " + this.value; }
```
### Using
```
var m = MyType(); // calls constructor
print(m.get_value()); // prints "Value Is: a"
print(get_value(m)); // prints "Value Is: a"
```
## Dynamic Objects
All ChaiScript defined types and generic Dynamic_Object support dynamic parameters
```
var o = Dynamic_Object();
o.f = fun(x) { print(x); }
o.f(3); // prints "3"
```
Implicit 'this' is allowed:
```
var o = Dynamic_Object();
o.x = 3;
o.f = fun(y) { print(this.x + y); }
o.f(10); // prints 13
```
## 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
If you want to disable dynamic parameter definitions, you can `set_explicit`.
```
class My_Class {
def My_Class() {
this.set_explicit(true);
this.x = 2; // this would fail with explicit set to true
}
};
```
## method_missing
A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate
method cannot be found
```
def method_missing(int i, string name, Vector v) {
print("method_missing(${i}, ${name}), ${v.size()} params");
}
5.bob(1,2,3); // prints "method_missing(5, bob, 3 params)"
```
`method_missing` signature can be either 2 parameters or 3 parameters. If the signature contains two parameters
it is treated as a property. If the property contains a function then additional parameters are passed to
the contained function.
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
## Context
* `__LINE__` Current file line number
* `__FILE__` Full path of current file
* `__CLASS__` Name of current class
* `__FUNC__` Name of current function
# Built-in Functions
## Evaluation
```
eval("4 + 5") // dynamically eval script string and returns value of last statement
eval_file("filename") // evals file and returns value of last statement
use("filename") // evals file exactly once and returns value of last statement
// if the file had already been 'used' nothing happens and undefined is returned
```
Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor
## JSON
* `from_json` converts a JSON string into its strongly typed (map, vector, int, double, string) representations
* `to_json` converts a ChaiScript object (either a `Object` or one of map, vector, int, double, string) tree into its JSON string representation
## 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

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
def isprime(n)
{
for (var i = 2; i < n; ++i)
for (auto i = 2; i < n; ++i)
{
if (n % i == 0) {return false}
}
@ -11,8 +11,8 @@ def isprime(n)
def primes(n)
{
var count = 0
for (var i = 2; i <= n; ++i)
auto count = 0
for (auto i = 2; i <= n; ++i)
{
if (isprime(i)) {++count}
}
@ -21,6 +21,6 @@ def primes(n)
}
var N = 5000
auto N = 5000
print("primes: " + primes(N).to_string())

View File

@ -1,16 +0,0 @@
#!/bin/bash
pushd ..
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2
tar -xvf cppcheck-1.66.tar.bz2
cd cppcheck-1.66
make -j2
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
sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output
echo -n '{ "body": " ' > output.json
echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json
echo -n '"}' >> output.json
if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then curl -H "Authorization: token ${TOKEN}" --request POST --data @output.json https://api.github.com/repos/ChaiScript/ChaiScript/commits/${TRAVIS_COMMIT}/comments; else curl -H "Authorization: token ${TOKEN}" --request POST --data @output.json https://api.github.com/repos/ChaiScript/ChaiScript/issues/${TRAVIS_PULL_REQUEST}/comments; fi

View File

@ -38,7 +38,7 @@
************************************************************************************/
$language_data = array (
'LANG_NAME' => 'ChaiScript',
'LANG_NAME' => 'Chaiscript',
'COMMENT_SINGLE' => array(1 => '//'),
'COMMENT_MULTI' => array('/*' => '*/'),
//Regular Expressions

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,17 +1,16 @@
// 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)
// and 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_HPP_
#define CHAISCRIPT_HPP_
/// @mainpage
/// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
/// \mainpage
/// <a href="http://www.chaiscript.com">ChaiScript</a> 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.
///
/// The parts of the ChaiScript API that the average user will be concerned with are contained in the
@ -19,43 +18,42 @@
///
/// 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
/// [github](http://www.github.com/ChaiScript/ChaiScript").
/// Currently, all source control and project management aspects of ChaiScript occur on <a href="http://www.github.com/ChaiScript/ChaiScript">github</a>.
///
/// ------------------------------------------------------------
/// <hr>
///
/// @sa chaiscript
/// @sa chaiscript::ChaiScript
/// @sa ChaiScript_Language for Built in Functions
/// @sa @ref LangGettingStarted
/// @sa @ref LangKeywordRef
/// @sa @ref LangInPlaceRef
/// @sa @ref LangObjectSystemRef
/// @sa http://www.chaiscript.com
/// @sa http://www.github.com/ChaiScript/ChaiScript
/// \sa chaiscript
/// \sa chaiscript::ChaiScript
/// \sa ChaiScript_Language for Built in Functions
/// \sa \ref LangGettingStarted
/// \sa \ref LangKeywordRef
/// \sa \ref LangInPlaceRef
/// \sa \ref LangObjectSystemRef
/// \sa http://www.chaiscript.com
/// \sa http://www.github.com/ChaiScript/ChaiScript
///
/// -----------------------------------------------------------
/// <hr>
///
/// @section gettingstarted API Getting Started
/// \section gettingstarted API Getting Started
///
/// - @ref basics
/// - @ref compiling
/// - @ref eval
/// - @ref adding_items
/// - @ref operatoroverloading
/// - @ref add_class
/// - @ref pointer_conversions
/// - @ref baseclasses
/// - @ref functionobjects
/// - @ref threading
/// - @ref exceptions
/// \li \ref basics
/// \li \ref compiling
/// \li \ref eval
/// \li \ref addingitems
/// \li \ref operatoroverloading
/// \li \ref helpermacro
/// \li \ref pointerconversions
/// \li \ref baseclasses
/// \li \ref functionobjects
/// \li \ref threading
/// \li \ref exceptions
///
///
/// @subsection basics Basics
/// \subsection basics Basics
///
/// Basic simple example:
///
/// ~~~~~~~{.cpp}
/// \code
/// //main.cpp
/// #include <chaiscript/chaiscript.hpp>
///
@ -67,119 +65,115 @@
/// int main()
/// {
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::fun(&function), "function");
/// chai.add(&function, "function");
///
/// double d = chai.eval<double>("function(3, 4.75);");
/// }
/// ~~~~~~~
/// \endcode
///
/// ------------------------------------------------------
/// <hr>
/// \subsection compiling Compiling ChaiScript Applications
///
/// @subsection compiling Compiling ChaiScript Applications
///
/// ChaiScript is a header only library with only one dependency: The
/// ChaiScript is a header only library with only one dependecy: The
/// 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
/// the dynamic loader. For example:
///
/// ~~~~~~~~
/// \code
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl
/// ~~~~~~~~
/// \endcode
///
/// Alternatively, you may compile without threading support.
///
/// ~~~~~~~~
/// \code
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl -DCHAISCRIPT_NO_THREADS
/// ~~~~~~~~
/// \endcode
///
/// ------------------------------------------
///
/// @subsection eval Evaluating Scripts
/// <hr>
/// \subsection eval Evaluating Scripts
///
/// Scripts can be evaluated with the () operator, eval method or eval_file method.
///
/// @subsubsection parenoperator () Operator
/// \subsubsection parenoperator () Operator
///
/// operator() can be used as a handy shortcut for evaluating ChaiScript snippets.
///
/// ~~~~~~~~{.cpp}
/// \code
/// chaiscript::ChaiScript chai;
/// chai("print(@"hello world@")");
/// ~~~~~~~~
/// chai("print(\"hello world\")");
/// \endcode
///
/// @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 typesafely return values
/// from the script.
///
/// ~~~~~~~~{.cpp}
/// \code
/// chaiscript::ChaiScript chai;
/// chai.eval("callsomefunc()");
/// int result = chai.eval<int>("1 + 3");
/// // result now equals 4
/// ~~~~~~~~
/// \endcode
///
/// @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
///
/// ~~~~~~~~{.cpp}
/// \code
/// chaiscript::ChaiScript chai;
/// chai.eval_file("myfile.chai");
/// std::string result = chai.eval_file<std::string>("myfile.chai") // extract the last value returned from the file
/// ~~~~~~~~
/// \endcode
///
/// @sa chaiscript::ChaiScript::eval_file
/// \sa chaiscript::ChaiScript::eval_file
///
/// --------------------------------------------------
///
/// @subsection adding_items Adding Items to ChaiScript
/// <hr>
/// \subsection addingitems Adding Items to ChaiScript
///
/// ChaiScript supports 4 basic things that can be added: objects, functions, type infos and Modules
///
/// @subsubsection adding_objects Adding Objects
/// \subsubsection addingobjects Adding Objects
///
/// 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
/// threads that need to access the same variables you will need to add them
/// separately for each thread, from the thread itself.
///
/// ~~~~~~~~~{.cpp}
/// \code
/// using namespace chaiscript;
/// ChaiScript chai;
/// int i = 5;
/// chai.add(var(i), "i");
/// chai("print(i)");
/// ~~~~~~~~~
/// \endcode
///
/// Immutable objects can be created with the chaiscript::const_var function.
///
/// ~~~~~~~~~{.cpp}
/// \code
/// chai.add(const_var(i), "i");
/// chai("i = 5"); // exception throw, cannot assign const var
/// ~~~~~~~~~
/// \endcode
///
/// 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
/// chaiscript::ChaiScript::add_global_const function.
///
/// ~~~~~~~~~{.cpp}
/// \code
/// chai.add_global_const(const_var(i), "i");
/// chai("def somefun() { print(i); }; somefun();");
/// ~~~~~~~~~
/// chai("def somefun() { print(i); }; sumfun();");
/// \endcode
///
/// @subsubsection adding_functions Adding Functions
/// \subsubsection addingfunctions Adding Functions
///
/// Functions, methods and members are all added using the same function: chaiscript::fun.
///
/// ~~~~~~~~~{.cpp}
/// \code
/// using namespace chaiscript;
///
/// class MyClass {
@ -196,26 +190,26 @@
/// chai.add(fun(&MyClass::memberdata), "memberdata");
/// chai.add(fun(&MyClass::method), "method");
/// chai.add(fun(&MyClass::staticmethod), "staticmethod");
/// ~~~~~~~~~
/// \endcode
///
/// Overloaded methods will need some help, to hint the compiler as to which overload you want:
///
/// ~~~~~~~~~{.cpp}
/// \code
/// chai.add(fun<void (MyClass::*)()>(&MyClass::overloadedmethod), "overloadedmethod");
/// chai.add(fun<void (MyClass::*)(const std::string &)>(&MyClass::overloadedmethod), "overloadedmethod");
/// ~~~~~~~~~
/// \endcode
///
/// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function.
///
/// ~~~~~~~~~{.cpp}
/// \code
/// MyClass obj;
/// chai.add(fun(&MyClass::method, &obj), "method");
/// chai("method()"); // equiv to obj.method()
/// chai.add(fun(&MyClass::method2, &obj, 3), "method2");
/// chai("method2()"); // equiv to obj.method2(3)
/// ~~~~~~~~~
/// \endcode
///
/// @subsubsection addingtypeinfo Adding Type Info
/// \subsubsection addingtypeinfo Adding Type Info
///
/// 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
@ -225,28 +219,27 @@
///
/// Continuing with the example "MyClass" from above:
///
/// ~~~~~~~~{.cpp}
/// \code
/// chai.add(user_type<MyClass>(), "MyClass");
/// ~~~~~~~~
/// \endcode
///
/// @subsubsection adding_modules Adding Modules
/// \subsubsection addingmodules Adding Modules
///
/// Modules are holders for collections of ChaiScript registrations.
///
/// ~~~~~~~~{.cpp}
/// \code
/// ModulePtr module = get_sum_module();
/// chai.add(module);
/// ~~~~~~~~
/// \endcode
///
/// @sa chaiscript::Module
/// \sa chaiscript::Module
///
/// -----------------------------------------------------------------------
///
/// @subsection operatoroverloading Operator Overloading
/// <hr>
/// \subsection operatoroverloading Operator Overloading
///
/// Operators are just like any other function in ChaiScript, to overload an operator, simply register it.
///
/// ~~~~~~~~{.cpp}
/// \code
/// class MyClass {
/// MyClass operator+(const MyClass &) const;
/// };
@ -261,18 +254,17 @@
/// }
///
/// chai.add(fun(append_string_int), "+");
/// ~~~~~~~~
/// \endcode
///
/// @sa @ref adding_functions
/// \sa \ref addingfunctions
///
/// -----------------------------------------------------------------------
///
/// @subsection add_class Class Helper Utility
/// <hr>
/// \subsection helpermacro Class Helper Macro
///
/// Much of the work of adding new classes to ChaiScript can be reduced with the help
/// of the add_class helper utility.
/// of the CHAISCRIPT_CLASS helper macro.
///
/// ~~~~~~~~{.cpp}
/// \code
/// class Test
/// {
/// public:
@ -285,40 +277,40 @@
///
/// int main()
/// {
///
/// chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
///
/// chaiscript::utility::add_class<chaiscript::Test>(*m,
/// "Test",
/// { constructor<Test()>(),
/// constructor<Test(const Test &)>() },
/// { {fun(&Test::function), "function"},
/// {fun(&Test::function2), "function2"},
/// {fun(&Test::function2), "function3"}
/// {fun(static_cast<std::string Test::*(double)>(&Test::functionOverload)), "functionOverload"}
/// {fun(static_cast<std::string Test::*(int)>(&Test::functionOverload)), "functionOverload"} }
/// CHAISCRIPT_CLASS( m,
/// Test,
/// (Test ())
/// (Test (const Test &)),
/// ((function))
/// ((function2))
/// ((function3))
/// ((functionOverload)(std::string (Test::*)(double)))
/// ((functionOverload)(std::string (Test::*)(int)))
/// ((operator=))
/// );
///
///
/// chaiscript::ChaiScript chai;
/// chai.add(m);
/// }
/// ~~~~~~~~
/// \endcode
///
/// @sa @ref adding_modules
/// \sa \ref addingmodules
///
/// -----------------------------------------------------------------------
///
/// @subsection pointer_conversions Pointer / Object Conversions
/// <hr>
/// \subsection pointerconversions Pointer / Object Conversions
///
/// 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.
///
/// 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). Const may be added, but never removed.
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be convered to a shared_ptr (this would add invalid reference counting).
/// 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.
///
/// ~~~~~~~~{.cpp}
/// \code
/// void fun1(const int *);
/// void fun2(int *);
/// void fun3(int);
@ -358,19 +350,18 @@
/// chai("fun9(i)");
/// chai("fun10(i)");
/// }
/// ~~~~~~~~
/// \endcode
///
/// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that
/// available and tested.
///
/// -----------------------------------------------------------------------
///
/// @subsection baseclasses Base Classes
/// <hr>
/// \subsection baseclasses Base Classes
///
/// 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.
///
/// ~~~~~~~~{.cpp}
/// \code
/// class Base {};
/// class Derived : public Base {};
/// void myfunction(Base *b);
@ -384,17 +375,16 @@
/// chai.add(chaiscript::fun(&myfunction), "myfunction");
/// chai("myfunction(d)");
/// }
/// ~~~~~~~~
/// \endcode
///
/// -----------------------------------------------------------------------
/// <hr>
///
/// \subsection functionobjects Function Objects
///
/// @subsection functionobjects Function Objects
///
/// Functions are first class objects in ChaiScript and ChaiScript supports automatic conversion
/// Functions are first class objects in Chaiscript and ChaiScript supports automatic conversion
/// between ChaiScript functions and std::function objects.
///
/// ~~~~~~~~{.cpp}
/// \code
/// void callafunc(const std::function<void (const std::string &)> &t_func)
/// {
/// t_func("bob");
@ -410,12 +400,11 @@
/// std::function<void ()> f = chai.eval<std::function<void ()> >("dump_system");
/// f(); // call the ChaiScript function dump_system, from C++
/// }
/// ~~~~~~~~
/// \endcode
///
/// -----------------------------------------------------------------------
/// <hr>
///
///
/// @subsection threading Threading
/// \subsection threading Threading
///
/// 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
@ -425,17 +414,16 @@
///
/// Disabling thread safety increases performance in many cases.
///
/// -----------------------------------------------------------------------
/// <hr>
///
/// \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
/// ChaiScript.
///
/// ~~~~~~~~{.cpp}
/// \code
/// void throwexception()
/// {
/// throw std::runtime_error("err");
@ -456,20 +444,19 @@
/// // i == 1
/// }
/// }
/// ~~~~~~~~
/// \endcode
///
/// @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
/// ChaiScript what possible exceptions are expected from the script being executed.
///
/// Example:
/// ~~~~~~~~{.cpp}
/// \code
/// chaiscript::ChaiScript chai;
///
/// 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 (int) {
/// } catch (float) {
@ -477,17 +464,19 @@
/// } catch (const std::exception &e) {
/// // This is the one what will be called in the specific throw() above
/// }
/// ~~~~~~~~
/// \endcode
///
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
/// @sa chaiscript::exception_specification
/// \sa chaiscript::Exception_Handler for details on automatic exception unboxing
/// \sa chaiscript::exception_specification
/// @page LangObjectSystemRef ChaiScript Language Object Model Reference
/// \page LangObjectSystemRef ChaiScript Language Object Model Reference
///
///
/// ChaiScript has an object system built in, for types defined within the ChaiScript system.
///
/// ~~~~~~~~~
/// \code
/// attr Rectangle::height
/// attr Rectangle::width
/// def Rectangle::Rectangle() { this.height = 10; this.width = 20 }
@ -496,84 +485,67 @@
/// var rect = Rectangle()
/// rect.height = 30
/// print(rect.area())
/// ~~~~~~~~~
/// \endcode
///
/// Since ChaiScript 5.4.0 it has been possible to use the "class" keyword to simplify this code.
///
/// ~~~~~~~~~
/// class Rectangle {
/// attr height
/// attr width
/// def Rectangle() { this.height = 10; this.width = 20 }
/// def area() { this.height * this.width }
/// }
///
/// var rect = Rectangle()
/// rect.height = 30
/// print(rect.area())
/// ~~~~~~~~~
///
/// @sa @ref keywordattr
/// @sa @ref keyworddef
/// \sa \ref keywordattr
/// \sa \ref keyworddef
/// @page LangInPlaceRef ChaiScript Language In-Place Creation Reference
/// @section inplacevector Vector
/// \page LangInPlaceRef ChaiScript Language In-Place Creation Reference
/// \section inplacevector Vector
///
/// ~~~~~~~~~
/// \code
/// In-place Vector ::= "[" [expression ("," expression)*] "]"
/// ~~~~~~~~~
/// \endcode
///
/// @section inplacerangedvector Ranged Vector
/// \section inplacerangedvector Ranged Vector
///
/// ~~~~~~~~~
/// \code
/// In-place Ranged Vector ::= "[" value ".." value "]"
/// ~~~~~~~~~
/// \endcode
///
/// Creates a vector over a range (eg. 1..10)
///
/// @section inplacemap Map
/// \section inplacemap Map
///
/// ~~~~~~~~
/// \code
/// In-place Map ::= "[" (string ":" expression)+ "]"
/// ~~~~~~~~
/// \endcode
/// @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
/// C++ or ECMAScript (JavaScript).
///
/// -----------------------------------------------------------------------
///
/// @section chaiscriptloops Loops
/// <hr>
/// \section chaiscriptloops Loops
///
/// Common looping constructs exist in ChaiScript
///
/// ~~~~~~~~
/// \code
/// var i = 0;
/// while (i < 10)
/// {
/// // do something
/// ++i;
/// }
/// ~~~~~~~~
/// \endcode
///
/// ~~~~~~~~
/// \code
/// for (var i = 0; i < 10; ++i)
/// {
/// // do something
/// }
/// ~~~~~~~~
/// \endcode
///
/// @sa @ref keywordfor
/// @sa @ref keywordwhile
/// \sa \ref keywordfor
/// \sa \ref keywordwhile
///
/// -----------------------------------------------------------------------
///
/// @section chaiscriptifs Conditionals
/// <hr>
/// \section chaiscriptifs Conditionals
///
/// If statements work as expected
///
/// ~~~~~~~~
/// \code
/// var b = true;
///
/// if (b) {
@ -583,124 +555,107 @@
/// } else {
/// // or do this
/// }
/// ~~~~~~~~
/// \endcode
///
/// @sa @ref keywordif
/// \sa \ref keywordif
///
/// -----------------------------------------------------------------------
///
/// @section chaiscriptfunctions Functions
/// <hr>
/// \section chaiscriptfunctions Functions
///
/// Functions are defined with the def keyword
///
/// ~~~~~~~~
/// \code
/// def myfun(x) { print(x); }
///
/// myfun(10);
/// ~~~~~~~~
/// \endcode
///
/// Functions may have "guards" which determine if which is called.
///
/// ~~~~~~~~
/// \code
/// eval> def myfun2(x) : x < 10 { print("less than 10"); }
/// eval> def myfun2(x) : x >= 10 { print("10 or greater"); }
/// eval> myfun2(5)
/// less than 10
/// eval> myfun2(12)
/// 10 or greater
/// ~~~~~~~~
/// \endcode
///
/// @sa @ref keyworddef
/// @sa @ref keywordattr
/// @sa @ref LangObjectSystemRef
/// \sa \ref keyworddef
/// \sa \ref keywordattr
/// \sa \ref LangObjectSystemRef
///
/// -----------------------------------------------------------------------
///
/// @section chaiscriptfunctionobjects Function Objects
/// <hr>
/// \section chaiscriptfunctionobjects Function Objects
///
/// Functions are first class types in ChaiScript and can be used as variables.
///
/// ~~~~~~~~
/// \code
/// eval> var p = print;
/// eval> p(1);
/// 1
/// ~~~~~~~~
/// \endcode
///
/// They can also be passed to functions.
///
/// ~~~~~~~~
/// \code
/// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); }
/// eval> def do_something(lhs, rhs) { print("lhs: ${lhs}, rhs: ${rhs}"); }
/// eval> callfunc(do_something, 1, 2);
/// eval> def dosomething(lhs, rhs) { print("lhs: ${lhs}, rhs: ${rhs}"); }
/// eval> callfunc(dosomething, 1, 2);
/// lhs: 1, rhs: 2
/// ~~~~~~~~
/// \endcode
///
/// Operators can also be treated as functions by using the back tick operator. Building on the above example:
///
/// ~~~~~~~~
/// \code
/// eval> callfunc(`+`, 1, 4);
/// 5
/// eval> callfunc(`*`, 3, 2);
/// 6
/// ~~~~~~~~
/// \endcode
///
/// -----------------------------------------------------------------------
///
/// @sa @ref LangKeywordRef
/// @sa ChaiScript_Language for Built in Functions
/// <hr>
/// \sa \ref LangKeywordRef
/// \sa ChaiScript_Language for Built in Functions
/// @page LangKeywordRef ChaiScript Language Keyword Reference
/// \page LangKeywordRef ChaiScript Language Keyword Reference
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordattr attr
/// <hr>
/// \section keywordattr attr
/// Defines a ChaiScript object attribute
///
/// ~~~~~~~~
/// \code
/// Attribute Definition ::= "attr" class_name "::" attribute_name
/// ~~~~~~~~
/// \endcode
///
/// @sa @ref LangObjectSystemRef
/// \sa \ref LangObjectSystemRef
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordauto auto
///
/// Defines a variable
///
/// ~~~~~~~~
/// Variable ::= "auto" identifier
/// ~~~~~~~~
///
/// Synonym for @ref keywordvar
///
/// -----------------------------------------------------------------------
///
/// @section keywordbreak break
/// <hr>
/// \section keywordbreak break
/// Stops execution of a looping block.
///
/// ~~~~~~~~
/// \code
/// Break Statement ::= "break"
/// ~~~~~~~~
/// \endcode
///
/// @sa @ref keywordfor
/// @sa @ref keywordwhile
/// \sa \ref keywordfor
/// \sa \ref keywordwhile
///
///
/// -----------------------------------------------------------------------
///
/// @section keyworddef def
/// <hr>
/// \section keyworddef def
/// Begins a function or method definition
///
/// ~~~~~~~~
/// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// ~~~~~~~~
/// \code
/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [arg ("," arg)*] ")" [":" guard] block
/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [arg ("," arg)*] ")" [":" guard] block
/// \endcode
///
/// annotation: meta-annotation on function, currently used as documentation. Optional.
/// identifier: name of function. Required.
/// args: comma-delimited list of parameter names with optional type specifiers. Optional.
/// args: comma-delimited list of parameter names. Optional.
/// guards: guarding statement that act as a prerequisite for the function. Optional.
/// { }: scoped block as function body. Required.
///
@ -712,56 +667,50 @@
/// Method definitions for known types extend those types with new methods. This includes C++ and ChaiScript defined types.
/// Method definitions for unknown types implicitly define the named type.
///
/// @sa @ref LangObjectSystemRef
/// \sa \ref LangObjectSystemRef
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordelse else
/// @sa @ref keywordif
/// <hr>
/// \section keywordelse else
/// \sa \ref keywordif
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordfor for
/// ~~~~~~~~
/// <hr>
/// \section keywordfor for
/// \code
/// For Block ::= "for" "(" [initial] ";" stop_condition ";" loop_expression ")" block
/// ~~~~~~~~
/// This loop can be broken using the @ref keywordbreak command.
/// \endcode
/// This loop can be broken using the \ref keywordbreak command.
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordfun fun
/// <hr>
/// \section keywordfun fun
/// Begins an anonymous function declaration (sometimes called a lambda).
///
/// ~~~~~~~~
/// \code
/// Lambda ::= "fun" "(" [variable] ("," variable)* ")" block
/// ~~~~~~~~
/// \endcode
///
/// _Example_
/// \b Examples:
///
/// ~~~~~~~~
/// \code
/// // Generate an anonymous function object that adds 2 to its parameter
/// var f = fun(x) { x + 2; }
/// ~~~~~~~~
/// \endcode
///
/// @sa @ref keyworddef for more details on ChaiScript functions
/// \sa \ref keyworddef for more details on ChaiScript functions
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordif if
/// <hr>
/// \section keywordif if
/// Begins a conditional block of code that only executes if the condition evaluates as true.
/// ~~~~~~~~
/// \code
/// If Block ::= "if" "(" condition ")" block
/// Else If Block ::= "else if" "(" condition ")" block
/// Else Block ::= "else" block
/// ~~~~~~~~
///
/// _Example_
///
/// ~~~~~~~~
/// \endcode
/// \b Example:
/// \code
/// if (true) {
/// // do something
/// } else if (false) {
@ -769,69 +718,46 @@
/// } else {
/// // otherwise do this
/// }
/// ~~~~~~~~
/// \endcode
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordtry try
/// ~~~~~~~~
/// <hr>
/// \section keywordtry try
/// \code
/// Try Block ::= "try" block
/// ("catch" ["(" [type] variable ")"] [":" guards] block)+
/// ("catch" ["(" variable ")"] [":" guards] block)+
/// ["finally" block]
/// ~~~~~~~~
/// \endcode
///
/// @sa ChaiScript_Language::throw
/// \sa ChaiScript_Language::throw
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordwhile while
/// <hr>
/// \section keywordwhile while
///
/// Begins a conditional block of code that loops 0 or more times, as long as the condition is true
///
/// ~~~~~~~~
/// \code
/// While Block ::= "while" "(" condition ")" block
/// ~~~~~~~~
///
/// This loop can be broken using the @ref keywordbreak command.
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordvar var
///
/// Defines a variable
///
/// ~~~~~~~~
/// Variable ::= "var" identifier
/// ~~~~~~~~
///
/// Synonym for @ref keywordauto
/// \endcode
/// This loop can be broken using the \ref keywordbreak command.
/// @namespace chaiscript
/// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
/// @namespace chaiscript::detail
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
/// \namespace chaiscript
/// \brief Namespace chaiscript contains every API call that the average user will be concerned with.
/// \namespace chaiscript::detail
/// \brief Classes and functions reserved for internal use. Items in this namespace are not supported.
#include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
#include "chaiscript_basic.hpp"
#include "chaiscript_stdlib.hpp"
#include "language/chaiscript_parser.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_ */

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,57 +1,21 @@
// 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)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_
#define CHAISCRIPT_DEFINES_HPP_
#ifdef _MSC_VER
#define CHAISCRIPT_STRINGIZE(x) "" #x
#define CHAISCRIPT_STRINGIZE_EXPANDED(x) CHAISCRIPT_STRINGIZE(x)
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE_EXPANDED(_MSC_FULL_VER)
#define CHAISCRIPT_MSVC _MSC_VER
#define CHAISCRIPT_HAS_DECLSPEC
static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required");
#else
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
#define CHAISCRIPT_HAS_DECLSPEc
#endif
#include <string_view>
#include <vector>
#if defined(_LIBCPP_VERSION)
#define CHAISCRIPT_LIBCPP
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
#ifdef _WIN32
#define CHAISCRIPT_WINDOWS
#endif
#if defined(_WIN32)
#if defined(__llvm__)
#define CHAISCRIPT_COMPILER_NAME "clang(windows)"
#elif defined(__GNUC__)
#define CHAISCRIPT_COMPILER_NAME "gcc(mingw)"
#else
#define CHAISCRIPT_COMPILER_NAME "msvc"
#endif
#else
#if defined(__llvm__)
#define CHAISCRIPT_COMPILER_NAME "clang"
#elif defined(__GNUC__)
#define CHAISCRIPT_COMPILER_NAME "gcc"
#else
#define CHAISCRIPT_COMPILER_NAME "unknown"
#endif
#endif
#if defined(__llvm__)
#define CHAISCRIPT_CLANG
#endif
#ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
@ -59,186 +23,6 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
#define CHAISCRIPT_UTF16_UTF32
#endif
#ifdef _DEBUG
#define CHAISCRIPT_DEBUG true
#else
#define CHAISCRIPT_DEBUG false
#endif
#include <cmath>
#include <memory>
#include <string>
namespace chaiscript {
constexpr static const int version_major = 7;
constexpr static const int version_minor = 0;
constexpr static const int version_patch = 0;
constexpr static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
constexpr static const bool debug_build = CHAISCRIPT_DEBUG;
template<typename B, typename D, typename... Arg>
inline std::shared_ptr<B> make_shared(Arg &&...arg) {
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_shared<D>(std::forward<Arg>(arg)...);
#else
return std::shared_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
#endif
}
template<typename B, typename D, typename... Arg>
inline std::unique_ptr<B> make_unique(Arg &&...arg) {
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_unique<D>(std::forward<Arg>(arg)...);
#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>
[[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type {
T t = 0;
for (const auto c : t_str) {
if (c < '0' || c > '9') {
return t;
}
t *= 10;
t += c - '0';
}
return 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 {
T t = 0;
T base{};
T decimal_place = 0;
int exponent = 0;
for (const auto c : t_str) {
switch (c) {
case '.':
decimal_place = 10;
break;
case 'e':
case 'E':
exponent = 1;
decimal_place = 0;
base = t;
t = 0;
break;
case '-':
exponent = -1;
break;
case '+':
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
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 exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
}
struct str_equal {
[[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::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

View File

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

View File

@ -1,28 +1,20 @@
// 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)
// and 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_THREADING_HPP_
#define CHAISCRIPT_THREADING_HPP_
#include <unordered_map>
#ifndef CHAISCRIPT_NO_THREADS
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <mutex>
#else
#ifndef CHAISCRIPT_NO_THREADS_WARNING
#pragma message ("ChaiScript is compiling without thread safety.")
#endif
#endif
#include "chaiscript_defines.hpp"
/// \file
///
@ -32,102 +24,150 @@
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
/// one thread simultaneously.
namespace chaiscript
{
namespace detail
{
/// 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 chaiscript::detail::threading {
namespace threading
{
#ifndef CHAISCRIPT_NO_THREADS
template<typename T>
using unique_lock = std::unique_lock<T>;
class unique_lock : public std::unique_lock<T>
{
public:
unique_lock(T &t) : std::unique_lock<T>(t) {}
};
template<typename T>
using shared_lock = std::shared_lock<T>;
class shared_lock : public std::unique_lock<T>
{
public:
shared_lock(T &t) : std::unique_lock<T>(t) {}
void unlock() {}
};
template<typename T>
using lock_guard = std::lock_guard<T>;
class lock_guard : public std::lock_guard<T>
{
public:
lock_guard(T &t) : std::lock_guard<T>(t) {}
};
using std::shared_mutex;
class shared_mutex : public std::mutex { };
using std::mutex;
using std::recursive_mutex;
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
///
/// \todo move to thread_local when it exists
template<typename T>
class Thread_Storage {
class Thread_Storage
{
public:
Thread_Storage() = default;
Thread_Storage(const Thread_Storage &) = delete;
Thread_Storage(Thread_Storage &&) = delete;
Thread_Storage &operator=(const Thread_Storage &) = delete;
Thread_Storage &operator=(Thread_Storage &&) = delete;
inline T *operator->() const
{
return get_tls().get();
}
~Thread_Storage() { t().erase(this); }
inline T &operator*() const
{
return *get_tls();
}
inline const T *operator->() const noexcept { return &(t()[this]); }
inline const T &operator*() const noexcept { return t()[this]; }
inline T *operator->() noexcept { return &(t()[this]); }
inline T &operator*() noexcept { return t()[this]; }
void *m_key;
private:
/// todo: is it valid to make this noexcept? The allocation could fail, but if it
/// does there is no possible way to recover
static std::unordered_map<const void *, T> &t() noexcept {
static thread_local std::unordered_map<const void *, T> my_t;
return my_t;
std::shared_ptr<T> get_tls() const
{
unique_lock<mutex> lock(m_mutex);
auto itr = m_instances.find(std::this_thread::get_id());
if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(new T());
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
return new_instance;
/*
static __thread std::shared_ptr<T> *m_data = 0;
if (!m_data) { m_data = new std::shared_ptr<T>(new T()); }
return *m_data;
*/
}
mutable mutex m_mutex;
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
};
#else // threading disabled
#else
template<typename T>
class unique_lock {
class unique_lock
{
public:
constexpr explicit unique_lock(T &) noexcept {}
constexpr void lock() noexcept {}
constexpr void unlock() noexcept {}
unique_lock(T &) {}
};
template<typename T>
class shared_lock {
class shared_lock
{
public:
constexpr explicit shared_lock(T &) noexcept {}
constexpr void lock() noexcept {}
constexpr void unlock() noexcept {}
shared_lock(T &) {}
void unlock() {}
};
template<typename T>
class lock_guard {
class lock_guard
{
public:
constexpr explicit lock_guard(T &) noexcept {}
lock_guard(T &) {}
};
class shared_mutex {
};
class shared_mutex { };
class recursive_mutex {};
class recursive_mutex {
};
template<typename T>
class Thread_Storage {
class Thread_Storage
{
public:
constexpr explicit Thread_Storage() noexcept {}
inline T *operator->() const
{
return &obj;
}
constexpr inline T *operator->() const noexcept { return &obj; }
constexpr inline T &operator*() const noexcept { return obj; }
inline T &operator*() const
{
return obj;
}
private:
mutable T obj;
};
#endif
} // namespace chaiscript::detail::threading
}
}
}
#endif

View File

@ -7,101 +7,146 @@
#ifndef CHAISCRIPT_ANY_HPP_
#define CHAISCRIPT_ANY_HPP_
#include <utility>
namespace chaiscript {
namespace detail {
namespace exception {
namespace exception
{
/// \brief Thrown in the event that an Any cannot be cast to the desired type
///
/// It is used internally during function dispatch.
///
/// \sa chaiscript::detail::Any
class bad_any_cast : public std::bad_cast {
class bad_any_cast : public std::bad_cast
{
public:
/// \brief Description of what error occurred
const char *what() const noexcept override { return "bad any cast"; }
bad_any_cast() noexcept
: m_what("bad any cast")
{
}
virtual ~bad_any_cast() noexcept {}
/// \brief Description of what error occured
virtual const char * what() const noexcept
{
return m_what.c_str();
}
private:
std::string m_what;
};
} // namespace exception
}
class Any {
private:
struct Data {
constexpr explicit Data(const std::type_info &t_type) noexcept
: m_type(t_type) {
}
Data &operator=(const Data &) = delete;
virtual ~Data() noexcept = default;
virtual void *data() noexcept = 0;
const std::type_info &type() const noexcept { return m_type; }
virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type;
struct Data
{
virtual void *data() = 0;
virtual const std::type_info &type() const = 0;
virtual std::shared_ptr<Data> clone() const = 0;
};
template<typename T>
struct Data_Impl : Data {
explicit Data_Impl(T t_type)
: Data(typeid(T))
, m_data(std::move(t_type)) {
struct Data_Impl : Data
{
Data_Impl(const T &t_type)
: m_type(typeid(T)),
m_data(t_type)
{
}
void *data() noexcept override { return &m_data; }
virtual void *data()
{
return &m_data;
}
std::unique_ptr<Data> clone() const override { return std::make_unique<Data_Impl<T>>(m_data); }
const std::type_info &type() const
{
return m_type;
}
Data_Impl &operator=(const Data_Impl &) = delete;
std::shared_ptr<Data> clone() const
{
return std::shared_ptr<Data>(new Data_Impl<T>(m_data));
}
const std::type_info &m_type;
T m_data;
};
std::unique_ptr<Data> m_data;
std::shared_ptr<Data> m_data;
public:
// construct/copy/destruct
constexpr Any() noexcept = default;
Any(Any &&) noexcept = default;
Any &operator=(Any &&t_any) = default;
Any() = default;
Any(const Any &t_any)
: m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) {
{
if (!t_any.empty())
{
m_data = t_any.m_data->clone();
} else {
m_data.reset();
}
}
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))) {
template<typename ValueType>
Any(const ValueType &t_value)
{
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
}
Any &operator=(const Any &t_any) {
Any & operator=(const Any &t_any)
{
Any copy(t_any);
swap(copy);
return *this;
}
template<typename ValueType>
Any & operator=(const ValueType &t_value)
{
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
return *this;
}
template<typename ToType>
ToType &cast() const {
if (m_data && typeid(ToType) == m_data->type()) {
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();
}
}
~Any()
{
}
// modifiers
Any &swap(Any &t_other) {
std::swap(t_other.m_data, m_data);
Any & swap(Any &t_other)
{
std::shared_ptr<Data> data = t_other.m_data;
t_other.m_data = m_data;
m_data = data;
return *this;
}
// queries
bool empty() const noexcept { return !static_cast<bool>(m_data); }
bool empty() const
{
return !bool(m_data);
}
const std::type_info &type() const noexcept {
if (m_data) {
const std::type_info & type() const
{
if (m_data)
{
return m_data->type();
} else {
return typeid(void);
@ -109,7 +154,9 @@ namespace chaiscript {
}
};
} // namespace detail
} // namespace chaiscript
}
}
#endif

View File

@ -1,64 +1,60 @@
// 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)
// and 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_BAD_BOXED_CAST_HPP_
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
#include <string>
#include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "../utility/static_string.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Info;
} // namespace chaiscript
namespace chaiscript {
namespace exception {
namespace chaiscript
{
namespace exception
{
/// \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.
///
/// \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
: from(t_from)
, to(&t_to)
, m_what(std::move(t_what)) {
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
: from(t_from), to(&t_to), m_what(t_what)
{
}
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept
: from(t_from)
, to(&t_to)
, m_what("Cannot perform boxed_cast") {
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
{
}
explicit bad_boxed_cast(utility::Static_String t_what) noexcept
: m_what(std::move(t_what)) {
bad_boxed_cast(const std::string &t_what) noexcept
: to(0), m_what(t_what)
{
}
bad_boxed_cast(const bad_boxed_cast &) noexcept = default;
~bad_boxed_cast() noexcept override = default;
virtual ~bad_boxed_cast() noexcept {}
/// \brief Description of what error occurred
const char *what() const noexcept override { return m_what.c_str(); }
/// \brief Description of what error occured
virtual const char * what() const noexcept
{
return m_what.c_str();
}
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:
utility::Static_String m_what;
std::string m_what;
};
} // namespace exception
} // namespace chaiscript
}
}
#endif

View File

@ -1,60 +1,133 @@
// 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)
// and 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_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_
#include <functional>
namespace chaiscript {
namespace detail {
template<typename T>
constexpr T *get_pointer(T *t) noexcept {
return t;
}
namespace chaiscript
{
namespace detail
{
template<typename T>
T *get_pointer(const std::reference_wrapper<T> &t) noexcept {
return &t.get();
template<int>
struct Placeholder
{
};
template<>
struct Placeholder<1>
{
static decltype(std::placeholders::_1) value() { return std::placeholders::_1; }
};
template<>
struct Placeholder<2>
{
static decltype(std::placeholders::_2) value() { return std::placeholders::_2; }
};
template<>
struct Placeholder<3>
{
static decltype(std::placeholders::_3) value() { return std::placeholders::_3; }
};
template<>
struct Placeholder<4>
{
static decltype(std::placeholders::_4) value() { return std::placeholders::_4; }
};
template<>
struct Placeholder<5>
{
static decltype(std::placeholders::_5) value() { return std::placeholders::_5; }
};
template<>
struct Placeholder<6>
{
static decltype(std::placeholders::_6) value() { return std::placeholders::_6; }
};
template<>
struct Placeholder<7>
{
static decltype(std::placeholders::_7) value() { return std::placeholders::_7; }
};
template<>
struct Placeholder<8>
{
static decltype(std::placeholders::_8) value() { return std::placeholders::_8; }
};
template<>
struct Placeholder<9>
{
static decltype(std::placeholders::_9) value() { return std::placeholders::_9; }
};
template<>
struct Placeholder<10>
{
static decltype(std::placeholders::_10) value() { return std::placeholders::_10; }
};
template<int count, int maxcount, typename Sig>
struct Bind_First
{
template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams)
{
return Bind_First<count - 1, maxcount, Sig>::bind(f, innerparams..., Placeholder<maxcount - count + 1>::value());
}
};
template<int maxcount, typename Sig>
struct Bind_First<0, maxcount, Sig>
{
template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams)
{
return std::bind(f, innerparams...);
}
};
template<typename O, typename Ret, typename P1, typename ... Param>
constexpr auto bind_first(Ret (*f)(P1, Param...), O &&o) {
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
}
template<typename O, typename Ret, typename Class, typename ... Param>
constexpr auto 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)...); };
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
}
template<typename O, typename Ret, typename Class, typename ... Param>
constexpr auto bind_first(Ret (Class::*f)(Param...) const, O &&o) {
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); };
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
}
template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(const std::function<Ret(P1, Param...)> &f, O &&o) {
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
}
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>
constexpr auto bind_first(const F &f, O &&o) {
return bind_first(f, std::forward<O>(o), &F::operator());
}
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -1,85 +1,84 @@
// 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)
// and 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_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_
#include "../utility/utility.hpp"
#include "dispatchkit.hpp"
#include "dynamic_object.hpp"
#include "register_function.hpp"
#include "operators.hpp"
#include "boxed_number.hpp"
#include <sstream>
#include <type_traits>
namespace chaiscript
{
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
namespace chaiscript::bootstrap {
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type>
void array(const std::string &type, Module &m) {
using ReturnType = typename std::remove_extent<T>::type;
m.add(user_type<T>(), type);
m.add(fun([](T &t, size_t index) -> ReturnType & {
constexpr const auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
+ std::to_string(extent));
} else {
return t[index];
namespace bootstrap
{
namespace detail
{
/// \brief Constructs a new POD value object from a Boxed_Number
/// \param[in] v Boxed_Number to copy into the new object
/// \returns The newly created object.
template<typename P1>
std::shared_ptr<P1> construct_pod(Boxed_Number v)
{
std::shared_ptr<P1> p(new P1());
Boxed_Value bv(p);
Boxed_Number nb(bv);
nb = v;
return p;
}
}),
"[]");
m.add(fun([](const T &t, size_t index) -> const ReturnType & {
constexpr const auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
+ std::to_string(extent));
} else {
return t[index];
}
}),
"[]");
m.add(fun([](const T &) { return std::extent<T>::value; }), "size");
}
/// \brief Adds a copy constructor for the given type to the given Model
/// \param[in] type The name of the type. The copy constructor will be named "type".
/// \param[in,out] m The Module to add the copy constructor to
/// \tparam T The type to add a copy constructor for
/// \returns The passed in Module
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
template<typename T>
void copy_constructor(const std::string &type, Module &m) {
m.add(constructor<T(const T &)>(), type);
ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(constructor<T (const T &)>(), type);
return m;
}
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
/// \tparam T Type to create comparison operators for
/// \param[in,out] m module to add comparison operators to
/// \returns the passed in Module.
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
template<typename T>
void opers_comparison(Module &m) {
ModulePtr opers_comparison(ModulePtr m = ModulePtr(new Module()))
{
operators::equal<T>(m);
operators::greater_than<T>(m);
operators::greater_than_equal<T>(m);
operators::less_than<T>(m);
operators::less_than_equal<T>(m);
operators::not_equal<T>(m);
return m;
}
/// \brief Adds default and copy constructors for the given type
/// \param[in] type The name of the type to add the constructors for.
/// \param[in,out] m The Module to add the basic constructors to
/// \tparam T Type to generate basic constructors for
/// \returns The passed in Module
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
/// \sa copy_constructor
/// \sa constructor
template<typename T>
void basic_constructors(const std::string &type, Module &m) {
m.add(constructor<T()>(), type);
ModulePtr basic_constructors(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(constructor<T ()>(), type);
copy_constructor<T>(type, m);
return m;
}
/// \brief Adds a constructor for a POD type
@ -87,58 +86,91 @@ namespace chaiscript::bootstrap {
/// \param[in] type The name of the type
/// \param[in,out] m The Module to add the constructor to
template<typename T>
void construct_pod(const std::string &type, Module &m) {
m.add(fun([](const Boxed_Number &bn) { return bn.get_as<T>(); }), type);
ModulePtr construct_pod(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&detail::construct_pod<T>), type);
return m;
}
/// Internal function for converting from a string to a value
/// uses ostream operator >> to perform the conversion
/**
* to_string function for internal use. Uses ostream operator<<
*/
template<typename Input>
Input parse_string(const std::string &i) {
if constexpr (!std::is_same<Input, wchar_t>::value && !std::is_same<Input, char16_t>::value && !std::is_same<Input, char32_t>::value) {
std::string to_string(Input i)
{
std::stringstream ss;
ss << i;
return ss.str();
}
/**
* Internal function for converting from a string to a value
* uses ostream operator >> to perform the conversion
*/
template<typename Input>
Input parse_string(const std::string &i)
{
std::stringstream ss(i);
Input t;
ss >> t;
return t;
} else {
throw std::runtime_error("Parsing of wide characters is not yet supported");
}
}
/// Add all common functions for a POD type. All operators, and
/// common conversions
/**
* Add all common functions for a POD type. All operators, and
* common conversions
*/
template<typename T>
void bootstrap_pod_type(const std::string &name, Module &m) {
m.add(user_type<T>(), name);
m.add(constructor<T()>(), name);
ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<T>(), name);
m->add(constructor<T ()>(), name);
construct_pod<T>(name, m);
m.add(fun(&parse_string<T>), "to_" + name);
m.add(fun([](const T t) { return t; }), "to_" + name);
m->add(fun(&to_string<T>), "to_string");
m->add(fun(&parse_string<T>), "to_" + name);
return m;
}
/// "clone" function for a shared_ptr type. This is used in the case
/// where you do not want to make a deep copy of an object during cloning
/// but want to instead maintain the shared_ptr. It is needed internally
/// for handling of Proxy_Function object (that is,
/// function variables.
/**
* "clone" function for a shared_ptr type. This is used in the case
* where you do not want to make a deep copy of an object during cloning
* but want to instead maintain the shared_ptr. It is needed internally
* for handling of Proxy_Function object (that is,
* function variables.
*/
template<typename Type>
auto shared_ptr_clone(const std::shared_ptr<Type> &p) {
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
{
return p;
}
/// Specific version of shared_ptr_clone just for Proxy_Functions
/**
* Specific version of shared_ptr_clone just for Proxy_Functions
*/
template<typename Type>
std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<Type>> &p) {
std::shared_ptr<typename std::remove_const<Type>::type>
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
{
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
}
/// Assignment function for shared_ptr objects, does not perform a copy of the
/// object pointed to, instead maintains the shared_ptr concept.
/// Similar to shared_ptr_clone. Used for Proxy_Function.
/**
* Assignment function for shared_ptr objects, does not perform a copy of the
* object pointed to, instead maintains the shared_ptr concept.
* Similar to shared_ptr_clone. Used for Proxy_Function.
*/
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) {
if (lhs.is_undef() || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get()))) {
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
{
if (lhs.is_undef()
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
{
lhs.assign(Boxed_Value(rhs));
return lhs;
} else {
@ -146,258 +178,266 @@ namespace chaiscript::bootstrap {
}
}
/// Class consisting of only static functions. All default bootstrapping occurs
/// from this class.
class Bootstrap {
/**
* Class consisting of only static functions. All default bootstrapping occurs
* from this class.
*/
class Bootstrap
{
private:
/// Function allowing for assignment of an unknown type to any other value
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) {
if (lhs.is_undef()) {
/**
* Function allowing for assignment of an unknown type to any other value
*/
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs)
{
if (lhs.is_undef())
{
return (lhs.assign(rhs));
} else {
throw exception::bad_boxed_cast("boxed_value has a set type already");
}
}
static void print(const std::string &s) noexcept { fwrite(s.c_str(), 1, s.size(), stdout); }
static void println(const std::string &s) noexcept { puts(s.c_str()); }
/// Add all arithmetic operators for PODs
static void opers_arithmetic_pod(Module &m) {
m.add(fun(&Boxed_Number::equals), "==");
m.add(fun(&Boxed_Number::less_than), "<");
m.add(fun(&Boxed_Number::greater_than), ">");
m.add(fun(&Boxed_Number::greater_than_equal), ">=");
m.add(fun(&Boxed_Number::less_than_equal), "<=");
m.add(fun(&Boxed_Number::not_equal), "!=");
m.add(fun(&Boxed_Number::pre_decrement), "--");
m.add(fun(&Boxed_Number::pre_increment), "++");
m.add(fun(&Boxed_Number::sum), "+");
m.add(fun(&Boxed_Number::unary_plus), "+");
m.add(fun(&Boxed_Number::unary_minus), "-");
m.add(fun(&Boxed_Number::difference), "-");
m.add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m.add(fun(&Boxed_Number::assign), "=");
m.add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m.add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m.add(fun(&Boxed_Number::assign_remainder), "%=");
m.add(fun(&Boxed_Number::assign_shift_left), "<<=");
m.add(fun(&Boxed_Number::assign_shift_right), ">>=");
m.add(fun(&Boxed_Number::bitwise_and), "&");
m.add(fun(&Boxed_Number::bitwise_complement), "~");
m.add(fun(&Boxed_Number::bitwise_xor), "^");
m.add(fun(&Boxed_Number::bitwise_or), "|");
m.add(fun(&Boxed_Number::assign_product), "*=");
m.add(fun(&Boxed_Number::assign_quotient), "/=");
m.add(fun(&Boxed_Number::assign_sum), "+=");
m.add(fun(&Boxed_Number::assign_difference), "-=");
m.add(fun(&Boxed_Number::quotient), "/");
m.add(fun(&Boxed_Number::shift_left), "<<");
m.add(fun(&Boxed_Number::product), "*");
m.add(fun(&Boxed_Number::remainder), "%");
m.add(fun(&Boxed_Number::shift_right), ">>");
static void print(const std::string &s)
{
std::cout << s;
}
/// Create a bound function object. The first param is the function to bind
/// the remaining parameters are the args to bind into the result
static Boxed_Value bind_function(const Function_Params &params) {
if (params.empty()) {
throw exception::arity_error(0, 1);
static void println(const std::string &s)
{
std::cout << s << std::endl;
}
/**
* Add all arithmetic operators for PODs
*/
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&Boxed_Number::equals), "==");
m->add(fun(&Boxed_Number::less_than), "<");
m->add(fun(&Boxed_Number::greater_than), ">");
m->add(fun(&Boxed_Number::greater_than_equal), ">=");
m->add(fun(&Boxed_Number::less_than_equal), "<=");
m->add(fun(&Boxed_Number::not_equal), "!=");
m->add(fun(&Boxed_Number::pre_decrement), "--");
m->add(fun(&Boxed_Number::pre_increment), "++");
m->add(fun(&Boxed_Number::sum), "+");
m->add(fun(&Boxed_Number::unary_plus), "+");
m->add(fun(&Boxed_Number::unary_minus), "-");
m->add(fun(&Boxed_Number::difference), "-");
m->add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m->add(fun(&Boxed_Number::assign), "=");
m->add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m->add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m->add(fun(&Boxed_Number::assign_remainder), "%=");
m->add(fun(&Boxed_Number::assign_shift_left), "<<=");
m->add(fun(&Boxed_Number::assign_shift_right), ">>=");
m->add(fun(&Boxed_Number::bitwise_and), "&");
m->add(fun(&Boxed_Number::bitwise_complement), "~");
m->add(fun(&Boxed_Number::bitwise_xor), "^");
m->add(fun(&Boxed_Number::bitwise_or), "|");
m->add(fun(&Boxed_Number::assign_product), "*=");
m->add(fun(&Boxed_Number::assign_quotient), "/=");
m->add(fun(&Boxed_Number::assign_sum), "+=");
m->add(fun(&Boxed_Number::assign_difference), "-=");
m->add(fun(&Boxed_Number::quotient), "/");
m->add(fun(&Boxed_Number::shift_left), "<<");
m->add(fun(&Boxed_Number::product), "*");
m->add(fun(&Boxed_Number::remainder), "%");
m->add(fun(&Boxed_Number::shift_right), ">>");
}
/**
* Create a bound function object. The first param is the function to bind
* the remaining parameters are the args to bind into the
* result
*/
static Boxed_Value bind_function(const std::vector<Boxed_Value> &params)
{
if (params.size() < 2)
{
throw exception::arity_error(static_cast<int>(params.size()), 2);
}
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) {
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f,
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
}
return Boxed_Value(Const_Proxy_Function(
std::make_shared<dispatch::Bound_Function>(std::move(f), std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
/**
* Returns true if a call can be made that consists of the first parameter
* (the function) with the remaining parameters as its arguments.
*/
static Boxed_Value call_exists(const std::vector<Boxed_Value> &params)
{
if (params.size() < 1)
{
throw exception::arity_error(static_cast<int>(params.size()), 1);
}
static bool has_guard(const Const_Proxy_Function &t_pf) noexcept {
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end())));
}
static bool has_guard(const Const_Proxy_Function &t_pf)
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->has_guard();
if (pf)
{
return bool(pf->get_guard());
} else {
return false;
}
}
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) {
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_guard()) {
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
if (pf->get_guard())
{
return pf->get_guard();
} else {
throw std::runtime_error("Function does not have a guard");
}
} else {
throw std::runtime_error("Function does not have a guard");
}
}
static void throw_exception(const Boxed_Value &bv) {
throw bv;
}
static std::shared_ptr<chaiscript::detail::Dispatch_Engine> bootstrap2(
std::shared_ptr<chaiscript::detail::Dispatch_Engine> e
= std::shared_ptr<chaiscript::detail::Dispatch_Engine> (new chaiscript::detail::Dispatch_Engine()))
{
e->add(user_type<void>(), "void");
return e;
}
static std::string what(const std::exception &e)
{
return e.what();
}
/**
* Boolean specialization of internal to_string function
*/
static std::string bool_to_string(bool b)
{
if (b)
{
return "true";
} else {
return "false";
}
}
template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, const dispatch::Proxy_Function_Base *b) {
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
const dispatch::Proxy_Function_Base *b)
{
auto v = (b->*f)();
std::vector<Boxed_Value> vbv;
for (const auto &o : v) {
for (const auto &o: v)
{
vbv.push_back(const_var(o));
}
return vbv;
}
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept {
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
return bool(pf);
}
static const chaiscript::AST_Node &get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) {
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf) {
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
template<typename Function>
static auto return_boxed_value_vector(const Function &f) {
return [f](const dispatch::Proxy_Function_Base *b) { return do_return_boxed_value_vector(f, b); };
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
{
return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1);
}
public:
/// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to
/// \returns passed in Module
static void bootstrap(Module &m) {
m.add(user_type<void>(), "void");
m.add(user_type<bool>(), "bool");
m.add(user_type<Boxed_Value>(), "Object");
m.add(user_type<Boxed_Number>(), "Number");
m.add(user_type<Proxy_Function>(), "Function");
m.add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
m.add(user_type<std::exception>(), "exception");
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
m.add(fun([](const std::exception &e) { return std::string(e.what()); }), "what");
m.add(user_type<std::out_of_range>(), "out_of_range");
m.add(user_type<std::logic_error>(), "logic_error");
m.add(chaiscript::base_class<std::exception, std::logic_error>());
m.add(chaiscript::base_class<std::logic_error, std::out_of_range>());
m.add(chaiscript::base_class<std::exception, std::out_of_range>());
m.add(user_type<std::runtime_error>(), "runtime_error");
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
m.add(constructor<std::runtime_error(const std::string &)>(), "runtime_error");
m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object(const std::string &)>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object()>(), "Dynamic_Object");
m.add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
m.add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
m.add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr");
m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
"get_attr");
m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)),
"method_missing");
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(
&dispatch::Dynamic_Object::method_missing)),
"method_missing");
m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
"[]");
m.eval(R"chaiscript(
def Dynamic_Object::clone() {
auto &new_o = Dynamic_Object(this.get_type_name());
for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
new_o;
}
def `=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
/// \returns passed in ModulePtr, or newly created one if default argument is used
static ModulePtr bootstrap(ModulePtr m = ModulePtr(new Module()))
{
for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } );
}
m->add(user_type<void>(), "void");
m->add(user_type<bool>(), "bool");
m->add(user_type<Boxed_Value>(), "Object");
m->add(user_type<Boxed_Number>(), "Number");
m->add(user_type<Proxy_Function>(), "Function");
m->add(user_type<std::exception>(), "exception");
def `!=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
{
var rhs_attrs := rhs.get_attrs();
var lhs_attrs := lhs.get_attrs();
m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
m->add(fun(&dispatch::Proxy_Function_Base::operator()), "call");
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
if (rhs_attrs.size() != lhs_attrs.size()) {
true;
} else {
return any_of(rhs_attrs, fun[lhs](x) { !lhs.has_attr(x.first) || lhs.get_attr(x.first) != x.second; } );
}
}
def `==`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
{
var rhs_attrs := rhs.get_attrs();
var lhs_attrs := lhs.get_attrs();
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
if (rhs_attrs.size() != lhs_attrs.size()) {
false;
} else {
return all_of(rhs_attrs, fun[lhs](x) { lhs.has_attr(x.first) && lhs.get_attr(x.first) == x.second; } );
}
}
)chaiscript");
m.add(fun(&has_guard), "has_guard");
m.add(fun(&get_guard), "get_guard");
m->add(user_type<std::runtime_error>(), "runtime_error");
m->add(chaiscript::base_class<std::exception, std::runtime_error>());
m.add(fun(&Boxed_Value::is_undef), "is_var_undef");
m.add(fun(&Boxed_Value::is_null), "is_var_null");
m.add(fun(&Boxed_Value::is_const), "is_var_const");
m.add(fun(&Boxed_Value::is_ref), "is_var_reference");
m.add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
m.add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
m.add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
m.add(fun(&Boxed_Value::is_type), "is_type");
m.add(fun(&Boxed_Value::get_attr), "get_var_attr");
m.add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
m.add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
m.add(fun(&Boxed_Value::get_type_info), "get_type_info");
m.add(user_type<Type_Info>(), "Type_Info");
m.add(constructor<Type_Info(const Type_Info &)>(), "Type_Info");
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
m->add(fun(&dispatch::Dynamic_Object::get_attr), "get_attr");
m->eval("def Dynamic_Object::clone() { auto &new_o = Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");
m->add(fun(&has_guard), "has_guard");
m->add(fun(&get_guard), "get_guard");
m->add(fun(&Boxed_Value::is_undef), "is_var_undef");
m->add(fun(&Boxed_Value::is_null), "is_var_null");
m->add(fun(&Boxed_Value::is_const), "is_var_const");
m->add(fun(&Boxed_Value::is_ref), "is_var_reference");
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
m->add(fun(&Boxed_Value::is_type), "is_type");
m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
m->add(user_type<Type_Info>(), "Type_Info");
operators::equal<Type_Info>(m);
m.add(fun(&Type_Info::is_const), "is_type_const");
m.add(fun(&Type_Info::is_reference), "is_type_reference");
m.add(fun(&Type_Info::is_void), "is_type_void");
m.add(fun(&Type_Info::is_undef), "is_type_undef");
m.add(fun(&Type_Info::is_pointer), "is_type_pointer");
m.add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
m.add(fun(&Type_Info::name), "cpp_name");
m.add(fun(&Type_Info::bare_name), "cpp_bare_name");
m.add(fun(&Type_Info::bare_equal), "bare_equal");
m->add(fun(&Type_Info::is_const), "is_type_const");
m->add(fun(&Type_Info::is_reference), "is_type_reference");
m->add(fun(&Type_Info::is_void), "is_type_void");
m->add(fun(&Type_Info::is_undef), "is_type_undef");
m->add(fun(&Type_Info::is_pointer), "is_type_pointer");
m->add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
m->add(fun(&Type_Info::name), "cpp_name");
m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
m->add(fun(&Type_Info::bare_equal), "bare_equal");
basic_constructors<bool>("bool", m);
operators::assign<bool>(m);
operators::equal<bool>(m);
operators::not_equal<bool>(m);
m.add(fun([](const std::string &s) { return s; }), "to_string");
m.add(fun([](const bool b) { return std::string(b ? "true" : "false"); }), "to_string");
m.add(fun(&unknown_assign), "=");
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
m.add(fun(&Boxed_Number::to_string), "to_string");
m->add(fun(&to_string<const std::string &>), "internal_to_string");
m->add(fun(&Bootstrap::bool_to_string), "internal_to_string");
m->add(fun(&unknown_assign), "=");
m->add(fun(&throw_exception), "throw");
m->add(fun(&what), "what");
bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m);
@ -406,13 +446,8 @@ namespace chaiscript::bootstrap {
bootstrap_pod_type<long>("long", m);
bootstrap_pod_type<unsigned int>("unsigned_int", m);
bootstrap_pod_type<unsigned long>("unsigned_long", m);
bootstrap_pod_type<long long>("long_long", m);
bootstrap_pod_type<unsigned long long>("unsigned_long_long", m);
bootstrap_pod_type<size_t>("size_t", m);
bootstrap_pod_type<char>("char", m);
bootstrap_pod_type<wchar_t>("wchar_t", m);
bootstrap_pod_type<char16_t>("char16_t", m);
bootstrap_pod_type<char32_t>("char32_t", m);
bootstrap_pod_type<std::int8_t>("int8_t", m);
bootstrap_pod_type<std::int16_t>("int16_t", m);
bootstrap_pod_type<std::int32_t>("int32_t", m);
@ -426,86 +461,27 @@ namespace chaiscript::bootstrap {
opers_arithmetic_pod(m);
m.add(fun(&Build_Info::version_major), "version_major");
m.add(fun(&Build_Info::version_minor), "version_minor");
m.add(fun(&Build_Info::version_patch), "version_patch");
m.add(fun(&Build_Info::version), "version");
m.add(fun(&Build_Info::compiler_version), "compiler_version");
m.add(fun(&Build_Info::compiler_name), "compiler_name");
m.add(fun(&Build_Info::compiler_id), "compiler_id");
m.add(fun(&Build_Info::debug_build), "debug_build");
m.add(fun(&print), "print_string");
m.add(fun(&println), "println_string");
m->add(fun(&print), "print_string");
m->add(fun(&println), "println_string");
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&bind_function, std::placeholders::_1))),
"bind");
m.add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m.add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
m.add(fun([](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
t_lhs.assign(t_rhs);
}),
"=");
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(fun(&Boxed_Value::type_match), "type_match");
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&call_exists, std::placeholders::_1))),
"call_exists");
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m->add(fun(&Boxed_Value::type_match), "type_match");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> >
// >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
"eval_error",
{},
{{fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
{fun([](const chaiscript::exception::eval_error &t_eval_error) {
std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(),
t_eval_error.call_stack.end(),
std::back_inserter(retval),
&chaiscript::var<const chaiscript::AST_Node_Trace &>);
return retval;
}),
"call_stack"}});
chaiscript::utility::add_class<chaiscript::File_Position>(m,
"File_Position",
{constructor<File_Position()>(), constructor<File_Position(int, int)>()},
{{fun(&File_Position::line), "line"},
{fun(&File_Position::column), "column"}});
chaiscript::utility::add_class<AST_Node>(m,
"AST_Node",
{},
{{fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"},
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
const auto children = t_node.get_children();
std::transform(children.begin(),
children.end(),
std::back_inserter(retval),
&chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>);
return retval;
}),
"children"}});
return m;
}
};
} // namespace chaiscript::bootstrap
}
}
#endif

View File

@ -1,122 +1,200 @@
// 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)
// and 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
/**
* \file
* This file contains utility functions for registration of STL container
* classes. The methodology used is based on the SGI STL concepts.
* http://www.sgi.com/tech/stl/table_of_contents.html
*/
/// \file
/// This file contains utility functions for registration of STL container
/// classes. The methodology used is based on the SGI STL concepts.
/// http://www.sgi.com/tech/stl/table_of_contents.html
#ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_
#include <functional>
#include <memory>
#include <stdexcept>
#include <typeinfo>
#include <vector>
#include "bootstrap.hpp"
#include "boxed_value.hpp"
#include "dispatchkit.hpp"
#include "operators.hpp"
#include "proxy_constructors.hpp"
#include "bootstrap.hpp"
#include "register_function.hpp"
#include "type_info.hpp"
namespace chaiscript::bootstrap::standard_library {
/// Bidir_Range, based on the D concept of ranges.
/// \todo Update the Range code to base its capabilities on
/// the user_typetraits of the iterator passed in
template<typename Container, typename IterType>
struct Bidir_Range {
using container_type = Container;
namespace chaiscript
{
namespace bootstrap
{
namespace standard_library
{
/**
* Bidir_Range, based on the D concept of ranges.
* \todo Update the Range code to base its capabilities on
* the user_typetraits of the iterator passed in
*/
template<typename Container>
struct Bidir_Range
{
typedef Container container_type;
typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
constexpr Bidir_Range(Container &c)
: m_begin(c.begin())
, m_end(c.end()) {
Bidir_Range(Container &c)
: m_begin(c.begin()), m_end(c.end())
{
}
constexpr bool empty() const noexcept { return m_begin == m_end; }
bool empty() const
{
return m_begin == m_end;
}
constexpr void pop_front() {
if (empty()) {
void pop_front()
{
if (empty())
{
throw std::range_error("Range empty");
}
++m_begin;
}
constexpr void pop_back() {
if (empty()) {
void pop_back()
{
if (empty())
{
throw std::range_error("Range empty");
}
--m_end;
}
constexpr decltype(auto) front() const {
if (empty()) {
reference_type front() const
{
if (empty())
{
throw std::range_error("Range empty");
}
return (*m_begin);
return *m_begin;
}
constexpr decltype(auto) back() const {
if (empty()) {
reference_type back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
auto pos = m_end;
typename Container::iterator pos = m_end;
--pos;
return (*(pos));
return *(pos);
}
IterType m_begin;
IterType m_end;
typename Container::iterator m_begin;
typename Container::iterator m_end;
};
template<typename Container>
struct Const_Bidir_Range
{
typedef const Container container_type;
typedef typename std::iterator_traits<typename Container::const_iterator>::reference const_reference_type;
Const_Bidir_Range(const Container &c)
: m_begin(c.begin()), m_end(c.end())
{
}
bool empty() const
{
return m_begin == m_end;
}
void pop_front()
{
if (empty())
{
throw std::range_error("Range empty");
}
++m_begin;
}
void pop_back()
{
if (empty())
{
throw std::range_error("Range empty");
}
--m_end;
}
const_reference_type front() const
{
if (empty())
{
throw std::range_error("Range empty");
}
return *m_begin;
}
const_reference_type back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
typename Container::const_iterator pos = m_end;
--pos;
return *(pos);
}
typename Container::const_iterator m_begin;
typename Container::const_iterator m_end;
};
namespace detail {
template<typename T>
size_t count(const T &t_target, const typename T::key_type &t_key) {
return t_target.count(t_key);
}
template<typename T>
void insert(T &t_target, const T &t_other) {
void insert(T &t_target, const T &t_other)
{
t_target.insert(t_other.begin(), t_other.end());
}
template<typename T>
void insert_ref(T &t_target, const typename T::value_type &t_val) {
void insert_ref(T &t_target, const typename T::value_type &t_val)
{
t_target.insert(t_val);
}
/// Add Bidir_Range support for the given ContainerType
/**
* Add Bidir_Range support for the given ContainerType
*/
template<typename Bidir_Type>
void input_range_type_impl(const std::string &type, Module &m) {
m.add(user_type<Bidir_Type>(), type + "_Range");
ModulePtr input_range_type_impl(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<Bidir_Type>(), type + "_Range");
copy_constructor<Bidir_Type>(type + "_Range", m);
m.add(constructor<Bidir_Type(typename Bidir_Type::container_type &)>(), "range_internal");
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range");
m.add(fun(&Bidir_Type::empty), "empty");
m.add(fun(&Bidir_Type::pop_front), "pop_front");
m.add(fun(&Bidir_Type::front), "front");
m.add(fun(&Bidir_Type::pop_back), "pop_back");
m.add(fun(&Bidir_Type::back), "back");
m->add(fun(&Bidir_Type::empty), "empty");
m->add(fun(&Bidir_Type::pop_front), "pop_front");
m->add(fun(&Bidir_Type::front), "front");
m->add(fun(&Bidir_Type::pop_back), "pop_back");
m->add(fun(&Bidir_Type::back), "back");
return m;
}
/// Algorithm for inserting at a specific position into a container
/**
* Algorithm for inserting at a specific position into a container
*/
template<typename Type>
void insert_at(Type &container, int pos, const typename Type::value_type &v) {
auto itr = container.begin();
auto end = container.end();
void insert_at(Type &container, int pos, const typename Type::value_type &v)
{
typename Type::iterator itr = container.begin();
typename Type::iterator end = container.end();
if (pos < 0 || std::distance(itr, end) < pos) {
if (pos < 0 || std::distance(itr, end) < pos)
{
throw std::range_error("Cannot insert past end of range");
}
@ -124,410 +202,364 @@ namespace chaiscript::bootstrap::standard_library {
container.insert(itr, v);
}
/// Algorithm for erasing a specific position from a container
/**
* Algorithm for erasing a specific position from a container
*/
template<typename Type>
void erase_at(Type &container, int pos) {
auto itr = container.begin();
auto end = container.end();
void erase_at(Type &container, int pos)
{
typename Type::iterator itr = container.begin();
typename Type::iterator end = container.end();
if (pos < 0 || std::distance(itr, end) <= pos) {
if (pos < 0 || std::distance(itr, end) < (pos-1))
{
throw std::range_error("Cannot erase past end of range");
}
std::advance(itr, pos);
container.erase(itr);
}
} // namespace detail
template<typename ContainerType>
void input_range_type(const std::string &type, Module &m) {
detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator>>(type, m);
detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator>>("Const_" + type, m);
}
/// Add random_access_container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/RandomAccessContainer.html
template<typename ContainerType>
void random_access_container_type(const std::string & /*type*/, Module &m) {
ModulePtr input_range_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
detail::input_range_type_impl<Bidir_Range<ContainerType> >(type,m);
detail::input_range_type_impl<Const_Bidir_Range<ContainerType> >("Const_" + type, m);
return m;
}
/**
* Add random_access_container concept to the given ContainerType
* http://www.sgi.com/tech/stl/RandomAccessContainer.html
*/
template<typename ContainerType>
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
typedef typename ContainerType::const_reference(ContainerType::*constindexoper)(size_t) const;
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
//to throw an exception in an out of bounds condition.
m.add(fun([](ContainerType &c, int index) -> typename ContainerType::reference {
/// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
/// during dispatch. reevaluate
return c.at(static_cast<typename ContainerType::size_type>(index));
}),
"[]");
m->add(
fun(std::function<typename ContainerType::reference (ContainerType *, int)>
(std::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
m->add(
fun(std::function<typename ContainerType::const_reference (const ContainerType *, int)>
(std::mem_fn(static_cast<constindexoper>(&ContainerType::at)))), "[]");
m.add(fun([](const ContainerType &c, int index) -> typename ContainerType::const_reference {
/// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
/// during dispatch. reevaluate
return c.at(static_cast<typename ContainerType::size_type>(index));
}),
"[]");
return m;
}
/// Add assignable concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Assignable.html
/**
* Add assignable concept to the given ContainerType
* http://www.sgi.com/tech/stl/Assignable.html
*/
template<typename ContainerType>
void assignable_type(const std::string &type, Module &m) {
copy_constructor<ContainerType>(type, m);
ModulePtr assignable_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
basic_constructors<ContainerType>(type, m);
operators::assign<ContainerType>(m);
return m;
}
/// Add container resize concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/
/**
* Add container concept to the given ContainerType
* http://www.sgi.com/tech/stl/Container.html
*/
template<typename ContainerType>
void resizable_type(const std::string & /*type*/, Module &m) {
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type &val) {
return a->resize(n, val);
}),
"resize");
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); }), "resize");
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
m->add(fun( std::function<int (const ContainerType *)>( [](const ContainerType *a) { return a->size(); } ) ), "size");
m->add(fun( std::function<bool (const ContainerType *)>( [](const ContainerType *a) { return a->empty(); } ) ), "empty");
m->add(fun( std::function<void (ContainerType *)>( [](ContainerType *a) { a->clear(); } ) ), "clear");
return m;
}
/// Add container reserve concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/
template<typename ContainerType>
void reservable_type(const std::string & /*type*/, Module &m) {
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); }), "reserve");
m.add(fun([](const ContainerType *a) { return a->capacity(); }), "capacity");
}
/// Add container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Container.html
template<typename ContainerType>
void container_type(const std::string & /*type*/, Module &m) {
m.add(fun([](const ContainerType *a) { return a->size(); }), "size");
m.add(fun([](const ContainerType *a) { return a->empty(); }), "empty");
m.add(fun([](ContainerType *a) { a->clear(); }), "clear");
}
/// Add default constructable concept to the given Type
/// http://www.sgi.com/tech/stl/DefaultConstructible.html
/**
* Add default constructable concept to the given Type
* http://www.sgi.com/tech/stl/DefaultConstructible.html
*/
template<typename Type>
void default_constructible_type(const std::string &type, Module &m) {
m.add(constructor<Type()>(), type);
ModulePtr default_constructible_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(constructor<Type ()>(), type);
return m;
}
/// Add sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Sequence.html
/**
* Add sequence concept to the given ContainerType
* http://www.sgi.com/tech/stl/Sequence.html
*/
template<typename ContainerType>
void sequence_type(const std::string & /*type*/, Module &m) {
m.add(fun(&detail::insert_at<ContainerType>), []() -> std::string {
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
return "insert_ref_at";
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
std::string insert_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
insert_name = "insert_ref_at";
} else {
return "insert_at";
}
}());
m.add(fun(&detail::erase_at<ContainerType>), "erase_at");
insert_name = "insert_at";
}
/// Add back insertion sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html
m->add(fun(&detail::insert_at<ContainerType>), insert_name);
m->add(fun(&detail::erase_at<ContainerType>), "erase_at");
return m;
}
/**
* Add back insertion sequence concept to the given ContainerType
* http://www.sgi.com/tech/stl/BackInsertionSequence.html
*/
template<typename ContainerType>
void back_insertion_sequence_type(const std::string &type, Module &m) {
m.add(fun([](ContainerType &container) -> decltype(auto) {
if (container.empty()) {
throw std::range_error("Container empty");
ModulePtr back_insertion_sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
typedef typename ContainerType::reference (ContainerType::*backptr)();
m->add(fun(static_cast<backptr>(&ContainerType::back)), "back");
std::string push_back_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
push_back_name = "push_back_ref";
} else {
return (container.back());
}
}),
"back");
m.add(fun([](const ContainerType &container) -> decltype(auto) {
if (container.empty()) {
throw std::range_error("Container empty");
} else {
return (container.back());
}
}),
"back");
using push_back = void (ContainerType::*)(const typename ContainerType::value_type &);
m.add(fun(static_cast<push_back>(&ContainerType::push_back)), [&]() -> std::string {
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
m.eval("# Pushes the second value onto the container while making a clone of the value\n"
"def push_back("
+ type
+ " container, x)\n"
"{ \n"
" if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n"
" container.push_back_ref(x) \n"
" } else { \n"
" container.push_back_ref(clone(x)); \n"
" }\n"
"} \n");
return "push_back_ref";
} else {
return "push_back";
}
}());
m.add(fun(&ContainerType::pop_back), "pop_back");
push_back_name = "push_back";
}
/// Front insertion sequence
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
typedef void (ContainerType::*pushback)(const typename ContainerType::value_type &);
m->add(fun(static_cast<pushback>(&ContainerType::push_back)), push_back_name);
m->add(fun(&ContainerType::pop_back), "pop_back");
return m;
}
/**
*Front insertion sequence
*http://www.sgi.com/tech/stl/FrontInsertionSequence.html
*/
template<typename ContainerType>
void front_insertion_sequence_type(const std::string &type, Module &m) {
using push_ptr = void (ContainerType::*)(typename ContainerType::const_reference);
using pop_ptr = void (ContainerType::*)();
ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = ModulePtr(new Module()))
{
typedef typename ContainerType::reference (ContainerType::*frontptr)();
typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference);
typedef void (ContainerType::*popptr)();
m.add(fun([](ContainerType &container) -> decltype(auto) {
if (container.empty()) {
throw std::range_error("Container empty");
m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
std::string push_front_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
push_front_name = "push_front_ref";
} else {
return (container.front());
}
}),
"front");
m.add(fun([](const ContainerType &container) -> decltype(auto) {
if (container.empty()) {
throw std::range_error("Container empty");
} else {
return (container.front());
}
}),
"front");
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)), [&]() -> std::string {
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
m.eval("# Pushes the second value onto the front of container while making a clone of the value\n"
"def push_front("
+ type
+ " container, x)\n"
"{ \n"
" if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n"
" container.push_front_ref(x) \n"
" } else { \n"
" container.push_front_ref(clone(x)); \n"
" }\n"
"} \n");
return "push_front_ref";
} else {
return "push_front";
}
}());
m.add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front");
push_front_name = "push_front";
}
/// bootstrap a given PairType
/// http://www.sgi.com/tech/stl/pair.html
m->add(fun(static_cast<pushptr>(&ContainerType::push_front)), push_front_name);
m->add(fun(static_cast<popptr>(&ContainerType::pop_front)), "pop_front");
return m;
}
/**
* bootstrap a given PairType
* http://www.sgi.com/tech/stl/pair.html
*/
template<typename PairType>
void pair_type(const std::string &type, Module &m) {
m.add(user_type<PairType>(), type);
ModulePtr pair_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<PairType>(), type);
m.add(fun(&PairType::first), "first");
m.add(fun(&PairType::second), "second");
typename PairType::first_type PairType::* f = &PairType::first;
typename PairType::second_type PairType::* s = &PairType::second;
m->add(fun(f), "first");
m->add(fun(s), "second");
basic_constructors<PairType>(type, m);
m.add(constructor<PairType(const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
m->add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
return m;
}
/// Add pair associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/PairAssociativeContainer.html
/**
* Add pair associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/PairAssociativeContainer.html
*/
template<typename ContainerType>
void pair_associative_container_type(const std::string &type, Module &m) {
ModulePtr pair_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
pair_type<typename ContainerType::value_type>(type + "_Pair", m);
return m;
}
/// Add unique associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
/**
* Add unique associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
*/
template<typename ContainerType>
void unique_associative_container_type(const std::string & /*type*/, Module &m) {
m.add(fun(detail::count<ContainerType>), "count");
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
m->add(fun<int (const ContainerType *, const typename ContainerType::key_type &)>(&ContainerType::count), "count");
using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &);
typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &);
m.add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
m->add(fun<int (ContainerType *, const typename ContainerType::key_type &)>(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
m.add(fun(&detail::insert<ContainerType>), "insert");
m->add(fun(&detail::insert<ContainerType>), "insert");
m.add(fun(&detail::insert_ref<ContainerType>), []() -> std::string {
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
return "insert_ref";
std::string insert_name;
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value))
{
insert_name = "insert_ref";
} else {
return "insert";
}
}());
insert_name = "insert";
}
/// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html
m->add(fun(&detail::insert_ref<ContainerType>), insert_name);
return m;
}
/**
* Add a MapType container
* http://www.sgi.com/tech/stl/Map.html
*/
template<typename MapType>
void map_type(const std::string &type, Module &m) {
m.add(user_type<MapType>(), type);
using elem_access = typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &);
using const_elem_access = const typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &) const;
m.add(fun(static_cast<elem_access>(&MapType::operator[])), "[]");
m.add(fun(static_cast<elem_access>(&MapType::at)), "at");
m.add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>)) {
m.eval(R"(
def Map::`==`(Map rhs) {
if ( rhs.size() != this.size() ) {
return false;
} else {
auto r1 = range(this);
auto r2 = range(rhs);
while (!r1.empty())
ModulePtr map_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
if (!eq(r1.front().first, r2.front().first) || !eq(r1.front().second, r2.front().second))
{
return false;
}
r1.pop_front();
r2.pop_front();
}
true;
}
} )");
}
m->add(user_type<MapType>(), type);
typedef typename MapType::mapped_type &(MapType::*elemaccess)(const typename MapType::key_type &);
m->add(fun(static_cast<elemaccess>(&MapType::operator[])), "[]");
container_type<MapType>(type, m);
default_constructible_type<MapType>(type, m);
assignable_type<MapType>(type, m);
unique_associative_container_type<MapType>(type, m);
pair_associative_container_type<MapType>(type, m);
input_range_type<MapType>(type, m);
return m;
}
/// http://www.sgi.com/tech/stl/List.html
/**
* hopefully working List type
* http://www.sgi.com/tech/stl/List.html
*/
template<typename ListType>
void list_type(const std::string &type, Module &m) {
m.add(user_type<ListType>(), type);
ModulePtr list_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<ListType>(), type);
front_insertion_sequence_type<ListType>(type, m);
back_insertion_sequence_type<ListType>(type, m);
sequence_type<ListType>(type, m);
resizable_type<ListType>(type, m);
container_type<ListType>(type, m);
default_constructible_type<ListType>(type, m);
assignable_type<ListType>(type, m);
input_range_type<ListType>(type, m);
return m;
}
/// Create a vector type with associated concepts
/// http://www.sgi.com/tech/stl/Vector.html
/**
* Create a vector type with associated concepts
* http://www.sgi.com/tech/stl/Vector.html
*/
template<typename VectorType>
void vector_type(const std::string &type, Module &m) {
m.add(user_type<VectorType>(), type);
ModulePtr vector_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<VectorType>(), type);
m.add(fun([](VectorType &container) -> decltype(auto) {
if (container.empty()) {
throw std::range_error("Container empty");
} else {
return (container.front());
}
}),
"front");
typedef typename VectorType::reference (VectorType::*frontptr)();
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
m.add(fun([](const VectorType &container) -> decltype(auto) {
if (container.empty()) {
throw std::range_error("Container empty");
} else {
return (container.front());
}
}),
"front");
back_insertion_sequence_type<VectorType>(type, m);
sequence_type<VectorType>(type, m);
random_access_container_type<VectorType>(type, m);
resizable_type<VectorType>(type, m);
reservable_type<VectorType>(type, m);
container_type<VectorType>(type, m);
default_constructible_type<VectorType>(type, m);
assignable_type<VectorType>(type, m);
input_range_type<VectorType>(type, m);
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) {
m.eval(R"(
def Vector::`==`(Vector rhs) {
if ( rhs.size() != this.size() ) {
return false;
} else {
auto r1 = range(this);
auto r2 = range(rhs);
while (!r1.empty())
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{
if (!eq(r1.front(), r2.front()))
{
return false;
}
r1.pop_front();
r2.pop_front();
}
true;
}
} )");
}
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \
if ( rhs.size() != this.size() ) { \
return false; \
} else { \
auto r1 = range(this); \
auto r2 = range(rhs); \
while (!r1.empty()) \
{ \
if (!eq(r1.front(), r2.front())) \
{ \
return false; \
} \
r1.pop_front(); \
r2.pop_front(); \
} \
return true; \
} \
}");
}
/// Add a String container
/// http://www.sgi.com/tech/stl/basic_string.html
return m;
}
/**
* Add a String container
* http://www.sgi.com/tech/stl/basic_string.html
*/
template<typename String>
void string_type(const std::string &type, Module &m) {
m.add(user_type<String>(), type);
ModulePtr string_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<String>(), type);
operators::addition<String>(m);
operators::assign_sum<String>(m);
opers_comparison<String>(m);
random_access_container_type<String>(type, m);
sequence_type<String>(type, m);
default_constructible_type<String>(type, m);
// container_type<String>(type, m);
container_type<String>(type, m);
assignable_type<String>(type, m);
input_range_type<String>(type, m);
//Special case: add push_back to string (which doesn't support other back_insertion operations
m.add(fun(&String::push_back), []() -> std::string {
if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
return "push_back_ref";
std::string push_back_name;
if (typeid(typename String::value_type) == typeid(Boxed_Value))
{
push_back_name = "push_back_ref";
} else {
return "push_back";
push_back_name = "push_back";
}
}());
m->add(fun(&String::push_back), push_back_name);
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); }), "find");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); }), "rfind");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); }), "find_first_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); }), "find_last_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); }), "find_last_not_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); }), "find_first_not_of");
typedef std::function<int (const String *, const String &, int)> find_func;
m.add(fun([](String *s, typename String::value_type c) -> decltype(auto) { return (*s += c); }), "+=");
m.add(fun([](String *s) { s->clear(); }), "clear");
m.add(fun([](const String *s) { return s->empty(); }), "empty");
m.add(fun([](const String *s) { return s->size(); }), "size");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find(f, pos); } )), "find");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->rfind(f, pos); } ) ), "rfind");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_first_of(f, pos); } ) ), "find_first_of");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_last_of(f, pos); } ) ), "find_last_of");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_last_not_of(f, pos); } ) ), "find_last_not_of");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_first_not_of(f, pos); } ) ), "find_first_not_of");
m.add(fun([](const String *s) { return s->c_str(); }), "c_str");
m.add(fun([](const String *s) { return s->data(); }), "data");
m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); }), "substr");
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->c_str(); } ) ), "c_str");
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->data(); } ) ), "data");
m->add(fun( std::function<String (const String *, int, int)>( [](const String *s, int pos, int len) { return s->substr(pos, len); } ) ), "substr");
return m;
}
}
}
}
/// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html
template<typename FutureType>
void future_type(const std::string &type, Module &m) {
m.add(user_type<FutureType>(), type);
m.add(fun([](const FutureType &t) { return t.valid(); }), "valid");
m.add(fun([](FutureType &t) { return t.get(); }), "get");
m.add(fun(&FutureType::wait), "wait");
}
} // namespace chaiscript::bootstrap::standard_library
#endif

View File

@ -1,30 +1,24 @@
// 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)
// and 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_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_
#include "../chaiscript_defines.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "type_info.hpp"
#include "boxed_value.hpp"
#include "boxed_cast_helper.hpp"
#include "dynamic_cast_conversion.hpp"
namespace chaiscript {
class Type_Conversions;
}
namespace chaiscript::detail::exception {
class bad_any_cast;
} // namespace chaiscript::detail::exception
#include "../chaiscript_threading.hpp"
namespace chaiscript
{
namespace chaiscript {
/// \brief Function for extracting a value stored in a Boxed_Value object
/// \tparam Type The type to extract from the Boxed_Value
/// \param[in] bv The Boxed_Value to extract a typed value from
@ -68,35 +62,46 @@ namespace chaiscript {
/// assert(i == 5);
/// \endcode
template<typename Type>
decltype(auto) 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>())) {
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv)
{
try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
return detail::Cast_Helper<Type>::cast(bv);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
}
}
if (t_conversions && (*t_conversions)->convertable_type<Type>()) {
#ifdef CHAISCRIPT_MSVC
//Thank you MSVC, yes we know that a constant value is being used in the if
// statment in THIS VERSION of the template instantiation
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
if (std::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value)
{
try {
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
} catch (...) {
try {
// try going the other way
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv),
t_conversions));
return detail::Cast_Helper<Type>::cast(detail::boxed_dynamic_cast<Type>(bv));
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
}
} else {
// If it's not convertable, just throw the error, don't waste the time on the
// If it's not polymorphic, just throw the error, don't waste the time on the
// attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
}
} // namespace chaiscript
}
#endif

View File

@ -1,169 +1,158 @@
// 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)
// and 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_BOXED_CAST_HELPER_HPP_
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#include <memory>
#include <type_traits>
#include "boxed_value.hpp"
#include "type_info.hpp"
#include "boxed_value.hpp"
namespace chaiscript {
class Type_Conversions_State;
namespace detail {
namespace chaiscript
{
namespace detail
{
// Cast_Helper_Inner helper classes
template<typename T>
constexpr T *throw_if_null(T *t) {
if (t) {
return t;
}
throw std::runtime_error("Attempted to dereference null Boxed_Value");
}
/**
* Generic Cast_Helper_Inner, for casting to any type
*/
template<typename Result>
struct Cast_Helper_Inner
{
typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
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;
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.is_ref())
{
if (!ob.get_type_info().is_const())
{
return std::cref((ob.get().cast<std::reference_wrapper<Result> >()).get());
} else {
throw chaiscript::detail::exception::bad_any_cast();
return ob.get().cast<std::reference_wrapper<const Result> >();
}
}
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);
if (!ob.get_type_info().is_const())
{
return std::cref(*(ob.get().cast<std::shared_ptr<Result> >()));
} else {
throw chaiscript::detail::exception::bad_any_cast();
return std::cref(*(ob.get().cast<std::shared_ptr<const Result> >()));
}
}
}
};
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);
template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
{
};
/**
* Cast_Helper_Inner for casting to a const & type
*/
template<typename Result>
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
{
};
/**
* Cast_Helper_Inner for casting to a const * type
*/
template<typename Result>
struct Cast_Helper_Inner<const Result *>
{
typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.is_ref())
{
if (!ob.get_type_info().is_const())
{
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
} else {
throw chaiscript::detail::exception::bad_any_cast();
return &(ob.get().cast<std::reference_wrapper<const Result> >()).get();
}
} else {
if (!ob.get_type_info().is_const())
{
return (ob.get().cast<std::shared_ptr<Result> >()).get();
} else {
return (ob.get().cast<std::shared_ptr<const Result> >()).get();
}
}
/// Generic Cast_Helper_Inner, for casting to any type
template<typename Result>
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()));
}
};
/**
* Cast_Helper_Inner for casting to a * type
*/
template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> {
};
struct Cast_Helper_Inner<Result *>
{
typedef Result * Result_Type;
/// Cast_Helper_Inner for casting to a const * type
template<typename Result>
struct Cast_Helper_Inner<const Result *> {
static const Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.is_ref())
{
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
} else {
return (ob.get().cast<std::shared_ptr<Result> >()).get();
}
}
};
/// Cast_Helper_Inner for casting to a * type
/**
* Cast_Helper_Inner for casting to a & type
*/
template<typename Result>
struct Cast_Helper_Inner<Result *> {
static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
struct Cast_Helper_Inner<Result &>
{
typedef Result& Result_Type;
static Result &cast(const Boxed_Value &ob)
{
if (ob.is_ref())
{
return ob.get().cast<std::reference_wrapper<Result> >();
} else {
Result &r = *(ob.get().cast<std::shared_ptr<Result> >());
return r;
}
}
};
/**
* Cast_Helper_Inner for casting to a std::shared_ptr<> type
*/
template<typename Result>
struct Cast_Helper_Inner<Result *const &> : public Cast_Helper_Inner<Result *> {
};
struct Cast_Helper_Inner<typename std::shared_ptr<Result> >
{
typedef typename std::shared_ptr<Result> Result_Type;
template<typename Result>
struct Cast_Helper_Inner<const Result *const &> : public Cast_Helper_Inner<const Result *> {
};
/// Cast_Helper_Inner for casting to a & type
template<typename Result>
struct Cast_Helper_Inner<const Result &> {
static const Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
static Result_Type cast(const Boxed_Value &ob)
{
return ob.get().cast<std::shared_ptr<Result> >();
}
};
/// Cast_Helper_Inner for casting to a & type
/**
* Cast_Helper_Inner for casting to a std::shared_ptr<const> type
*/
template<typename Result>
struct Cast_Helper_Inner<Result &> {
static Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
}
};
struct Cast_Helper_Inner<typename std::shared_ptr<const Result> >
{
typedef typename std::shared_ptr<const Result> Result_Type;
/// Cast_Helper_Inner for casting to a && type
template<typename Result>
struct Cast_Helper_Inner<Result &&> {
static Result &&cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &&> {
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &> {
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<const std::unique_ptr<Result> &> {
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result>> {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob.get().cast<std::shared_ptr<Result>>(); }
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<const Result>> {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
if (!ob.get_type_info().is_const()) {
static Result_Type cast(const Boxed_Value &ob)
{
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> >();
@ -171,90 +160,111 @@ namespace chaiscript {
}
};
/// 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>
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>
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> >
{
};
/**
* Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
*/
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
{
};
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> &> {
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result>>();
return ob.pointer_sentinel(res);
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
*/
template<>
struct Cast_Helper_Inner<Boxed_Value>
{
typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return ob;
}
};
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result>> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
};
template<typename 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 const Boxed_Value & type
*/
template<>
struct Cast_Helper_Inner<Boxed_Value> {
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob; }
};
/// Cast_Helper_Inner for casting to a Boxed_Value & type
template<>
struct Cast_Helper_Inner<Boxed_Value &> {
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return std::ref(const_cast<Boxed_Value &>(ob));
}
};
/// Cast_Helper_Inner for casting to a const Boxed_Value & type
template<>
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<>
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>
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>
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>
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>
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>
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>
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>
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));
struct Cast_Helper
{
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return Cast_Helper_Inner<T>::cast(ob);
}
};
} // namespace detail
}
} // namespace chaiscript
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,271 +1,276 @@
// 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)
// and 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_BOXED_VALUE_HPP_
#define CHAISCRIPT_BOXED_VALUE_HPP_
#include <map>
#include <memory>
#include <type_traits>
#include "../chaiscript_defines.hpp"
#include "any.hpp"
#include "type_info.hpp"
namespace chaiscript {
#include "../chaiscript_threading.hpp"
#include <map>
#include "any.hpp"
namespace chaiscript
{
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
/// \sa chaiscript::boxed_cast
class Boxed_Value {
class Boxed_Value
{
public:
/// used for explicitly creating a "void" object
struct Void_Type {
/**
* used for explicitly creating a "void" object
*/
struct Void_Type
{
};
private:
/// structure which holds the internal state of a Boxed_Value
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process
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)
, m_obj(std::move(to))
, m_data_ptr(ti.is_const() ? nullptr : const_cast<void *>(t_void_ptr))
, m_const_data_ptr(t_void_ptr)
, m_is_ref(is_ref)
, m_return_value(t_return_value) {
/**
* structure which holds the internal state of a Boxed_Value
*/
struct Data
{
Data(const Type_Info &ti,
const chaiscript::detail::Any &to,
bool tr,
const void *t_void_ptr)
: m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?0:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
m_is_ref(tr)
{
}
Data &operator=(const Data &rhs) {
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);
}
return *this;
}
Data(const Data &) = delete;
Data(Data &&) = default;
Data &operator=(Data &&rhs) = default;
~Data()
{
}
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 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);
struct Object_Data
{
static std::shared_ptr<Data> get(Boxed_Value::Void_Type)
{
return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
chaiscript::detail::Any(),
false,
nullptr)
;
}
template<typename T>
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) {
return get(*obj, t_return_value);
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj)
{
return get(*obj);
}
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);
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj)
{
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj),
false,
obj.get()
);
}
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);
static std::shared_ptr<Data> get(T *t)
{
return get(std::ref(*t));
}
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))),
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
{
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj),
true,
ptr,
t_return_value);
&obj.get()
);
}
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(const T& t)
{
auto p = std::make_shared<T>(t);
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(p),
false,
p.get()
);
}
static std::shared_ptr<Data> get()
{
return std::make_shared<Data>(
Type_Info(),
chaiscript::detail::Any(),
false,
nullptr
);
}
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)) {
/**
* Basic Boxed_Value constructor
*/
template<typename T>
explicit Boxed_Value(T t)
: m_data(Object_Data::get(t))
{
}
/// Unknown-type constructor
Boxed_Value() = default;
/**
* Copy constructor - each copy shares the same data pointer
*/
Boxed_Value(const Boxed_Value &t_so)
: m_data(t_so.m_data)
{
}
Boxed_Value(Boxed_Value &&) = default;
Boxed_Value &operator=(Boxed_Value &&) = default;
Boxed_Value(const Boxed_Value &) = default;
Boxed_Value &operator=(const Boxed_Value &) = default;
/**
* Unknown-type constructor
*/
Boxed_Value()
: m_data(Object_Data::get())
{
}
void swap(Boxed_Value &rhs) noexcept { std::swap(m_data, rhs.m_data); }
~Boxed_Value()
{
}
/// 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 {
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;
}
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 {
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
: m_ptr(t_ptr)
, m_data(data) {
}
~Sentinel() {
// save new pointer data
const auto ptr_ = m_ptr.get().get();
m_data.get().m_data_ptr = ptr_;
m_data.get().m_const_data_ptr = ptr_;
}
Sentinel &operator=(Sentinel &&s) = default;
Sentinel(Sentinel &&s) = default;
operator std::shared_ptr<T> &() const noexcept { return m_ptr.get(); }
Sentinel &operator=(const Sentinel &) = delete;
Sentinel(Sentinel &) = delete;
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
std::reference_wrapper<Data> m_data;
};
return Sentinel(ptr, *(m_data.get()));
}
bool is_null() const noexcept { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); }
const chaiscript::detail::Any &get() const noexcept { return m_data->m_obj; }
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];
if (attr) {
return Boxed_Value(attr, Internal_Construction());
} else {
Boxed_Value bv; // default construct a new one
attr = bv.m_data;
return bv;
}
}
Boxed_Value &copy_attrs(const Boxed_Value &t_obj) {
if (t_obj.m_data->m_attrs) {
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
}
/**
* shared data assignment, same as copy construction
*/
Boxed_Value &operator=(const Boxed_Value &rhs)
{
Boxed_Value temp(rhs);
swap(temp);
return *this;
}
Boxed_Value &clone_attrs(const Boxed_Value &t_obj) {
copy_attrs(t_obj);
reset_return_value();
return *this;
const Type_Info &get_type_info() const
{
return m_data->m_type_info;
}
/**
* return true if the object is uninitialized
*/
bool is_undef() const
{
return m_data->m_type_info.is_undef();
}
bool is_const() const
{
return m_data->m_type_info.is_const();
}
bool is_type(const Type_Info &ti) const
{
return m_data->m_type_info.bare_equal(ti);
}
bool is_null() const
{
return (m_data->m_data_ptr == 0 && m_data->m_const_data_ptr == 0);
}
const chaiscript::detail::Any & get() const
{
return m_data->m_obj;
}
bool is_ref() const
{
return m_data->m_is_ref;
}
bool is_pointer() const
{
return !is_ref();
}
void *get_ptr() const
{
return m_data->m_data_ptr;
}
const void *get_const_ptr() const
{
return m_data->m_const_data_ptr;
}
/// \returns true if the two Boxed_Values share the same internal type
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept { return l.get_type_info() == r.get_type_info(); }
private:
// necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction {
};
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
: m_data(std::move(t_data)) {
static bool type_match(Boxed_Value l, Boxed_Value r)
{
return l.get_type_info() == r.get_type_info();
}
std::shared_ptr<Data> m_data = Object_Data::get();
private:
std::shared_ptr<Data> m_data;
};
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or
/// std::reference_type
/// \brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
/// a copy is not made.
/// @param t The value to box
/// \param t The value to box
///
/// Example:
///
/// ~~~{.cpp}
/// \code
/// int i;
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::var(i), "i");
/// chai.add(chaiscript::var(&i), "ip");
/// ~~~
/// \endcode
///
/// @sa @ref adding_objects
/// \sa \ref addingobjects
template<typename T>
Boxed_Value var(T &&t) {
return Boxed_Value(std::forward<T>(t));
Boxed_Value var(T t)
{
return Boxed_Value(t);
}
namespace detail {
@ -274,8 +279,9 @@ namespace chaiscript {
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
template<typename T>
Boxed_Value const_var_impl(const T &t) {
return Boxed_Value(std::make_shared<typename std::add_const<T>::type>(t));
Boxed_Value const_var_impl(const T &t)
{
return Boxed_Value(std::shared_ptr<typename std::add_const<T>::type >(new T(t)));
}
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
@ -284,7 +290,8 @@ namespace chaiscript {
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
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) );
}
@ -294,7 +301,8 @@ namespace chaiscript {
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
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) );
}
@ -304,10 +312,11 @@ namespace chaiscript {
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
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()) );
}
} // namespace detail
}
/// \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.
@ -330,29 +339,16 @@ namespace chaiscript {
/// chai.add(chaiscript::const_var(Green), "Green");
/// \endcode
///
/// \todo support C++11 strongly typed enums
/// \sa \ref adding_objects
/// \sa \ref addingobjects
template<typename T>
Boxed_Value const_var(const T &t) {
Boxed_Value const_var(const T &t)
{
return detail::const_var_impl(t);
}
inline Boxed_Value void_var() {
static const auto v = Boxed_Value(Boxed_Value::Void_Type());
return v;
}
inline Boxed_Value const_var(bool b) {
static const auto t = detail::const_var_impl(true);
static const auto f = detail::const_var_impl(false);
if (b) {
return t;
} else {
return f;
}
}
} // namespace chaiscript
#endif

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,287 @@
// 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_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include "type_info.hpp"
#include "boxed_value.hpp"
#include "boxed_cast_helper.hpp"
#include "bad_boxed_cast.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_dynamic_cast(const std::string &w) noexcept
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_dynamic_cast() noexcept {}
};
}
namespace detail
{
class Dynamic_Conversion
{
public:
virtual Boxed_Value convert(const Boxed_Value &derived) = 0;
const Type_Info &base()
{
return m_base;
}
const Type_Info &derived()
{
return m_derived;
}
protected:
Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived)
: m_base(t_base), m_derived(t_derived)
{
}
virtual ~Dynamic_Conversion() {}
private:
Type_Info m_base;
Type_Info m_derived;
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Dynamic_Conversion
{
public:
Dynamic_Conversion_Impl()
: Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
{
}
virtual Boxed_Value convert(const Boxed_Value &t_derived)
{
if (t_derived.get_type_info().bare_equal(user_type<Derived>()))
{
if (t_derived.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_derived.is_const())
{
std::shared_ptr<const Base> data
= std::dynamic_pointer_cast<const Base>(detail::Cast_Helper<std::shared_ptr<const Derived> >::cast(t_derived));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
} else {
std::shared_ptr<Base> data
= std::dynamic_pointer_cast<Base>(detail::Cast_Helper<std::shared_ptr<Derived> >::cast(t_derived));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_derived.is_const())
{
const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived);
const Base &data = dynamic_cast<const Base &>(d);
return Boxed_Value(std::cref(data));
} else {
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived);
Base &data = dynamic_cast<Base &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_derived.get_type_info(), typeid(Base), "Unknown dynamic_cast_conversion");
}
}
};
class Dynamic_Conversions
{
public:
static inline Dynamic_Conversions &get()
{
static Dynamic_Conversions obj;
return obj;
}
template<typename Base, typename Derived>
static std::shared_ptr<Dynamic_Conversion> create()
{
std::shared_ptr<Dynamic_Conversion> conversion(new Dynamic_Conversion_Impl<Base, Derived>());
/// \todo this is a hack and a kludge. The idea is to make sure that
/// the conversion is registered both in the module's notion of the static conversion object
/// and in the global notion of the static conversion object
/// someday this will almost certainly have to change. Maybe it is time for ChaiScript
/// to become a library?
Dynamic_Conversions::get().add_conversion(conversion);
return conversion;
}
template<typename InItr>
void cleanup(InItr begin, const InItr &end)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
while (begin != end)
{
if (begin->unique())
{
m_conversions.erase(begin->get());
}
++begin;
}
}
void add_conversion(const std::shared_ptr<Dynamic_Conversion> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion.get());
}
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(base, derived) != m_conversions.end();
}
Dynamic_Conversion *get_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
std::set<Dynamic_Conversion *>::const_iterator itr =
find(base, derived);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name());
}
}
private:
Dynamic_Conversions() {}
std::set<Dynamic_Conversion *>::const_iterator find(
const Type_Info &base, const Type_Info &derived) const
{
for (std::set<Dynamic_Conversion *>::const_iterator itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
{
return itr;
}
}
return m_conversions.end();
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<Dynamic_Conversion *> m_conversions;
};
}
typedef std::shared_ptr<chaiscript::detail::Dynamic_Conversion> Dynamic_Cast_Conversion;
/// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new base class registration for applying to a module or to the chaiscript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the base type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<Base, Derived>());
/// \endcode
///
/// \todo Move share static type registration code into a mechanism that allows it to be properly
/// shared by all modules
template<typename Base, typename Derived>
Dynamic_Cast_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
return detail::Dynamic_Conversions::create<Base, Derived>();
}
namespace detail
{
template<typename Base, typename Derived>
bool dynamic_cast_converts()
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived)
{
return detail::Dynamic_Conversions::get().has_conversion(base, derived);
}
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived)
{
try {
return detail::Dynamic_Conversions::get().get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
} catch (const std::out_of_range &) {
throw chaiscript::exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
} catch (const std::bad_cast &) {
throw chaiscript::exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
}
}
}
}
#endif

View File

@ -1,98 +1,272 @@
// 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)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#include <map>
#include <string>
#include <utility>
#include "boxed_value.hpp"
namespace chaiscript {
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
namespace chaiscript {
namespace dispatch {
struct option_explicit_set : std::runtime_error {
explicit option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") {
}
option_explicit_set(const option_explicit_set &) = default;
~option_explicit_set() noexcept override = default;
};
class Dynamic_Object {
namespace chaiscript
{
namespace dispatch
{
class Dynamic_Object
{
public:
explicit Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name))
, m_option_explicit(false) {
Dynamic_Object(const std::string &t_type_name)
: m_type_name(t_type_name)
{
}
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");
}
std::string get_type_name() const
{
return m_type_name;
}
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);
Boxed_Value get_attr(const std::string &t_attr_name)
{
return m_attrs[t_attr_name];
}
return get_attr(t_method_name);
std::map<std::string, Boxed_Value> get_attrs()
{
return m_attrs;
}
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:
const std::string m_type_name = "";
bool m_option_explicit = false;
std::string m_type_name;
std::map<std::string, Boxed_Value> m_attrs;
};
} // namespace dispatch
} // namespace chaiscript
namespace detail
{
/**
* A Proxy_Function implementation designed for calling a function
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
const std::string &t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(t_func->get_param_types()),
m_type_name(t_type_name), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function(
const std::string &t_type_name,
const Proxy_Function &t_func,
const Type_Info &t_ti)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)),
m_type_name(t_type_name), m_func(t_func), m_ti(new Type_Info(t_ti))
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
virtual ~Dynamic_Object_Function() {}
virtual bool operator==(const Proxy_Function_Base &f) const
{
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f);
if (df)
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti))
{
return m_func->call_match(vals);
} else {
return false;
}
}
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
{
return {m_func};
}
virtual int get_arity() const
{
return m_func->get_arity();
}
virtual std::string annotation() const
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
{
if (dynamic_object_typename_match(params, m_type_name, m_ti))
{
return (*m_func)(params);
} else {
throw exception::guard_error();
}
}
virtual bool compare_first_type(const Boxed_Value &bv) const
{
return dynamic_object_typename_match(bv, m_type_name, m_ti);
}
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;
}
static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::shared_ptr<Type_Info> &ti)
{
static Type_Info doti = user_type<Dynamic_Object>();
if (bv.get_type_info().bare_equal(doti))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
if (ti)
{
return bv.get_type_info().bare_equal(*ti);
} else {
return false;
}
}
}
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::shared_ptr<Type_Info> &ti)
{
if (bvs.size() > 0)
{
return dynamic_object_typename_match(bvs[0], name, ti);
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
std::shared_ptr<Type_Info> m_ti;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
const std::string &t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types())),
m_type_name(t_type_name), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
std::vector<Type_Info>::const_iterator begin = tl.begin();
std::vector<Type_Info>::const_iterator end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const
{
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
if (dc)
{
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
std::vector<Boxed_Value> new_vals;
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals);
}
virtual int get_arity() const
{
// "this" is not considered part of the arity
return m_func->get_arity() - 1;
}
virtual std::string annotation() const
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
{
std::vector<Boxed_Value> new_params;
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
new_params.push_back(bv);
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params);
return bv;
}
private:
std::string m_type_name;
Proxy_Function m_func;
};
}
}
}
#endif

View File

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

View File

@ -1,43 +1,82 @@
// 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)
// and 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_EXCEPTION_SPECIFICATION_HPP_
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#include <memory>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
namespace chaiscript {
namespace detail {
struct Exception_Handler_Base {
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
virtual ~Exception_Handler_Base() = default;
namespace chaiscript
{
namespace detail
{
struct Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv) = 0;
protected:
template<typename T>
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) {
try {
T t = t_engine.boxed_cast<T>(bv);
throw t;
} catch (const chaiscript::exception::bad_boxed_cast &) {
}
void throw_type(const Boxed_Value &bv)
{
try { T t = boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
}
};
template<typename... T>
struct Exception_Handler_Impl : Exception_Handler_Base {
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override { (throw_type<T>(bv, t_engine), ...); }
template<typename T1>
struct Exception_Handler_Impl1 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
}
};
} // namespace detail
template<typename T1, typename T2>
struct Exception_Handler_Impl2 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
}
};
template<typename T1, typename T2, typename T3>
struct Exception_Handler_Impl3 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T3>(bv);
}
};
template<typename T1, typename T2, typename T3, typename T4>
struct Exception_Handler_Impl4 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T3>(bv);
throw_type<T4>(bv);
}
};
template<typename T1, typename T2, typename T3, typename T4, typename T5>
struct Exception_Handler_Impl5 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T3>(bv);
throw_type<T4>(bv);
throw_type<T5>(bv);
}
};
}
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
///
@ -49,8 +88,7 @@ namespace chaiscript {
/// chaiscript::ChaiScript chai;
///
/// 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 (int) {
/// } catch (float) {
@ -90,14 +128,49 @@ namespace chaiscript {
///
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
/// \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
/// \sa \ref exceptions
template<typename... T>
Exception_Handler exception_specification() {
return std::make_shared<detail::Exception_Handler_Impl<T...>>();
template<typename T1>
Exception_Handler exception_specification()
{
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

View File

@ -1,122 +1,133 @@
// 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)
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
// and 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_CALL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_HPP_
#include <functional>
#include <string>
#include <vector>
#include "boxed_cast.hpp"
#include "function_call_detail.hpp"
#include "proxy_functions.hpp"
#include "function_call_detail.hpp"
namespace chaiscript {
class Boxed_Value;
class Type_Conversions_State;
namespace detail {
template<typename T>
struct Cast_Helper;
} // namespace detail
} // namespace chaiscript
namespace chaiscript {
namespace dispatch {
namespace detail {
template<typename Ret, typename... Param>
constexpr auto arity(Ret (*)(Param...)) noexcept {
return sizeof...(Param);
}
} // namespace detail
#include <iostream>
/// Build a function caller that knows how to dispatch on a set of functions
/// example:
/// std::function<void (int)> f =
/// build_function_caller(dispatchkit.get_function("print"));
/// \returns A std::function object for dispatching
/// \param[in] funcs the set of functions to dispatch on.
namespace chaiscript
{
namespace dispatch
{
/**
* Build a function caller that knows how to dispatch on a set of functions
* example:
* std::function<void (int)> f =
* build_function_caller(dispatchkit.get_function("print"));
* \returns A std::function object for dispatching
* \param[in] funcs the set of functions to dispatch on.
*/
template<typename FunctionType>
std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
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()) == detail::arity(static_cast<FunctionType *>(nullptr));
});
if (!has_arity_match) {
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs)
{
FunctionType *p=0;
return detail::build_function_caller_helper(p, funcs);
}
FunctionType *p = nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions);
}
/// Build a function caller for a particular Proxy_Function object
/// useful in the case that a function is being pass out from scripting back
/// into code
/// example:
/// void my_function(Proxy_Function f)
/// {
/// std::function<void (int)> local_f =
/// build_function_caller(f);
/// }
/// \returns A std::function object for dispatching
/// \param[in] func A function to execute.
/**
* Build a function caller for a particular Proxy_Function object
* useful in the case that a function is being pass out from scripting back
* into code
* example:
* void my_function(Proxy_Function f)
* {
* std::function<void (int)> local_f =
* build_function_caller(f);
* }
* \returns A std::function object for dispatching
* \param[in] func A function to execute.
*/
template<typename FunctionType>
std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) {
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
std::function<FunctionType>
functor(Const_Proxy_Function func)
{
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(func);
return functor<FunctionType>(funcs);
}
/// Helper for automatically unboxing a Boxed_Value that contains a function object
/// and creating a typesafe C++ function caller from it.
/**
* Helper for automatically unboxing a Boxed_Value that contains a function object
* and creating a typesafe C++ function caller from it.
*/
template<typename FunctionType>
std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) {
return functor<FunctionType>(boxed_cast<Const_Proxy_Function>(bv, t_conversions), t_conversions);
std::function<FunctionType>
functor(const Boxed_Value &bv)
{
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv));
}
}
} // namespace dispatch
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>
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>())) {
return dispatch::functor<Signature>(ob, t_conversions);
struct Cast_Helper<const std::function<Signature> &>
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob);
} else {
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob);
}
}
};
/// Cast helper to handle automatic casting to std::function
/**
* Cast helper to handle automatic casting to std::function
*/
template<typename 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>())) {
return dispatch::functor<Signature>(ob, t_conversions);
struct Cast_Helper<std::function<Signature> >
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob);
} else {
return Cast_Helper_Inner<std::function<Signature>>::cast(ob, t_conversions);
return Cast_Helper_Inner<std::function<Signature> >::cast(ob);
}
}
};
/// Cast helper to handle automatic casting to const std::function
/**
* Cast helper to handle automatic casting to const std::function
*/
template<typename 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>())) {
return dispatch::functor<Signature>(ob, t_conversions);
struct Cast_Helper<const std::function<Signature> >
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob);
} else {
return Cast_Helper_Inner<const std::function<Signature>>::cast(ob, t_conversions);
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob);
}
}
};
} // namespace detail
} // namespace chaiscript
}
}
#endif

View File

@ -1,80 +1,79 @@
// 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)
// and 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_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "proxy_functions.hpp"
#include "type_conversions.hpp"
namespace chaiscript::dispatch::detail {
/// used internally for unwrapping a function call's types
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret>
struct Function_Caller_Ret
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params)
{
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params));
}
};
/**
* Specialization for void return types
*/
template<>
struct Function_Caller_Ret<void>
{
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params)
{
dispatch::dispatch(t_funcs, params);
}
};
/**
* 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) {
struct Build_Function_Caller_Helper
{
Build_Function_Caller_Helper(const std::vector<Const_Proxy_Function> &t_funcs)
: m_funcs(t_funcs)
{
}
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);
}
Ret operator()(Param...param)
{
return Function_Caller_Ret<Ret>::call(m_funcs, {
(std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)...
}
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) {
/*
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs)
{
if (funcs.size() == 1)
{
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
@ -88,10 +87,12 @@ namespace chaiscript::dispatch::detail {
// 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));
}
}
}
}
} // namespace chaiscript::dispatch::detail
#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,195 +1,187 @@
// 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)
// and 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_HANDLE_RETURN_HPP_
#define CHAISCRIPT_HANDLE_RETURN_HPP_
#include <functional>
#include <memory>
#include <type_traits>
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "boxed_number.hpp"
#include "type_info.hpp"
#include <string>
namespace chaiscript {
class Boxed_Number;
} // namespace chaiscript
#include <stdexcept>
#include <vector>
namespace chaiscript {
namespace dispatch {
template<class T, class U>
class Proxy_Function_Callable_Impl;
template<class T>
class Assignable_Proxy_Function_Impl;
namespace detail {
/// Used internally for handling a return value from a Proxy_Function call
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
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) {
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>>)>>
static Boxed_Value handle(T &&r) {
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
struct Handle_Return
{
static Boxed_Value handle(const Ret &r)
{
return const_var(r);
}
};
template<typename Ret>
struct Handle_Return<const std::function<Ret> &> {
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
struct Handle_Return<Ret *>
{
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p);
}
};
template<typename Ret>
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &> {
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>>> {
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f), f));
struct Handle_Return<std::shared_ptr<Ret> &>
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
};
template<typename Ret>
struct Handle_Return<std::function<Ret> &> {
static Boxed_Value handle(std::function<Ret> &f) {
return Boxed_Value(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(
std::ref(f), std::shared_ptr<std::function<Ret>>()));
}
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
struct Handle_Return<std::shared_ptr<Ret> >
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<Ret *&> {
static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
struct Handle_Return<const Ret *&> {
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
struct Handle_Return<Ret *> {
static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
struct Handle_Return<const Ret *> {
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
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>
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> {
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &> {
};
template<typename Ret>
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &> {
static Boxed_Value handle(std::unique_ptr<Ret> &&r) { return Boxed_Value(std::move(r), true); }
};
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);
struct Handle_Return<const std::shared_ptr<Ret> &>
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
}
};
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);
struct Handle_Return<const Ret &>
{
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> {
};
struct Handle_Return<Ret &>
{
static Boxed_Value handle(Ret &r)
{
return Boxed_Value(std::ref(r));
}
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> {
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Number> {
static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; }
};
template<>
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number> {
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<void> {
static Boxed_Value handle() { return void_var(); }
struct Handle_Return<const Boxed_Value>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
/**
* 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

View File

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

View File

@ -1,37 +1,39 @@
// 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)
// and 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_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include "proxy_functions.hpp"
namespace chaiscript::dispatch::detail {
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/**
* A constructor function, used for creating a new object
* of a given type with a given set of params
*/
template<typename Class, typename ... Params>
Proxy_Function build_constructor_(Class (*)(Params...)) {
if constexpr (!std::is_copy_constructible_v<Class>) {
auto call = [](auto &&...param) { return std::make_shared<Class>(std::forward<decltype(param)>(param)...); };
std::shared_ptr<Class> constructor_(Params ... params)
{
return std::shared_ptr<Class>(new Class(params...));
}
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base,
dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class>(Params...), decltype(call)>>(call));
} else if constexpr (true) {
auto call = [](auto &&...param) { return Class(std::forward<decltype(param)>(param)...); };
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Class(Params...), decltype(call)>>(
call));
template<typename Class, typename ... Params >
Proxy_Function build_constructor_(Class (*)(Params...))
{
typedef std::shared_ptr<Class> (sig)(Params...);
return Proxy_Function(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>))));
}
}
}
} // namespace chaiscript::dispatch::detail
namespace 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, ...)
@ -44,10 +46,13 @@ namespace chaiscript {
/// chai.add(constructor<MyClass (int, float)>(), "MyClass");
/// \endcode
template<typename T>
Proxy_Function constructor() {
T *f = nullptr;
Proxy_Function constructor()
{
T *f = 0;
return (dispatch::detail::build_constructor_(f));
}
} // namespace chaiscript
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,111 +1,179 @@
// 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)
// and 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_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#include <array>
#include <functional>
#include "boxed_value.hpp"
#include "boxed_cast.hpp"
#include "type_info.hpp"
#include "handle_return.hpp"
#include <string>
#include <stdexcept>
#include <vector>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_value.hpp"
#include "function_params.hpp"
#include "handle_return.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions_State;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript {
namespace exception {
namespace chaiscript
{
namespace exception
{
/**
* Exception thrown when there is a mismatch in number of
* 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)
: std::range_error("Function dispatch arity mismatch")
, got(t_got)
, expected(t_expected) {
: std::range_error("Function dispatch arity mismatch"),
got(t_got), expected(t_expected)
{
}
arity_error(const arity_error &) = default;
~arity_error() noexcept override = default;
virtual ~arity_error() noexcept {}
int got;
int expected;
};
} // namespace exception
}
namespace dispatch {
namespace detail {
namespace dispatch
{
namespace detail
{
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret, typename ... 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>()...};
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
{
return std::vector<Type_Info> { chaiscript::detail::Get_Type_Info<Ret>::get(),
chaiscript::detail::Get_Type_Info<Params>::get()... };
}
// Forward declaration
template<typename ... Rest>
struct Try_Cast;
// implementation
template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...>
{
static void do_try(const std::vector<Boxed_Value> &params, int generation)
{
boxed_cast<Param>(params[generation]);
Try_Cast<Rest...>::do_try(params, generation+1);
}
};
// 0th case
template<>
struct Try_Cast<>
{
static void do_try(const std::vector<Boxed_Value> &, int)
{
}
};
/**
* 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 primarly used to prevent
* registration of two functions with the exact same signatures
*/
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...),
const std::vector<Boxed_Value> &params)
{
try {
std::vector<Boxed_Value>::size_type i = 0;
(boxed_cast<Params>(params[i++], &t_conversions), ...);
return true;
Try_Cast<Params...>::do_try(params, 0);
} catch (const exception::bad_boxed_cast &) {
return false;
}
return true;
}
template<typename Callable, typename Ret, typename... Params, size_t... I>
Ret call_func(Ret (*)(Params...),
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)...);
template<typename Ret, int count, typename ... Params>
struct Call_Func
{
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, InnerParams &&... innerparams)
{
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
}
};
template<typename Ret, typename ... Params>
struct Call_Func<Ret, 0, Params...>
{
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams))...);
}
};
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter 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 Ret, typename ... Params>
Ret call_func(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params)
{
if (params.size() == sizeof...(Params))
{
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params);
}
/// Used by Proxy_Function_Impl to perform typesafe execution of a function.
/// The function attempts to unbox each parameter to the expected type.
/// if any unboxing fails the execution of the function fails and
/// the bad_boxed_cast is passed up to the caller.
template<typename Callable, typename Ret, typename... Params>
Boxed_Value
call_func(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);
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
}
}
}
}
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
template<typename Ret>
struct Do_Call
{
template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params)
{
return Handle_Return<Ret>::handle(call_func(fun, params));
}
};
template<>
struct Do_Call<void>
{
template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params)
{
call_func(fun, params);
return Handle_Return<void>::handle();
} else {
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
}
};
}
}
}
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
#endif

View File

@ -1,62 +1,90 @@
// 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)
// and 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_REGISTER_FUNCTION_HPP_
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
#include <type_traits>
#include "dispatchkit.hpp"
#include "bind_first.hpp"
#include "function_signature.hpp"
#include "proxy_functions.hpp"
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)...));
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
template<typename T>
struct FunctionSignature
{
};
template<typename Sig>
struct FunctionSignature<std::function<Sig> >
{
typedef Sig Signature;
};
template<typename Ret, typename ... Args>
std::function<Ret (Args...) > to_function(Ret (*func)(Args...))
{
return std::function<Ret (Args...)>(func);
}
template<typename Ret, typename Class, typename ... Args>
std::function<Ret (Class &, Args...) > to_function(Ret (Class::*func)(Args...))
{
return std::function<Ret (Class &, Args...)>(func);
}
template<typename Ret, typename Class, typename ... Args>
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
{
return std::function<Ret (const Class &, Args...)>(func);
}
template<bool Object>
struct Fun_Helper
{
template<typename T>
static Proxy_Function go(T t)
{
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)));
new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t)));
}
};
template<>
struct Fun_Helper<true>
{
template<typename T, typename Class>
static Proxy_Function go(T Class::* m)
{
return Proxy_Function(new Attribute_Access<T, Class>(m));
}
};
}
}
// 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>{});
/// \brief Creates a new Proxy_Function object from a std::function object
/// \param[in] f std::function to expose to ChaiScript
///
/// \b Example:
/// \code
/// std::function<int (char, float, std::string)> f = get_some_function();
/// chaiscript::ChaiScript chai;
/// chai.add(fun(f), "some_function");
/// \endcode
///
/// \sa \ref addingfunctions
template<typename T>
Proxy_Function fun(const std::function<T> &f)
{
return Proxy_Function(new dispatch::Proxy_Function_Impl<T>(f));
}
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
/// \param[in] t Function / member to expose
///
@ -76,10 +104,11 @@ namespace chaiscript {
/// chai.add(fun(&MyClass::memberdata), "memberdata");
/// \endcode
///
/// \sa \ref adding_functions
/// \sa \ref addingfunctions
template<typename T>
Proxy_Function fun(T &&t) {
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t));
Proxy_Function fun(T t)
{
return dispatch::detail::Fun_Helper<std::is_member_object_pointer<T>::value>::go(t);
}
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
@ -99,12 +128,41 @@ namespace chaiscript {
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
/// \endcode
///
/// \sa \ref adding_functions
/// \sa \ref addingfunctions
template<typename T, typename Q>
Proxy_Function fun(T &&t, const Q &q) {
return fun(detail::bind_first(std::forward<T>(t), q));
Proxy_Function fun(T t, const Q &q)
{
return fun(detail::bind_first(t, q));
}
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it
/// \param[in] t Function / member to expose
/// \param[in] q Value to bind to first parameter
/// \param[in] r Value to bind to second parameter
///
/// \b Example:
/// \code
/// struct MyClass
/// {
/// void memberfunction(int);
/// };
///
/// MyClass obj;
/// chaiscript::ChaiScript chai;
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
/// // memberfunction() will be equivalent to obj.memberfunction(1)
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
/// \endcode
///
/// \sa \ref addingfunctions
template<typename T, typename Q, typename R>
Proxy_Function fun(T t, const Q &q, const R &r)
{
return fun(detail::bind_first(detail::bind_first(t, q), r));
}
}
} // namespace chaiscript
#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

View File

@ -1,539 +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
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <algorithm>
#include <atomic>
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "../utility/static_string.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript {
namespace exception {
/// \brief Error thrown when there's a problem with type conversion
class conversion_error : public bad_boxed_cast {
public:
conversion_error(const Type_Info t_to, const Type_Info t_from, const utility::Static_String what) noexcept
: bad_boxed_cast(t_from, (*t_to.bare_type_info()), what)
, type_to(t_to) {
}
Type_Info type_to;
};
class bad_boxed_dynamic_cast : public bad_boxed_cast {
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept
: bad_boxed_cast(t_from, t_to, t_what) {
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: bad_boxed_cast(t_from, t_to) {
}
explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept
: bad_boxed_cast(w) {
}
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
~bad_boxed_dynamic_cast() noexcept override = default;
};
class bad_boxed_type_cast : public bad_boxed_cast {
public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept
: bad_boxed_cast(t_from, t_to, t_what) {
}
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: bad_boxed_cast(t_from, t_to) {
}
explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept
: bad_boxed_cast(w) {
}
bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
~bad_boxed_type_cast() noexcept override = default;
};
} // namespace exception
namespace detail {
class Type_Conversion_Base {
public:
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
const Type_Info &to() const noexcept { return m_to; }
const Type_Info &from() const noexcept { return m_from; }
virtual bool bidir() const noexcept { return true; }
virtual ~Type_Conversion_Base() = default;
protected:
Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
: m_to(std::move(t_to))
, m_from(std::move(t_from)) {
}
private:
const Type_Info m_to;
const Type_Info m_from;
};
template<typename From, typename To>
class Static_Caster {
public:
static Boxed_Value cast(const Boxed_Value &t_from) {
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) {
if (t_from.is_pointer()) {
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const()) {
return Boxed_Value([&]() {
if (auto data
= std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from, nullptr))) {
return data;
} else {
throw std::bad_cast();
}
}());
} else {
return Boxed_Value([&]() {
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr))) {
return data;
} else {
throw std::bad_cast();
}
}());
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const()) {
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = static_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = static_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename From, typename To>
class Dynamic_Caster {
public:
static Boxed_Value cast(const Boxed_Value &t_from) {
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) {
if (t_from.is_pointer()) {
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const()) {
return Boxed_Value([&]() {
if (auto data
= std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from, nullptr))) {
return data;
} else {
throw std::bad_cast();
}
}());
} else {
return Boxed_Value([&]() {
if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr))) {
return data;
} else {
#ifdef CHAISCRIPT_LIBCPP
/// \todo fix this someday after libc++ is fixed.
if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) {
auto from = detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr);
if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) {
return std::static_pointer_cast<To>(from);
}
}
#endif
throw std::bad_cast();
}
}());
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const()) {
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Type_Conversion_Base {
public:
Dynamic_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) {
}
Boxed_Value convert_down(const Boxed_Value &t_base) const override { return Dynamic_Caster<Base, Derived>::cast(t_base); }
Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster<Derived, Base>::cast(t_derived); }
};
template<typename Base, typename Derived>
class Static_Conversion_Impl : public Type_Conversion_Base {
public:
Static_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) {
}
Boxed_Value convert_down(const Boxed_Value &t_base) const override {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(),
typeid(Derived),
"Unable to cast down inheritance hierarchy with non-polymorphic types");
}
bool bidir() const noexcept override { return false; }
Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster<Derived, Base>::cast(t_derived); }
};
template<typename Callable>
class Type_Conversion_Impl : public Type_Conversion_Base {
public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(t_to, t_from)
, m_func(std::move(t_func)) {
}
Boxed_Value convert_down(const Boxed_Value &) const override {
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
}
Boxed_Value convert(const Boxed_Value &t_from) const override {
/// \todo better handling of errors from the conversion function
return m_func(t_from);
}
bool bidir() const noexcept override { return false; }
private:
Callable m_func;
};
} // namespace detail
class Type_Conversions {
public:
struct Conversion_Saves {
bool enabled = false;
std::vector<Boxed_Value> saves;
};
struct Less_Than {
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const noexcept {
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
}
};
Type_Conversions()
: m_mutex()
, m_conversions()
, m_convertableTypes()
, m_num_types(0) {
}
Type_Conversions(const Type_Conversions &t_other) = delete;
Type_Conversions(Type_Conversions &&) = delete;
Type_Conversions &operator=(const Type_Conversions &) = delete;
Type_Conversions &operator=(Type_Conversions &&) = delete;
const std::set<const std::type_info *, Less_Than> &thread_cache() const {
auto &cache = *m_thread_cache;
if (cache.size() != m_num_types) {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
cache = m_convertableTypes;
}
return cache;
}
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) {
throw exception::conversion_error(conversion->to(), conversion->from(), "Trying to re-insert an existing conversion!");
}
m_conversions.insert(conversion);
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
m_num_types = m_convertableTypes.size();
}
template<typename T>
bool convertable_type() const noexcept {
const auto type = user_type<T>().bare_type_info();
return thread_cache().count(type) != 0;
}
template<typename To, typename From>
bool converts() const noexcept {
return converts(user_type<To>(), user_type<From>());
}
bool converts(const Type_Info &to, const Type_Info &from) const noexcept {
const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) {
return has_conversion(to, from);
} else {
return false;
}
}
template<typename To>
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const {
return boxed_type_conversion(user_type<To>(), t_saves, from);
}
template<typename From>
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const {
return boxed_type_down_conversion(user_type<From>(), t_saves, to);
}
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const {
try {
Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
if (t_saves.enabled) {
t_saves.saves.push_back(ret);
}
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation");
}
}
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const {
try {
Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
if (t_saves.enabled) {
t_saves.saves.push_back(ret);
}
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation");
}
}
static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) { t_saves.enabled = t_val; }
std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves) {
std::vector<Boxed_Value> ret;
std::swap(ret, t_saves.saves);
return ret;
}
bool has_conversion(const Type_Info &to, const Type_Info &from) const {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find_bidir(to, from) != m_conversions.end();
}
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto itr = find(to, from);
if (itr != m_conversions.end()) {
return *itr;
} else {
throw std::out_of_range(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name());
}
}
Conversion_Saves &conversion_saves() const noexcept { return *m_conversion_saves; }
private:
std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find_bidir(const Type_Info &to, const Type_Info &from) const {
return std::find_if(m_conversions.begin(),
m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool {
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
});
}
std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find(const Type_Info &to, const Type_Info &from) const {
return std::find_if(m_conversions.begin(),
m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
});
}
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
std::set<const std::type_info *, Less_Than> m_convertableTypes;
std::atomic_size_t m_num_types;
mutable chaiscript::detail::threading::Thread_Storage<std::set<const std::type_info *, Less_Than>> m_thread_cache;
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
};
class Type_Conversions_State {
public:
Type_Conversions_State(const Type_Conversions &t_conversions, Type_Conversions::Conversion_Saves &t_saves)
: m_conversions(t_conversions)
, m_saves(t_saves) {
}
const Type_Conversions *operator->() const noexcept { return &m_conversions.get(); }
const Type_Conversions *get() const noexcept { return &m_conversions.get(); }
Type_Conversions::Conversion_Saves &saves() const noexcept { return m_saves; }
private:
std::reference_wrapper<const Type_Conversions> m_conversions;
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
};
using Type_Conversion = std::shared_ptr<chaiscript::detail::Type_Conversion_Base>;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new to class registration for applying to a module or to the ChaiScript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::to_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
Type_Conversion base_class() {
// Can only be used with related polymorphic types
// may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base, Derived>::value, "Classes are not related by inheritance");
if constexpr (std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value) {
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
} else {
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
}
}
template<typename Callable>
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, const Callable &t_func) {
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
}
template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function) {
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
user_type<To>(),
func);
}
template<typename From, typename To>
Type_Conversion type_conversion() {
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr)));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
user_type<To>(),
func);
}
template<typename To>
Type_Conversion vector_conversion() {
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
To vec;
vec.reserve(from_vec.size());
for (const Boxed_Value &bv : from_vec) {
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
}
return Boxed_Value(std::move(vec));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(),
user_type<To>(),
func);
}
template<typename To>
Type_Conversion map_conversion() {
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::map<std::string, Boxed_Value> &from_map
= detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
To map;
for (const std::pair<const std::string, Boxed_Value> &p : from_map) {
map.insert(std::make_pair(p.first, detail::Cast_Helper<typename To::mapped_type>::cast(p.second, nullptr)));
}
return Boxed_Value(std::move(map));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(
user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
}
} // namespace chaiscript
#endif

View File

@ -1,182 +1,225 @@
// 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)
// and 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_TYPE_INFO_HPP_
#define CHAISCRIPT_TYPE_INFO_HPP_
#include <memory>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <memory>
#include <type_traits>
namespace chaiscript {
namespace detail {
namespace chaiscript
{
namespace detail
{
template<typename T>
struct Bare_Type {
using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type;
struct Bare_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
class Type_Info {
class Type_Info
{
public:
constexpr Type_Info(const bool t_is_const,
const bool t_is_reference,
const bool t_is_pointer,
const bool t_is_void,
const bool t_is_arithmetic,
const std::type_info *t_ti,
const std::type_info *t_bare_ti) noexcept
: m_type_info(t_ti)
, m_bare_type_info(t_bare_ti)
, 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)) {
Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bareti)
: m_type_info(t_ti), m_bare_type_info(t_bareti),
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
m_is_undef(false)
{
}
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;
Type_Info()
: m_type_info(0), m_bare_type_info(0),
m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_is_arithmetic(false),
m_is_undef(true)
{
}
constexpr bool operator==(const 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;
Type_Info(const Type_Info &ti)
: m_type_info(ti.m_type_info),
m_bare_type_info(ti.m_bare_type_info),
m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
m_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_is_arithmetic(ti.m_is_arithmetic),
m_is_undef(ti.m_is_undef)
{
}
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept { return !is_undef() && (*m_bare_type_info) == ti; }
Type_Info &operator=(const Type_Info &ti)
{
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_const = ti.m_is_const;
m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_is_arithmetic = ti.m_is_arithmetic;
m_is_undef = ti.m_is_undef;
return *this;
}
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; }
bool operator<(const Type_Info &ti) const
{
return m_type_info < ti.m_type_info;
}
const char *name() const noexcept {
if (!is_undef()) {
bool operator==(const Type_Info &ti) const
{
return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
}
bool operator==(const std::type_info &ti) const
{
return m_type_info != 0 && (*m_type_info) == ti;
}
bool bare_equal(const Type_Info &ti) const
{
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);
}
bool bare_equal_type_info(const std::type_info &ti) const
{
return m_bare_type_info != 0
&& (*m_bare_type_info) == ti;
}
bool is_const() const { return m_is_const; }
bool is_reference() const { return m_is_reference; }
bool is_void() const { return m_is_void; }
bool is_arithmetic() const { return m_is_arithmetic; }
bool is_undef() const { return m_is_undef || m_bare_type_info == 0; }
bool is_pointer() const { return m_is_pointer; }
std::string name() const
{
if (m_type_info)
{
return m_type_info->name();
} else {
return "";
}
}
const char *bare_name() const noexcept {
if (!is_undef()) {
std::string bare_name() const
{
if (m_bare_type_info)
{
return m_bare_type_info->name();
} else {
return "";
}
}
constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; }
private:
struct Unknown_Type {
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
bool m_is_const;
bool m_is_reference;
bool m_is_pointer;
bool m_is_void;
bool m_is_arithmetic;
bool m_is_undef;
};
const std::type_info *m_type_info = &typeid(Unknown_Type);
const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
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;
unsigned int m_flags = (1 << is_undef_flag);
};
namespace detail {
/// Helper used to create a Type_Info object
namespace detail
{
/**
* Helper used to create a Type_Info object
*/
template<typename T>
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,
std::is_reference<T>::value,
std::is_pointer<T>::value,
struct Get_Type_Info
{
typedef T type;
constexpr static Type_Info get()
{
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
&typeid(T),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::shared_ptr<T>> {
constexpr static Type_Info get() noexcept {
return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
std::is_pointer<T>::value,
struct Get_Type_Info<std::shared_ptr<T> >
{
typedef T type;
constexpr 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,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
&typeid(std::shared_ptr<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>> {
};
struct Get_Type_Info<const std::shared_ptr<T> &>
{
typedef T type;
template<typename T>
struct Get_Type_Info<const std::shared_ptr<T> &> {
constexpr static Type_Info get() noexcept {
return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
std::is_pointer<T>::value,
constexpr 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,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
&typeid(const std::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::reference_wrapper<T>> {
constexpr static Type_Info get() noexcept {
return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
std::is_pointer<T>::value,
struct Get_Type_Info<std::reference_wrapper<T> >
{
typedef T type;
constexpr 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,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
&typeid(std::reference_wrapper<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &> {
constexpr static Type_Info get() noexcept {
return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
std::is_pointer<T>::value,
struct Get_Type_Info<const std::reference_wrapper<T> &>
{
typedef T type;
constexpr 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,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
} // namespace detail
template<typename T>
struct Stripped_Type
{
typedef typename Bare_Type<typename detail::Get_Type_Info<T>::type>::type type;
};
}
/// \brief Creates a Type_Info object representing the type passed in
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
@ -188,10 +231,12 @@ namespace chaiscript {
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
/// \endcode
template<typename T>
constexpr Type_Info user_type(const T & /*t*/) noexcept {
constexpr Type_Info user_type(const T &/*t*/)
{
return detail::Get_Type_Info<T>::get();
}
/// \brief Creates a Type_Info object representing the templated type
/// \tparam T Type of object to get a Type_Info for
/// \return Type_Info for T
@ -201,10 +246,12 @@ namespace chaiscript {
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
/// \endcode
template<typename T>
constexpr Type_Info user_type() noexcept {
constexpr Type_Info user_type()
{
return detail::Get_Type_Info<T>::get();
}
} // namespace chaiscript
}
#endif

View File

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

View File

@ -1,404 +1,174 @@
// 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)
// and 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_COMMON_HPP_
#define CHAISCRIPT_COMMON_HPP_
#include <algorithm>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "../chaiscript_defines.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp"
#include <unordered_set>
namespace chaiscript {
struct AST_Node;
struct AST_Node_Trace;
namespace exception {
struct eval_error;
}
} // 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));
}
}
};
namespace chaiscript
{
/// 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
enum class AST_Node_Type {
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
class AST_Node_Type {
public:
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond
};
};
enum class Operator_Precedence {
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
*/
const char *ast_node_type_to_string(int ast_node_type) {
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "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"};
namespace {
/// 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 {
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"};
return ast_node_types[static_cast<int>(ast_node_type)];
return ast_node_types[ast_node_type];
}
}
} // namespace
/// \brief Convenience type for file positions
struct File_Position {
int line = 0;
int column = 0;
int line;
int column;
constexpr File_Position(int t_file_line, int t_file_column) noexcept
: line(t_file_line)
, column(t_file_column) {
}
File_Position(int t_file_line, int t_file_column)
: line(t_file_line), column(t_file_column) { }
constexpr File_Position() noexcept = default;
};
struct Parse_Location {
Parse_Location(std::string t_fname = "", const int t_start_line = 0, const int t_start_col = 0, const int t_end_line = 0, const int t_end_col = 0)
: start(t_start_line, t_start_col)
, end(t_end_line, t_end_col)
, filename(std::make_shared<std::string>(std::move(t_fname))) {
}
Parse_Location(std::shared_ptr<std::string> t_fname,
const int t_start_line = 0,
const int t_start_col = 0,
const int t_end_line = 0,
const int t_end_col = 0)
: start(t_start_line, t_start_col)
, end(t_end_line, t_end_col)
, filename(std::move(t_fname)) {
}
File_Position start;
File_Position end;
std::shared_ptr<std::string> filename;
};
/// \brief 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)) {
}
File_Position() : line(0), column(0) { }
};
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
using AST_NodePtr = std::unique_ptr<AST_Node>;
using AST_NodePtr_Const = std::unique_ptr<const AST_Node>;
typedef std::shared_ptr<struct AST_Node> AST_NodePtr;
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.
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
struct eval_error : std::runtime_error {
namespace exception
{
/**
* Errors generated during parsing or evaluation
*/
struct eval_error : public std::runtime_error {
std::string reason;
File_Position start_position;
File_Position end_position;
std::string filename;
std::string detail;
std::vector<AST_Node_Trace> call_stack;
std::vector<AST_NodePtr> call_stack;
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
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), end_position(t_where), filename(t_fname), 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,
const std::vector<Boxed_Value> &t_parameters,
const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
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)) {
}
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
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))
{}
eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters,
const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept
: 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)) {
}
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) {
}
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), end_position(t_where), filename(t_fname)
{}
explicit eval_error(const std::string &t_why) noexcept
: std::runtime_error("Error: \"" + t_why + "\" ")
, reason(t_why) {
}
eval_error(const std::string &t_why) noexcept
: std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why)
{}
eval_error(const eval_error &) = default;
std::string pretty_print() const {
std::string pretty_print() const
{
std::ostringstream ss;
ss << what();
if (!call_stack.empty()) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
ss << '\n'
<< detail << '\n';
if (call_stack.size() > 0) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")" << std::endl;
ss << std::endl << detail << std::endl;
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
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) {
ss << '\n';
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{
ss << std::endl;
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
}
}
}
ss << '\n';
ss << std::endl;
return ss.str();
}
~eval_error() noexcept override = default;
virtual ~eval_error() noexcept {}
private:
template<typename T>
static AST_Node_Type id(const T &t) noexcept {
return t.identifier;
static int id(const T& t)
{
return t->identifier;
}
template<typename T>
static std::string pretty(const T &t) {
return t.pretty_print();
static std::string pretty(const T& t)
{
return t->pretty_print();
}
template<typename T>
static const std::string &fname(const T &t) noexcept {
return t.filename();
static std::string fname(const T& t)
{
return *t->filename;
}
template<typename T>
static std::string startpos(const T &t) {
static std::string startpos(const T& t)
{
std::ostringstream oss;
oss << t.start().line << ", " << t.start().column;
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, const chaiscript::detail::Dispatch_Engine &t_ss) {
assert(t_func);
static std::string format_types(const Const_Proxy_Function &t_func,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
int arity = t_func->get_arity();
std::vector<Type_Info> types = t_func->get_param_types();
std::string retval;
if (arity == -1) {
if (arity == -1)
{
retval = "(...)";
if (t_dot_notation) {
if (t_dot_notation)
{
retval = "(Object)." + retval;
}
} else if (types.size() <= 1) {
@ -409,13 +179,18 @@ namespace chaiscript {
std::string paramstr;
for (size_t index = 1; index != types.size(); ++index) {
for (size_t index = 1;
index != types.size();
++index)
{
paramstr += (types[index].is_const()?"const ":"");
paramstr += t_ss.get_type_name(types[index]);
if (index == 1 && t_dot_notation) {
if (index == 1 && t_dot_notation)
{
paramstr += ").(";
if (types.size() == 2) {
if (types.size() == 2)
{
paramstr += ", ";
}
} else {
@ -429,15 +204,20 @@ namespace chaiscript {
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()) {
if (dynfun)
{
Proxy_Function f = dynfun->get_guard();
if (f) {
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
if (dynfunguard && dynfunguard->has_parse_tree()) {
if (f)
{
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfunguard
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
if (dynfunguard)
{
retval += " : " + format_guard(dynfunguard->get_parse_tree());
}
}
@ -449,50 +229,68 @@ namespace chaiscript {
}
template<typename T>
static std::string format_guard(const T &t) {
return t.pretty_print();
static std::string format_guard(const T &t)
{
return t->pretty_print();
}
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 << ")";
oss << "(" << *t->filename << " " << t->start.line << ", " << t->start.column << ")";
return oss.str();
}
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) {
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
if (t_functions.size() == 1) {
assert(t_functions[0]);
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
if (t_functions.size() == 1)
{
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl;
} else {
ss << " " << t_functions.size() << " overloads available:\n";
ss << " " << t_functions.size() << " overloads available:" << std::endl;
for (const auto &t_function : t_functions) {
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
for (std::vector<chaiscript::Const_Proxy_Function>::const_iterator itr = t_functions.begin();
itr != t_functions.end();
++itr)
{
ss << " " << format_types((*itr), t_dot_notation, t_ss) << std::endl;
}
}
return ss.str();
}
static std::string
format_parameters(const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) {
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << "(";
if (!t_parameters.empty()) {
if (!t_parameters.empty())
{
std::string paramstr;
for (auto itr = t_parameters.begin(); itr != t_parameters.end(); ++itr) {
for (std::vector<Boxed_Value>::const_iterator itr = t_parameters.begin();
itr != t_parameters.end();
++itr)
{
paramstr += (itr->is_const()?"const ":"");
paramstr += t_ss.type_name(*itr);
if (itr == t_parameters.begin() && t_dot_notation) {
if (itr == t_parameters.begin() && t_dot_notation)
{
paramstr += ").(";
if (t_parameters.size() == 1) {
if (t_parameters.size() == 1)
{
paramstr += ", ";
}
} else {
@ -507,10 +305,12 @@ namespace chaiscript {
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;
if (t_fname != "__EVAL__") {
if (t_fname != "__EVAL__")
{
ss << "in '" << t_fname << "' ";
} else {
ss << "during evaluation ";
@ -519,18 +319,16 @@ namespace chaiscript {
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;
ss << "at (" << t_where.line << ", " << t_where.column << ")";
return ss.str();
}
static std::string format(const std::string &t_why,
const File_Position &t_where,
const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) {
static std::string format(const std::string &t_why, const File_Position &t_where, 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;
ss << format_why(t_why);
@ -550,7 +348,8 @@ namespace chaiscript {
static std::string format(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) {
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << format_why(t_why);
@ -562,7 +361,8 @@ namespace chaiscript {
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;
ss << format_why(t_why);
@ -577,125 +377,199 @@ namespace chaiscript {
}
};
/// Errors generated when loading a file
struct file_not_found_error : std::runtime_error {
explicit file_not_found_error(const std::string &t_filename)
/**
* Errors generated when loading a file
*/
struct file_not_found_error : public std::runtime_error {
file_not_found_error(const std::string &t_filename) noexcept
: 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() noexcept override = default;
std::string filename;
virtual ~file_not_found_error() noexcept {}
};
} // 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:
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
virtual void debug_print(const AST_Node &t, std::string prepend = "") const = 0;
virtual void *get_tracer_ptr() = 0;
virtual ~ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
const std::string text;
const int identifier; //< \todo shouldn't this be a strongly typed enum value?
std::shared_ptr<const std::string> filename;
File_Position start, end;
std::vector<AST_NodePtr> children;
AST_NodePtr annotation;
template<typename T>
T &get_tracer() noexcept {
// to do type check this somehow?
return *static_cast<T *>(get_tracer_ptr());
virtual std::string pretty_print() const
{
std::ostringstream oss;
oss << text;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->pretty_print();
}
return oss.str();
}
/**
* Prints the contents of an AST node, including its children, recursively
*/
std::string to_string(std::string t_prepend = "") {
std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->to_string(t_prepend + " ");
}
return oss.str();
}
std::string internal_to_string() {
return to_string();
}
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e)
{
try {
return eval_internal(t_e);
} catch (exception::eval_error &ee) {
ee.call_stack.push_back(shared_from_this());
throw ee;
}
}
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);
}
protected:
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
};
} // namespace parser
AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname,
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
text(t_ast_node_text), identifier(t_id), filename(t_fname),
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
{
}
namespace eval {
namespace detail {
/// Special type for returned values
AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname) :
text(t_ast_node_text), identifier(t_id), filename(t_fname) {}
virtual ~AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &)
{
throw std::runtime_error("Undispatched ast_node (internal error)");
}
private:
// Copy and assignment explicitly unimplemented
AST_Node(const AST_Node &);
AST_Node& operator=(const AST_Node &);
};
namespace eval
{
namespace detail
{
/**
* Special type for returned values
*/
struct Return_Value {
Boxed_Value retval;
Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { }
};
/// Special type indicating a call to 'break'
/**
* Special type indicating a call to 'break'
*/
struct Break_Loop {
};
/// Special type indicating a call to 'continue'
struct Continue_Loop {
Break_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)
: m_ds(t_ds) {
m_ds->new_scope(m_ds.stack_holder());
struct Scope_Push_Pop
{
Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de)
{
m_de.new_scope();
}
~Scope_Push_Pop()
{
m_de.pop_scope();
}
~Scope_Push_Pop() { m_ds->pop_scope(m_ds.stack_holder()); }
private:
const chaiscript::detail::Dispatch_State &m_ds;
// explicitly unimplemented copy and assignment
Scope_Push_Pop(const Scope_Push_Pop &);
Scope_Push_Pop& operator=(const Scope_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de;
};
/// Creates a new function call and pops it on destruction
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 &operator=(const Function_Push_Pop &) = delete;
explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) {
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
/// Creates a new functon call and pops it on destruction
struct Function_Push_Pop
{
Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de)
{
m_de.new_function_call();
}
~Function_Push_Pop() { m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); }
~Function_Push_Pop()
{
m_de.pop_function_call();
}
void save_params(const std::vector<Boxed_Value> &t_params)
{
m_de.save_function_params(t_params);
}
void save_params(const Function_Params &t_params) { m_ds->save_function_params(t_params); }
private:
const chaiscript::detail::Dispatch_State &m_ds;
// explicitly unimplemented copy and assignment
Function_Push_Pop(const Function_Push_Pop &);
Function_Push_Pop& operator=(const Function_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de;
};
/// Creates a new scope then pops it on destruction
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 &operator=(const Stack_Push_Pop &) = delete;
explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) {
m_ds->new_stack(m_ds.stack_holder());
struct Stack_Push_Pop
{
Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de)
{
m_de.new_stack();
}
~Stack_Push_Pop()
{
m_de.pop_stack();
}
~Stack_Push_Pop() { m_ds->pop_stack(m_ds.stack_holder()); }
private:
const chaiscript::detail::Dispatch_State &m_ds;
// explicitly unimplemented copy and assignment
Stack_Push_Pop(const Stack_Push_Pop &);
Stack_Push_Pop& operator=(const Stack_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de;
};
} // namespace detail
} // namespace eval
} // namespace chaiscript
}
}
}
#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,530 @@
// 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 {
constexpr static const char *chaiscript_prelude=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(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
{
eval(type_name(x))(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(", ") + "]";
}
# Basic to_string function
def to_string(x) {
internal_to_string(x);
}
# 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
}
}
# Pushes the second value onto the container first value while making a clone of the value
def push_back(container, x) : call_exists(push_back_ref, container, x)
{
container.push_back_ref(clone(x))
}
# Pushes the second value onto the front of the container first value while making a clone of the value
def push_front(container, x) : call_exists(push_front_ref, container, x)
{
container.push_front_ref(clone(x))
}
# 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;
}
# 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)
{
return 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();
}
return false;
}
def contains(container, item) {
return 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(substr) : is_type(substr, "string") {
int(find(this, substr, 0));
}
# Returns the position of last match of the second value string in the first value string
def string::rfind(substr) : is_type(substr, "string") {
int(rfind(this, substr, -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(list) : is_type(list, "string") {
int(find_first_of(this, list, 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(list) : is_type(list, "string") {
int(find_last_of(this, list, -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(list) : is_type(list, "string") {
int(find_first_not_of(this, list, 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(list) : is_type(list, "string") {
int(find_last_not_of(this, list, -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, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") {
auto range = range(container);
while (!range.empty()) {
if (compare_func(range.front(), value)) {
return range;
} else {
range.pop_front();
}
}
return range;
}
def find(container, value) {
return 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_ */

View File

@ -2,8 +2,10 @@
/// regarding the ChaiScript standard runtime library.
/// \brief Items in this namespace exist in the ChaiScript language runtime. They are not part of the C++ API
namespace ChaiScript_Language {
/// \page LangStandardLibraryRef ChaiScript Language Standard Library Reference
namespace ChaiScript_Language
{
/// \page LangStandardLibraryRef ChaiScript Language Standard Libary Reference
///
/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly
/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available
@ -11,13 +13,15 @@ namespace ChaiScript_Language {
/// (the general category of Range cs and their iteration).
///
/// \brief Generic concept of a value in ChaiScript.
///
/// The Object type exists merely as a concept. All objects in ChaiScript support this concept
/// and have the following methods available to them. All objects are stored internally as chaiscript::Boxed_Value types.
///
/// \sa chaiscript::Boxed_Value
class Object {
class Object
{
public:
/// \brief Returns the Type_Info value for this Object
Type_Info get_type_info() const;
@ -50,7 +54,8 @@ namespace ChaiScript_Language {
};
/// \brief Item returned from a Range object from a Map
class Map_Pair {
class Map_Pair
{
public:
/// \brief Returns the key of the Map entry
const string first();
@ -59,6 +64,7 @@ namespace ChaiScript_Language {
Object second();
};
/// \brief Maps strings to Objects
///
/// ChaiScript has a built in shortcut for generating Map objects:
@ -79,7 +85,8 @@ namespace ChaiScript_Language {
///
/// \sa Map_Pair
/// \sa chaiscript::bootstrap::standard_library::map_type
class Map {
class Map
{
public:
/// \brief Returns an object that implements the Range concept for the Map_Pair's in this Map
Range range();
@ -101,16 +108,20 @@ namespace ChaiScript_Language {
/// \brief Returns true if the map contains no items
bool empty() const;
};
/// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable
class Container {
/// \brief A concept implemented by string, Vector and Map. It is convertable to Range, default constructable and back_insertable
class Container
{
public:
void push_back(Object);
Range range();
Const_Range range() const;
};
/// \brief Converts o into a string.
///
/// \code
@ -119,6 +130,7 @@ namespace ChaiScript_Language {
/// \endcode
string to_string(Object o);
/// \brief Prints o to the terminal, without a trailing carriage return. Applies conversions to string automatically.
/// \code
/// eval> puts("hi, "); puts("there")
@ -128,6 +140,7 @@ namespace ChaiScript_Language {
/// \sa print
void puts(Object o);
/// \brief Prints o to the terminal, with a trailing carriage return. Applies conversions to string automatically
/// \code
/// eval> print("hello")
@ -140,10 +153,10 @@ namespace ChaiScript_Language {
/// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript.
///
/// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string
/// Because the ChaiScript string object is an std::string, it is directly convertable to and from std::string
/// using the chaiscript::boxed_cast and chaiscript::var functions.
///
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct passthroughs to the
/// std::string of the same name.
///
/// \note Object and function notations are equivalent in ChaiScript. This means that
@ -151,7 +164,8 @@ namespace ChaiScript_Language {
/// second formation of the function calls.
/// \sa \ref keyworddef for extending existing C++ classes in ChaiScript
/// \sa chaiscript::bootstrap::standard_library::string_type
class string {
class string
{
public:
/// \brief Finds the first instance of substr.
/// \code
@ -160,6 +174,7 @@ namespace ChaiScript_Language {
/// \endcode
int find(string s) const;
/// \brief Finds the last instance of substr.
/// \code
/// eval> rfind("abab", "ab")
@ -274,7 +289,8 @@ namespace ChaiScript_Language {
/// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range
///
/// \sa Const_Range
class Range {
class Range
{
public:
/// \brief Returns the last item of the range
Object back();
@ -293,8 +309,9 @@ namespace ChaiScript_Language {
/// \brief Moves the front pointer forward one
///
/// \post front() returns the element at front() + 1;
/// \post front() returne the element at front() + 1;
void pop_front();
};
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
@ -303,7 +320,8 @@ namespace ChaiScript_Language {
/// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range
///
/// \sa Range
class Const_Range {
class Const_Range
{
public:
/// \brief Returns the last item of the range
const Object back();
@ -322,8 +340,9 @@ namespace ChaiScript_Language {
/// \brief Moves the front pointer forward one
///
/// \post front() returns the element at front() + 1;
/// \post front() returne the element at front() + 1;
void pop_front();
};
/// \brief A vector of Objects
@ -343,7 +362,8 @@ namespace ChaiScript_Language {
/// Implemented with std::vector<chaiscript::Boxed_Value>
///
/// \sa chaiscript::bootstrap::standard_library::vector_type
class Vector {
class Vector
{
public:
/// \brief returns the Object at the given index. Throws an exception if the index does not exist
Object operator[](int t_index);
@ -397,9 +417,11 @@ namespace ChaiScript_Language {
/// \brief Returns the number of elements in the Vector
int size() const;
};
class Type_Info {
class Type_Info
{
public:
/// \brief Compares this Type_Info object with another one and returns true if the two types are the same
/// after const, pointer, reference are removed.
@ -428,8 +450,10 @@ namespace ChaiScript_Language {
/// \brief Returns the ChaiScript registered name for the type if one exists.
string name() const;
};
/// \brief Represents a function object in ChaiScript
///
/// A function object may be one function, such as:
@ -450,7 +474,8 @@ namespace ChaiScript_Language {
/// \endcode
///
/// Examples in the function definitions below will reference these examples
class Function {
class Function
{
public:
/// \brief Returns the annotation description of the function
string get_annotation() const;
@ -480,7 +505,7 @@ namespace ChaiScript_Language {
/// \endcode
Vector get_contained_functions() const;
/// \brief Returns a function guard as function
/// \brief Returns a vector of the contained functions
///
/// Example:
/// \code
@ -494,7 +519,7 @@ namespace ChaiScript_Language {
/// \brief Returns a vector of Type_Info objects that represent the param types for this function.
/// The first value in the list is the return type.
///
/// If this function is a conglomerate of several functions (get_contained_values().size() > 0)
/// If this function is a conglomeration of several functions (get_contained_values().size() > 0)
/// then the function returns as many Type_Info objects as it can. If the functions contained all have
/// the same arity, then it represents the arity. If they have different arities, it returns only
/// one value - the return type.
@ -509,7 +534,7 @@ namespace ChaiScript_Language {
/// \endcode
Vector get_param_types() const;
/// \brief Returns true if the function has a guard to it. Always returns false for a conglomerate function
/// \brief Returns true if the function has a guard to it. Always returns falls for a conglomerate function
bool has_guard() const;
/// \brief Calls the function with the given set of parameters and returns the value;
@ -522,6 +547,8 @@ namespace ChaiScript_Language {
Object call(Vector t_params) const;
}
/// \brief Returns the max of a or b. Requires that operator>(a, b) exists
/// Equivalent to
/// \code
@ -533,8 +560,7 @@ namespace ChaiScript_Language {
/// eval> max(4, 10)
/// 10
/// \endcode
Object
max(Object a, Object b);
Object max(Object a, Object b);
/// \brief Returns the min of a or b. Requires that operator<(a, b) exists
///
@ -572,6 +598,7 @@ namespace ChaiScript_Language {
/// \endcode
bool even(Object x);
/// \brief Applies the function f over each element in the Range c.
///
/// Example:
@ -583,6 +610,7 @@ namespace ChaiScript_Language {
/// \endcode
void for_each(Range c, Function f);
/// \brief Applies f over each element in the Range c, joining all the results.
///
/// Example:
@ -592,6 +620,7 @@ namespace ChaiScript_Language {
/// \endcode
Object map(Range c, Function f);
/// \brief Starts with the initial value and applies the function f to it and the first element of the Range c.
/// The result is then applied to the second element, and so on until the elements are exhausted.
///
@ -602,6 +631,7 @@ namespace ChaiScript_Language {
/// \endcode
Object foldl(Range c, Function f, Object initial);
/// \brief Returns the sum total of the values in the Range c.
///
/// Example:
@ -616,6 +646,7 @@ namespace ChaiScript_Language {
/// \endcode
Numeric sum(Range c);
/// \brief Returns the product of the value in the Range c.
///
/// Example:
@ -630,6 +661,7 @@ namespace ChaiScript_Language {
/// \endcode
Numeric product(Range c);
/// \brief Takes num elements from the Range c, returning them.
///
/// Example:
@ -641,6 +673,7 @@ namespace ChaiScript_Language {
/// \returns A container of the same type that was passed in
Object take(Range c, int num);
/// \brief Takes elements from the Range c that match function f, stopping at the first non-match, returning them as a new Vector.
///
/// Example:
@ -652,6 +685,7 @@ namespace ChaiScript_Language {
/// \returns A container of the same type that was passed in
Object take_while(Range c, Function f);
/// \brief Drops num elements from the Range c, returning the remainder.
///
/// Example:
@ -663,6 +697,7 @@ namespace ChaiScript_Language {
/// \returns A container of the same type that was passed in
Object drop(Range c, int num);
/// \brief Drops elements from the Range c that match f, stopping at the first non-match, returning the remainder.
///
/// Example:
@ -672,6 +707,7 @@ namespace ChaiScript_Language {
/// \endcode
Object drop_while(Range c, Function f);
/// \brief Similar to foldl, this takes the first two elements as its starting values for f. This assumes Range c has at least 2 elements.
///
/// Example:
@ -681,14 +717,16 @@ namespace ChaiScript_Language {
/// \endcode
Object reduce(Range c, Function f);
/// \brief Takes elements from Container c that match function f, return them.
/// \brief Takes elements from Range c that match function f, return them.
///
/// Example:
/// \code
/// eval> filter([1, 2, 3, 4], odd)
/// [1, 3]
/// \endcode
Object filter(Container c, Function f);
Object filter(Range c, Function f);
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
///
@ -699,6 +737,7 @@ namespace ChaiScript_Language {
/// \endcode
string join(Range c, string delim);
/// \brief Returns the contents of the Container c in reversed order.
///
/// Example:
@ -708,6 +747,7 @@ namespace ChaiScript_Language {
/// \endcode
Container reverse(Container c);
/// \brief Generates a new Vector filled with values starting at x and ending with y.
///
/// Works on types supporting operator<=(x, y) and operator++(x)
@ -719,6 +759,7 @@ namespace ChaiScript_Language {
/// \endcode
Vector generate_range(Object x, Object y);
/// \brief Returns a new Range with x and y concatenated.
///
/// Example:
@ -728,6 +769,7 @@ namespace ChaiScript_Language {
/// \endcode
Object concat(Range x, Range y);
/// \brief Returns a new Vector with x and y as its values.
///
/// Example:
@ -737,6 +779,7 @@ namespace ChaiScript_Language {
/// \endcode
Vector collate(Object x, Object y);
/// \brief Applies f to elements of x and y, returning a new Vector with the result of each application.
///
/// Example:
@ -746,6 +789,7 @@ namespace ChaiScript_Language {
/// \endcode
Vector zip_with(Function f, Range x, Range y);
/// \brief Collates elements of x and y, returning a new Vector with the result.
///
/// Example:
@ -755,6 +799,7 @@ namespace ChaiScript_Language {
/// \endcode
Vector zip(Range x, Range y);
/// \brief returns true if there exists a call to the Function f that takes the given parameters
///
/// Example:
@ -770,6 +815,7 @@ namespace ChaiScript_Language {
/// \brief Reverses a Const_Range object so that the elements are accessed in reverse
Const_Range retro(Const_Range);
/// \brief Raises the given object as an exception. Any type of object can be thrown.
///
/// Example:
@ -780,4 +826,5 @@ namespace ChaiScript_Language {
///
/// \sa \ref keywordtry
void throw(Object);
} // namespace ChaiScript_Language
}

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

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