mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2025-12-06 08:46:53 +08:00
Merge branch 'develop' into master
This commit is contained in:
commit
439c1a96d3
117
.clang-format
117
.clang-format
@ -1,98 +1,33 @@
|
||||
# clang-format: 11
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyNamespace: true
|
||||
SplitEmptyRecord: true
|
||||
BreakAfterJavaFieldAnnotations: true
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: true
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakStringLiterals: true
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveBitFields: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BasedOnStyle: WebKit
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBraces: Attach
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: true
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: true
|
||||
Cpp11BracedListStyle: true
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeCategories:
|
||||
- Priority: 2
|
||||
Regex: ^"(llvm|llvm-c|clang|clang-c)/
|
||||
- Priority: 3
|
||||
Regex: ^(<|"(gtest|gmock|isl|json)/)
|
||||
- Priority: 1
|
||||
Regex: .*
|
||||
IncludeIsMainRegex: (Test)?$
|
||||
IndentCaseLabels: false
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: true
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
Language: Cpp
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: Inner
|
||||
ObjCBlockIndentWidth: 7
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
NamespaceIndentation: All
|
||||
PenaltyBreakBeforeFirstCallParameter: 200
|
||||
PenaltyBreakComment: 5
|
||||
PenaltyBreakFirstLessLess: 50
|
||||
PenaltyExcessCharacter: 4
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SortIncludes: true
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 0
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 8
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceInEmptyBlock: false
|
||||
Standard: Latest
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
||||
|
||||
|
||||
30
.travis.yml
30
.travis.yml
@ -5,10 +5,12 @@ 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++-4.9
|
||||
- g++-5
|
||||
- g++-6
|
||||
- g++-7
|
||||
- g++-8
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "ChaiScript/ChaiScript"
|
||||
@ -22,7 +24,7 @@ matrix:
|
||||
include:
|
||||
- os: linux
|
||||
sudo: false
|
||||
env: GCC_VER="4.9"
|
||||
env: GCC_VER="7"
|
||||
compiler: gcc
|
||||
# - os: linux
|
||||
#sudo: false
|
||||
@ -30,19 +32,20 @@ matrix:
|
||||
#compiler: gcc
|
||||
- os: linux
|
||||
sudo: false
|
||||
env: GCC_VER="5" CPPCHECK=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
||||
env: GCC_VER="7" CPPCHECK=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
sudo: false
|
||||
env: GCC_VER="6" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
||||
env: GCC_VER="8" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
compiler: clang
|
||||
osx_image: xcode8
|
||||
- os: osx
|
||||
compiler: clang
|
||||
osx_image: xcode8
|
||||
env: CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
|
||||
#- 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:
|
||||
@ -52,6 +55,7 @@ env:
|
||||
|
||||
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:
|
||||
|
||||
125
CMakeLists.txt
125
CMakeLists.txt
@ -1,8 +1,11 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
|
||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# required since cmake 3.4 at least for libc++
|
||||
set(CMAKE_ENABLE_EXPORTS ON)
|
||||
|
||||
project(chaiscript)
|
||||
|
||||
@ -15,7 +18,6 @@ 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)
|
||||
option(BUILD_IN_CPP17_MODE "Build with C++17 flags" FALSE)
|
||||
|
||||
mark_as_advanced(USE_STD_MAKE_SHARED)
|
||||
|
||||
@ -49,8 +51,8 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
|
||||
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
|
||||
if(ENABLE_MEMORY_SANITIZER)
|
||||
add_definitions(-fsanitize=memory -g)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
|
||||
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)
|
||||
@ -60,27 +62,26 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
endif()
|
||||
|
||||
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
|
||||
|
||||
if (ENABLE_LTO)
|
||||
add_definitions(-flto)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
|
||||
if(ENABLE_LTO)
|
||||
check_ipo_supported()
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif()
|
||||
|
||||
option(GPROF_OUTPUT "Generate profile data" FALSE)
|
||||
if (GPROF_OUTPUT)
|
||||
if(GPROF_OUTPUT)
|
||||
add_definitions(-pg)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
|
||||
endif()
|
||||
|
||||
|
||||
option(PROFILE_GENERATE "Generate profile data" FALSE)
|
||||
if (PROFILE_GENERATE)
|
||||
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)
|
||||
if(PROFILE_USE)
|
||||
add_definitions(-fprofile-use)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
|
||||
endif()
|
||||
@ -98,8 +99,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 6)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 1)
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 7)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 0)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||
@ -125,7 +126,7 @@ if(NOT MINGW)
|
||||
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
|
||||
endif()
|
||||
|
||||
@ -143,36 +144,10 @@ else()
|
||||
set(READLINE_FLAG)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||
|
||||
if(GCC_VERSION VERSION_LESS 4.9)
|
||||
set(CPP14_FLAG "-std=c++1y")
|
||||
else()
|
||||
if (BUILD_IN_CPP17_MODE)
|
||||
set(CPP14_FLAG "-std=c++1z")
|
||||
else()
|
||||
set(CPP14_FLAG "-std=c++14")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if (BUILD_IN_CPP17_MODE)
|
||||
set(CPP14_FLAG "-std=c++1z")
|
||||
else()
|
||||
set(CPP14_FLAG "-std=c++14")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
|
||||
|
||||
if (BUILD_IN_CPP17_MODE)
|
||||
add_definitions(/std:c++17)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
if (MSVC_VERSION STREQUAL "1800")
|
||||
if(MSVC_VERSION STREQUAL "1800")
|
||||
# VS2013 doesn't have magic statics
|
||||
add_definitions(/w44640)
|
||||
else()
|
||||
@ -180,7 +155,7 @@ if(MSVC)
|
||||
add_definitions(/w34062)
|
||||
endif()
|
||||
|
||||
add_definitions(/bigobj /permissive-)
|
||||
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
|
||||
@ -190,10 +165,10 @@ if(MSVC)
|
||||
# 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 -pedantic ${CPP14_FLAG})
|
||||
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")
|
||||
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)
|
||||
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()
|
||||
@ -204,16 +179,12 @@ else()
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
option(USE_LIBCXX "Use clang's libcxx" TRUE)
|
||||
option(USE_LIBCXX "Use clang's libcxx" FALSE)
|
||||
|
||||
if(USE_LIBCXX)
|
||||
add_definitions(-stdlib=libc++)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG} -stdlib=libc++")
|
||||
else()
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}")
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
elseif(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}")
|
||||
endif()
|
||||
|
||||
# limitations in MinGW require us to make an optimized build
|
||||
@ -279,8 +250,8 @@ add_executable(chai src/main.cpp ${Chai_INCLUDES})
|
||||
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
|
||||
if(BUILD_SAMPLES)
|
||||
add_executable(example samples/example.cpp)
|
||||
target_link_libraries(example ${LIBS})
|
||||
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(memory_leak_test samples/memory_leak_test.cpp)
|
||||
@ -312,7 +283,7 @@ file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tes
|
||||
list(SORT PERFORMANCE_TESTS)
|
||||
|
||||
|
||||
if (RUN_FUZZY_TESTS)
|
||||
if(RUN_FUZZY_TESTS)
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
|
||||
|
||||
@ -341,37 +312,6 @@ endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
||||
# Add catch tests macro
|
||||
macro(ADD_CATCH_TESTS executable)
|
||||
if (MSVC)
|
||||
file(TO_NATIVE_PATH "${QT_LIBRARY_DIR}" QT_LIB_PATH)
|
||||
set(NEWPATH "${QT_LIB_PATH};$ENV{PATH}")
|
||||
else()
|
||||
set(NEWPATH $ENV{PATH})
|
||||
endif()
|
||||
|
||||
get_target_property(target_files ${executable} SOURCES)
|
||||
|
||||
foreach(source ${target_files})
|
||||
if(NOT "${source}" MATCHES "/moc_.*cxx")
|
||||
string(REGEX MATCH .*cpp source "${source}")
|
||||
if(source)
|
||||
file(READ "${source}" contents)
|
||||
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
|
||||
foreach(hit ${found_tests})
|
||||
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
|
||||
add_test(compiled.${test_name} "${executable}" ${test_name})
|
||||
set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
|
||||
|
||||
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) }")
|
||||
@ -403,7 +343,7 @@ if(BUILD_TESTING)
|
||||
list(APPEND TESTS unit.${filename})
|
||||
endforeach()
|
||||
|
||||
if (RUN_PERFORMANCE_TESTS)
|
||||
if(RUN_PERFORMANCE_TESTS)
|
||||
foreach(filename ${PERFORMANCE_TESTS})
|
||||
message(STATUS "Adding performance test ${filename}")
|
||||
|
||||
@ -460,10 +400,8 @@ 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
|
||||
@ -472,12 +410,11 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(multifile_test ${LIBS})
|
||||
add_test(NAME MultiFile_Test COMMAND multifile_test)
|
||||
|
||||
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
|
||||
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
if(BUILD_LIBFUZZ_TESTER)
|
||||
add_executable(fuzzer src/libfuzzer_client.cpp src/sha3.cpp)
|
||||
target_compile_options(fuzzer PRIVATE "-fsanitize=fuzzer,address")
|
||||
@ -485,7 +422,7 @@ if(BUILD_LIBFUZZ_TESTER)
|
||||
endif()
|
||||
|
||||
|
||||
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
|
||||
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
|
||||
|
||||
install(DIRECTORY include/chaiscript DESTINATION include
|
||||
PATTERN "*.hpp"
|
||||
@ -506,6 +443,6 @@ 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 lib/pkgconfig)
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
|
||||
|
||||
|
||||
3
LICENSE
3
LICENSE
@ -1,7 +1,6 @@
|
||||
BSD-3-Clause License
|
||||
|
||||
Copyright 2009-2016 Jason Turner
|
||||
Copyright 2009-2012 Jonathan Turner.
|
||||
Copyright 2009-2018 Jason Turner
|
||||
|
||||
All Rights Reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
version: 6.1.x.{build}
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2019
|
||||
environment:
|
||||
matrix:
|
||||
- VS_VERSION: "Visual Studio 14"
|
||||
- VS_VERSION: "Visual Studio 15"
|
||||
- VS_VERSION: "Visual Studio 16"
|
||||
build_script:
|
||||
- cmd: >-
|
||||
mkdir build
|
||||
|
||||
@ -11,20 +11,18 @@ ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme.
|
||||
# Initializing ChaiScript
|
||||
|
||||
```
|
||||
chaiscript::ChaiScript chai; // loads stdlib from loadable module on file system
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
|
||||
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");
|
||||
@ -32,7 +30,7 @@ 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");
|
||||
```
|
||||
@ -41,18 +39,18 @@ chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name"
|
||||
|
||||
#### Preferred
|
||||
|
||||
```
|
||||
```cpp
|
||||
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
|
||||
```
|
||||
|
||||
#### Alternative
|
||||
|
||||
```
|
||||
```cpp
|
||||
chai.add(chaiscript::fun(std::static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
|
||||
```
|
||||
This overload technique is also used when exposing base member using derived type
|
||||
|
||||
```
|
||||
```cpp
|
||||
struct Base
|
||||
{
|
||||
int data;
|
||||
@ -66,9 +64,9 @@ chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
|
||||
|
||||
### Lambda
|
||||
|
||||
```
|
||||
```cpp
|
||||
chai.add(
|
||||
chaiscript::fun<std::string (bool)>(
|
||||
chaiscript::fun<std::function<std::string (bool)>>(
|
||||
[](bool type) {
|
||||
if (type) { return "x"; }
|
||||
else { return "y"; }
|
||||
@ -77,7 +75,7 @@ chai.add(
|
||||
|
||||
### Constructors
|
||||
|
||||
```
|
||||
```cpp
|
||||
chai.add(chaiscript::constructor<MyType ()>(), "MyType");
|
||||
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
|
||||
```
|
||||
@ -86,7 +84,7 @@ chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
|
||||
|
||||
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
|
||||
|
||||
```
|
||||
```cpp
|
||||
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
|
||||
```
|
||||
|
||||
@ -109,27 +107,27 @@ add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s);
|
||||
|
||||
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 ChaiScritp about the relationship.
|
||||
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>());
|
||||
@ -170,7 +168,8 @@ chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overw
|
||||
|
||||
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); })); },
|
||||
@ -186,7 +185,7 @@ print(math.pi) // prints 3.14159
|
||||
# Using STL
|
||||
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
|
||||
|
||||
```
|
||||
```cpp
|
||||
typedef std::vector<std::pair<int, std::string>> data_list;
|
||||
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
|
||||
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
|
||||
@ -204,7 +203,7 @@ chai.eval(R"_(
|
||||
|
||||
## General
|
||||
|
||||
```
|
||||
```cpp
|
||||
chai.eval("print(\"Hello World\")");
|
||||
chai.eval(R"(print("Hello World"))");
|
||||
```
|
||||
@ -215,13 +214,13 @@ Returns values are of the type `Boxed_Value` which is meant to be opaque to the
|
||||
|
||||
### 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
|
||||
@ -229,7 +228,7 @@ chaiscript::boxed_cast<double>(v); // free function version, does not know about
|
||||
|
||||
### 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
|
||||
@ -259,7 +258,7 @@ int main()
|
||||
|
||||
## 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
|
||||
|
||||
@ -269,7 +268,7 @@ chai.eval("print(i)"); // prints 3
|
||||
|
||||
## Catching Eval Errors
|
||||
|
||||
```
|
||||
```cpp
|
||||
try {
|
||||
chai.eval("2.3 + \"String\"");
|
||||
} catch (const chaiscript::exception::eval_error &e) {
|
||||
@ -279,7 +278,7 @@ try {
|
||||
|
||||
## 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) {
|
||||
@ -294,19 +293,19 @@ try {
|
||||
## 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++
|
||||
```
|
||||
@ -346,7 +345,7 @@ while (some_condition()) { /* do something */ }
|
||||
|
||||
```
|
||||
// ranged for
|
||||
for (x : [1,2,3]) { print(i); }
|
||||
for (i : [1, 2, 3]) { print(i); }
|
||||
```
|
||||
|
||||
Each of the loop styles can be broken using the `break` statement. For example:
|
||||
@ -391,11 +390,23 @@ switch (myvalue) {
|
||||
|
||||
## Built in Types
|
||||
|
||||
There are a number of build-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
|
||||
|
||||
@ -566,28 +577,11 @@ If both a 2 parameter and a 3 parameter signature match, the 3 parameter functio
|
||||
* `__LINE__` Current file line number
|
||||
* `__FILE__` Full path of current file
|
||||
* `__CLASS__` Name of current class
|
||||
* `__FUNC__` Mame of current function
|
||||
* `__FUNC__` Name of current function
|
||||
|
||||
|
||||
# Built In Functions
|
||||
|
||||
## Disabling Built-Ins
|
||||
|
||||
When constructing a ChaiScript object, a vector of parameters can be passed in to disable or enable various built-in methods.
|
||||
|
||||
Current options:
|
||||
|
||||
```
|
||||
enum class Options
|
||||
{
|
||||
Load_Modules,
|
||||
No_Load_Modules,
|
||||
External_Scripts,
|
||||
No_External_Scripts
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Evaluation
|
||||
|
||||
```
|
||||
@ -603,3 +597,6 @@ Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constr
|
||||
|
||||
* `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.)
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
// 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)
|
||||
// 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_HPP_
|
||||
#define CHAISCRIPT_HPP_
|
||||
|
||||
|
||||
|
||||
/// @mainpage
|
||||
/// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
|
||||
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
|
||||
@ -22,7 +19,8 @@
|
||||
///
|
||||
/// 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
|
||||
/// [github](http://www.github.com/ChaiScript/ChaiScript").
|
||||
///
|
||||
/// ------------------------------------------------------------
|
||||
///
|
||||
@ -315,8 +313,8 @@
|
||||
/// 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 converted 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.
|
||||
///
|
||||
@ -470,7 +468,8 @@
|
||||
/// 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) {
|
||||
@ -483,8 +482,6 @@
|
||||
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
|
||||
/// @sa chaiscript::exception_specification
|
||||
|
||||
|
||||
|
||||
/// @page LangObjectSystemRef ChaiScript Language Object Model Reference
|
||||
///
|
||||
///
|
||||
@ -652,7 +649,6 @@
|
||||
/// @sa @ref LangKeywordRef
|
||||
/// @sa ChaiScript_Language for Built in Functions
|
||||
|
||||
|
||||
/// @page LangKeywordRef ChaiScript Language Keyword Reference
|
||||
///
|
||||
///
|
||||
@ -813,7 +809,6 @@
|
||||
///
|
||||
/// Synonym for @ref keywordauto
|
||||
|
||||
|
||||
/// @namespace chaiscript
|
||||
/// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
|
||||
|
||||
@ -821,25 +816,22 @@
|
||||
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
|
||||
|
||||
#include "chaiscript_basic.hpp"
|
||||
#include "language/chaiscript_parser.hpp"
|
||||
#include "chaiscript_stdlib.hpp"
|
||||
#include "language/chaiscript_parser.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class ChaiScript : public ChaiScript_Basic
|
||||
{
|
||||
namespace chaiscript {
|
||||
class ChaiScript : public ChaiScript_Basic {
|
||||
public:
|
||||
ChaiScript(std::vector<std::string> t_modulepaths = {},
|
||||
std::vector<std::string> t_usepaths = {},
|
||||
const std::vector<Options> &t_opts = chaiscript::default_options())
|
||||
: ChaiScript_Basic(
|
||||
chaiscript::Std_Lib::library(),
|
||||
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>>(),
|
||||
t_modulepaths, t_usepaths, t_opts)
|
||||
{
|
||||
std::move(t_modulepaths),
|
||||
std::move(t_usepaths),
|
||||
std::move(t_opts)) {
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif /* CHAISCRIPT_HPP_ */
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BASIC_HPP_
|
||||
@ -9,13 +9,13 @@
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
|
||||
#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
#include "dispatchkit/dynamic_object.hpp"
|
||||
#include "dispatchkit/boxed_number.hpp"
|
||||
#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/dynamic_object.hpp"
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
|
||||
#include "language/chaiscript_eval.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:
|
||||
@ -34,6 +34,4 @@ ChaiScript_Basic chai(
|
||||
|
||||
// If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp
|
||||
|
||||
|
||||
|
||||
#endif /* CHAISCRIPT_BASIC_HPP_ */
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DEFINES_HPP_
|
||||
@ -20,9 +20,10 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
|
||||
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
|
||||
#endif
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#if defined( _LIBCPP_VERSION )
|
||||
#if defined(_LIBCPP_VERSION)
|
||||
#define CHAISCRIPT_LIBCPP
|
||||
#endif
|
||||
|
||||
@ -48,12 +49,10 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__llvm__)
|
||||
#define CHAISCRIPT_CLANG
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_HAS_DECLSPEC
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
@ -70,92 +69,63 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
|
||||
#define CHAISCRIPT_DEBUG false
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
namespace chaiscript {
|
||||
static const int version_major = 6;
|
||||
static const int version_minor = 1;
|
||||
static const int version_patch = 0;
|
||||
constexpr static const int version_major = 7;
|
||||
constexpr static const int version_minor = 0;
|
||||
constexpr static const int version_patch = 0;
|
||||
|
||||
static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
|
||||
static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
|
||||
static const bool debug_build = CHAISCRIPT_DEBUG;
|
||||
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)
|
||||
{
|
||||
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)...)));
|
||||
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)
|
||||
{
|
||||
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)...)));
|
||||
return std::unique_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
|
||||
#endif
|
||||
}
|
||||
|
||||
struct Build_Info {
|
||||
static int version_major()
|
||||
{
|
||||
return chaiscript::version_major;
|
||||
}
|
||||
[[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; }
|
||||
|
||||
static int version_minor()
|
||||
{
|
||||
return chaiscript::version_minor;
|
||||
}
|
||||
[[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; }
|
||||
|
||||
static int version_patch()
|
||||
{
|
||||
return chaiscript::version_patch;
|
||||
}
|
||||
[[nodiscard]] constexpr static int version_patch() noexcept { return chaiscript::version_patch; }
|
||||
|
||||
static std::string version()
|
||||
{
|
||||
[[nodiscard]] static std::string version() {
|
||||
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
||||
}
|
||||
|
||||
static std::string compiler_id()
|
||||
{
|
||||
return compiler_name() + '-' + compiler_version();
|
||||
}
|
||||
[[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); }
|
||||
|
||||
static std::string build_id()
|
||||
{
|
||||
return compiler_id() + (debug_build()?"-Debug":"-Release");
|
||||
}
|
||||
[[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build() ? "-Debug" : "-Release"); }
|
||||
|
||||
static std::string compiler_version()
|
||||
{
|
||||
return chaiscript::compiler_version;
|
||||
}
|
||||
[[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; }
|
||||
|
||||
static std::string compiler_name()
|
||||
{
|
||||
return chaiscript::compiler_name;
|
||||
}
|
||||
[[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; }
|
||||
|
||||
static bool debug_build()
|
||||
{
|
||||
return chaiscript::debug_build;
|
||||
}
|
||||
[[nodiscard]] constexpr static bool debug_build() noexcept { return chaiscript::debug_build; }
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto parse_num(const char *t_str) -> typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
{
|
||||
[[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 (char c = *t_str; (c = *t_str) != 0; ++t_str) {
|
||||
for (const auto c : t_str) {
|
||||
if (c < '0' || c > '9') {
|
||||
return t;
|
||||
}
|
||||
@ -165,19 +135,15 @@ namespace chaiscript {
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
||||
{
|
||||
[[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 (char c;; ++t_str) {
|
||||
c = *t_str;
|
||||
switch (c)
|
||||
{
|
||||
for (const auto c : t_str) {
|
||||
switch (c) {
|
||||
case '.':
|
||||
decimal_place = 10;
|
||||
break;
|
||||
@ -206,40 +172,73 @@ namespace chaiscript {
|
||||
if (decimal_place < 10) {
|
||||
t *= 10;
|
||||
t += static_cast<T>(c - '0');
|
||||
}
|
||||
else {
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T parse_num(const std::string &t_str)
|
||||
{
|
||||
return parse_num<T>(t_str.c_str());
|
||||
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 {
|
||||
};
|
||||
};
|
||||
|
||||
enum class Options
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
static inline std::vector<Options> default_options()
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
@ -19,53 +19,48 @@
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
|
||||
//#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/operators.hpp"
|
||||
#include "dispatchkit/bootstrap.hpp"
|
||||
#include "dispatchkit/bootstrap_stl.hpp"
|
||||
#include "dispatchkit/operators.hpp"
|
||||
//#include "dispatchkit/boxed_value.hpp"
|
||||
#include "language/chaiscript_prelude.hpp"
|
||||
#include "dispatchkit/register_function.hpp"
|
||||
#include "language/chaiscript_prelude.hpp"
|
||||
#include "utility/json_wrap.hpp"
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
#include <future>
|
||||
#endif
|
||||
|
||||
|
||||
/// @file
|
||||
///
|
||||
/// This file generates the standard library that normal ChaiScript usage requires.
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class Std_Lib
|
||||
{
|
||||
namespace chaiscript {
|
||||
class Std_Lib {
|
||||
public:
|
||||
|
||||
static ModulePtr library()
|
||||
{
|
||||
[[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::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);
|
||||
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value>>("Map", *lib);
|
||||
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value>>("Pair", *lib);
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
|
||||
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
||||
lib->add(chaiscript::fun(
|
||||
[](const std::function<chaiscript::Boxed_Value()> &t_func) { return std::async(std::launch::async, t_func); }),
|
||||
"async");
|
||||
#endif
|
||||
|
||||
json_wrap::library(*lib);
|
||||
|
||||
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
|
||||
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/);
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,25 +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-2017, Jason Turner (jason@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_THREADING_HPP_
|
||||
#define CHAISCRIPT_THREADING_HPP_
|
||||
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <thread>
|
||||
#else
|
||||
#ifndef CHAISCRIPT_NO_THREADS_WARNING
|
||||
#pragma message ("ChaiScript is compiling without thread safety.")
|
||||
#pragma message("ChaiScript is compiling without thread safety.")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -33,29 +32,22 @@
|
||||
/// 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 threading
|
||||
{
|
||||
|
||||
/// If threading is enabled, then this namespace contains std thread classes.
|
||||
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
|
||||
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
|
||||
namespace chaiscript::detail::threading {
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
|
||||
template<typename T>
|
||||
using unique_lock = std::unique_lock<T>;
|
||||
|
||||
template<typename T>
|
||||
using shared_lock = std::unique_lock<T>;
|
||||
using shared_lock = std::shared_lock<T>;
|
||||
|
||||
template<typename T>
|
||||
using lock_guard = std::lock_guard<T>;
|
||||
|
||||
|
||||
using shared_mutex = std::mutex;
|
||||
using std::shared_mutex;
|
||||
|
||||
using std::mutex;
|
||||
|
||||
@ -64,8 +56,7 @@ namespace chaiscript
|
||||
/// 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.
|
||||
template<typename T>
|
||||
class Thread_Storage
|
||||
{
|
||||
class Thread_Storage {
|
||||
public:
|
||||
Thread_Storage() = default;
|
||||
Thread_Storage(const Thread_Storage &) = delete;
|
||||
@ -73,101 +64,70 @@ namespace chaiscript
|
||||
Thread_Storage &operator=(const Thread_Storage &) = delete;
|
||||
Thread_Storage &operator=(Thread_Storage &&) = delete;
|
||||
|
||||
~Thread_Storage()
|
||||
{
|
||||
t().erase(this);
|
||||
}
|
||||
~Thread_Storage() { t().erase(this); }
|
||||
|
||||
inline const T *operator->() const
|
||||
{
|
||||
return &(t()[this]);
|
||||
}
|
||||
inline const T *operator->() const noexcept { return &(t()[this]); }
|
||||
|
||||
inline const T &operator*() const
|
||||
{
|
||||
return t()[this];
|
||||
}
|
||||
inline const T &operator*() const noexcept { return t()[this]; }
|
||||
|
||||
inline T *operator->()
|
||||
{
|
||||
return &(t()[this]);
|
||||
}
|
||||
|
||||
inline T &operator*()
|
||||
{
|
||||
return t()[this];
|
||||
}
|
||||
inline T *operator->() noexcept { return &(t()[this]); }
|
||||
|
||||
inline T &operator*() noexcept { return t()[this]; }
|
||||
|
||||
void *m_key;
|
||||
|
||||
private:
|
||||
static std::unordered_map<const void*, T> &t()
|
||||
{
|
||||
thread_local std::unordered_map<const void *, T> my_t;
|
||||
/// 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;
|
||||
}
|
||||
};
|
||||
|
||||
#else // threading disabled
|
||||
template<typename T>
|
||||
class unique_lock
|
||||
{
|
||||
class unique_lock {
|
||||
public:
|
||||
explicit unique_lock(T &) {}
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
constexpr explicit unique_lock(T &) noexcept {}
|
||||
constexpr void lock() noexcept {}
|
||||
constexpr void unlock() noexcept {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class shared_lock
|
||||
{
|
||||
class shared_lock {
|
||||
public:
|
||||
explicit shared_lock(T &) {}
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
constexpr explicit shared_lock(T &) noexcept {}
|
||||
constexpr void lock() noexcept {}
|
||||
constexpr void unlock() noexcept {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class lock_guard
|
||||
{
|
||||
class lock_guard {
|
||||
public:
|
||||
explicit lock_guard(T &) {}
|
||||
constexpr explicit lock_guard(T &) noexcept {}
|
||||
};
|
||||
|
||||
class shared_mutex { };
|
||||
|
||||
class recursive_mutex {};
|
||||
class shared_mutex {
|
||||
};
|
||||
|
||||
class recursive_mutex {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Thread_Storage
|
||||
{
|
||||
class Thread_Storage {
|
||||
public:
|
||||
explicit Thread_Storage()
|
||||
{
|
||||
}
|
||||
constexpr explicit Thread_Storage() noexcept {}
|
||||
|
||||
inline T *operator->() const
|
||||
{
|
||||
return &obj;
|
||||
}
|
||||
constexpr inline T *operator->() const noexcept { return &obj; }
|
||||
|
||||
inline T &operator*() const
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
constexpr inline T &operator*() const noexcept { return obj; }
|
||||
|
||||
private:
|
||||
mutable T obj;
|
||||
};
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace chaiscript::detail::threading
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -11,78 +11,50 @@
|
||||
|
||||
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:
|
||||
bad_any_cast() = default;
|
||||
|
||||
bad_any_cast(const bad_any_cast &) = default;
|
||||
|
||||
~bad_any_cast() noexcept override = default;
|
||||
|
||||
/// \brief Description of what error occurred
|
||||
const char * what() const noexcept override
|
||||
{
|
||||
return m_what.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_what = "bad any cast";
|
||||
const char *what() const noexcept override { return "bad any cast"; }
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace exception
|
||||
|
||||
class Any {
|
||||
private:
|
||||
struct Data
|
||||
{
|
||||
explicit Data(const std::type_info &t_type)
|
||||
: m_type(t_type)
|
||||
{
|
||||
struct Data {
|
||||
constexpr explicit Data(const std::type_info &t_type) noexcept
|
||||
: m_type(t_type) {
|
||||
}
|
||||
|
||||
Data &operator=(const Data &) = delete;
|
||||
|
||||
virtual ~Data() = default;
|
||||
virtual ~Data() noexcept = default;
|
||||
|
||||
virtual void *data() = 0;
|
||||
virtual void *data() noexcept = 0;
|
||||
|
||||
const std::type_info &type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
const std::type_info &type() const noexcept { return m_type; }
|
||||
|
||||
virtual std::unique_ptr<Data> clone() const = 0;
|
||||
const std::type_info &m_type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Data_Impl : Data
|
||||
{
|
||||
struct Data_Impl : Data {
|
||||
explicit Data_Impl(T t_type)
|
||||
: Data(typeid(T)),
|
||||
m_data(std::move(t_type))
|
||||
{
|
||||
: Data(typeid(T))
|
||||
, m_data(std::move(t_type)) {
|
||||
}
|
||||
|
||||
void *data() override
|
||||
{
|
||||
return &m_data;
|
||||
}
|
||||
void *data() noexcept override { return &m_data; }
|
||||
|
||||
std::unique_ptr<Data> clone() const override
|
||||
{
|
||||
return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
|
||||
}
|
||||
std::unique_ptr<Data> clone() const override { return std::make_unique<Data_Impl<T>>(m_data); }
|
||||
|
||||
Data_Impl &operator=(const Data_Impl&) = delete;
|
||||
Data_Impl &operator=(const Data_Impl &) = delete;
|
||||
|
||||
T m_data;
|
||||
};
|
||||
@ -91,63 +63,44 @@ namespace chaiscript {
|
||||
|
||||
public:
|
||||
// construct/copy/destruct
|
||||
Any() = default;
|
||||
Any(Any &&) = default;
|
||||
constexpr Any() noexcept = default;
|
||||
Any(Any &&) noexcept = default;
|
||||
Any &operator=(Any &&t_any) = default;
|
||||
|
||||
Any(const Any &t_any)
|
||||
{
|
||||
if (!t_any.empty())
|
||||
{
|
||||
m_data = t_any.m_data->clone();
|
||||
} else {
|
||||
m_data.reset();
|
||||
}
|
||||
: m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) {
|
||||
}
|
||||
|
||||
|
||||
template<typename ValueType,
|
||||
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
|
||||
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::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
|
||||
{
|
||||
: m_data(std::make_unique<Data_Impl<std::decay_t<ValueType>>>(std::forward<ValueType>(t_value))) {
|
||||
}
|
||||
|
||||
|
||||
Any & operator=(const Any &t_any)
|
||||
{
|
||||
Any &operator=(const Any &t_any) {
|
||||
Any copy(t_any);
|
||||
swap(copy);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ToType>
|
||||
ToType &cast() const
|
||||
{
|
||||
if (m_data && typeid(ToType) == m_data->type())
|
||||
{
|
||||
ToType &cast() const {
|
||||
if (m_data && typeid(ToType) == m_data->type()) {
|
||||
return *static_cast<ToType *>(m_data->data());
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// modifiers
|
||||
Any & swap(Any &t_other)
|
||||
{
|
||||
Any &swap(Any &t_other) {
|
||||
std::swap(t_other.m_data, m_data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// queries
|
||||
bool empty() const
|
||||
{
|
||||
return !bool(m_data);
|
||||
}
|
||||
bool empty() const noexcept { return !static_cast<bool>(m_data); }
|
||||
|
||||
const std::type_info & type() const
|
||||
{
|
||||
const std::type_info &type() const noexcept {
|
||||
if (m_data) {
|
||||
return m_data->type();
|
||||
} else {
|
||||
@ -156,9 +109,7 @@ namespace chaiscript {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_BAD_BOXED_CAST_HPP_
|
||||
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||
|
||||
@ -15,59 +14,51 @@
|
||||
#include <typeinfo>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "../utility/static_string.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Info;
|
||||
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,
|
||||
std::string t_what) noexcept
|
||||
: from(t_from), to(&t_to), m_what(std::move(t_what))
|
||||
{
|
||||
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(Type_Info t_from, const std::type_info &t_to)
|
||||
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
|
||||
{
|
||||
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") {
|
||||
}
|
||||
|
||||
explicit bad_boxed_cast(std::string t_what) noexcept
|
||||
: m_what(std::move(t_what))
|
||||
{
|
||||
explicit bad_boxed_cast(utility::Static_String t_what) noexcept
|
||||
: m_what(std::move(t_what)) {
|
||||
}
|
||||
|
||||
bad_boxed_cast(const bad_boxed_cast &) = default;
|
||||
bad_boxed_cast(const bad_boxed_cast &) noexcept = default;
|
||||
~bad_boxed_cast() noexcept override = default;
|
||||
|
||||
/// \brief Description of what error occurred
|
||||
const char * what() const noexcept override
|
||||
{
|
||||
return m_what.c_str();
|
||||
}
|
||||
const char *what() const noexcept override { 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
|
||||
|
||||
private:
|
||||
std::string m_what;
|
||||
utility::Static_String m_what;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace exception
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,85 +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-2017, Jason Turner (jason@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_BIND_FIRST_HPP_
|
||||
#define CHAISCRIPT_BIND_FIRST_HPP_
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
namespace chaiscript {
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
T* get_pointer(T *t)
|
||||
{
|
||||
constexpr T *get_pointer(T *t) noexcept {
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* get_pointer(const std::reference_wrapper<T> &t)
|
||||
{
|
||||
T *get_pointer(const std::reference_wrapper<T> &t) noexcept {
|
||||
return &t.get();
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
auto bind_first(Ret (*f)(P1, Param...), O&& o)
|
||||
{
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return f(std::forward<O>(o), std::forward<Param>(param)...);
|
||||
};
|
||||
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)...); };
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
auto bind_first(Ret (Class::*f)(Param...), O&& o)
|
||||
{
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
};
|
||||
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)...); };
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
auto bind_first(Ret (Class::*f)(Param...) const, O&& o)
|
||||
{
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
};
|
||||
|
||||
template<typename O, typename Ret, typename 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)...); };
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
|
||||
{
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return f(o, std::forward<Param>(param)...);
|
||||
};
|
||||
template<typename 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)...); };
|
||||
}
|
||||
|
||||
template<typename F, typename O, typename Ret, typename Class, typename P1, typename ... Param>
|
||||
auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const)
|
||||
{
|
||||
return [fo, o, f](Param ...param) -> Ret {
|
||||
return (fo.*f)(o, std::forward<Param>(param)...);
|
||||
};
|
||||
|
||||
template<typename F, typename O, 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>
|
||||
auto bind_first(const F &f, O&& 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
|
||||
|
||||
@ -1,58 +1,48 @@
|
||||
// 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)
|
||||
// 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_BOOTSTRAP_HPP_
|
||||
#define CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
|
||||
#include "../utility/utility.hpp"
|
||||
#include "register_function.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
|
||||
namespace bootstrap
|
||||
{
|
||||
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
|
||||
void array(const std::string &type, Module& m)
|
||||
{
|
||||
typedef typename std::remove_extent<T>::type ReturnType;
|
||||
/// \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 auto extent = std::extent<T>::value;
|
||||
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));
|
||||
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 &t, size_t index)->const ReturnType &{
|
||||
constexpr auto extent = std::extent<T>::value;
|
||||
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));
|
||||
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 &) {
|
||||
constexpr auto extent = std::extent<T>::value;
|
||||
return extent;
|
||||
}), "size");
|
||||
m.add(fun([](const T &) { return std::extent<T>::value; }), "size");
|
||||
}
|
||||
|
||||
/// \brief Adds a copy constructor for the given type to the given Model
|
||||
@ -61,9 +51,8 @@ namespace chaiscript
|
||||
/// \tparam T The type to add a copy constructor for
|
||||
/// \returns The passed in Module
|
||||
template<typename T>
|
||||
void copy_constructor(const std::string &type, Module& m)
|
||||
{
|
||||
m.add(constructor<T (const T &)>(), type);
|
||||
void copy_constructor(const std::string &type, Module &m) {
|
||||
m.add(constructor<T(const T &)>(), type);
|
||||
}
|
||||
|
||||
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
|
||||
@ -71,8 +60,7 @@ namespace chaiscript
|
||||
/// \param[in,out] m module to add comparison operators to
|
||||
/// \returns the passed in Module.
|
||||
template<typename T>
|
||||
void opers_comparison(Module& m)
|
||||
{
|
||||
void opers_comparison(Module &m) {
|
||||
operators::equal<T>(m);
|
||||
operators::greater_than<T>(m);
|
||||
operators::greater_than_equal<T>(m);
|
||||
@ -81,8 +69,6 @@ namespace chaiscript
|
||||
operators::not_equal<T>(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
|
||||
@ -91,9 +77,8 @@ namespace chaiscript
|
||||
/// \sa copy_constructor
|
||||
/// \sa constructor
|
||||
template<typename T>
|
||||
void basic_constructors(const std::string &type, Module& m)
|
||||
{
|
||||
m.add(constructor<T ()>(), type);
|
||||
void basic_constructors(const std::string &type, Module &m) {
|
||||
m.add(constructor<T()>(), type);
|
||||
copy_constructor<T>(type, m);
|
||||
}
|
||||
|
||||
@ -102,83 +87,58 @@ namespace chaiscript
|
||||
/// \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);
|
||||
void construct_pod(const std::string &type, Module &m) {
|
||||
m.add(fun([](const Boxed_Number &bn) { return bn.get_as<T>(); }), type);
|
||||
}
|
||||
|
||||
|
||||
/// Internal function for converting from a string to a value
|
||||
/// uses ostream operator >> to perform the conversion
|
||||
template<typename Input>
|
||||
auto parse_string(const std::string &i)
|
||||
-> typename std::enable_if<
|
||||
!std::is_same<Input, wchar_t>::value
|
||||
&& !std::is_same<Input, char16_t>::value
|
||||
&& !std::is_same<Input, char32_t>::value,
|
||||
Input>::type
|
||||
{
|
||||
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::stringstream ss(i);
|
||||
Input t;
|
||||
ss >> t;
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename Input>
|
||||
auto parse_string(const std::string &)
|
||||
-> typename std::enable_if<
|
||||
std::is_same<Input, wchar_t>::value
|
||||
|| std::is_same<Input, char16_t>::value
|
||||
|| std::is_same<Input, char32_t>::value,
|
||||
Input>::type
|
||||
{
|
||||
} 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
|
||||
template<typename T>
|
||||
void bootstrap_pod_type(const std::string &name, Module& m)
|
||||
{
|
||||
void bootstrap_pod_type(const std::string &name, Module &m) {
|
||||
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([](const T t) { return t; }), "to_" + name);
|
||||
}
|
||||
|
||||
|
||||
/// "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)
|
||||
{
|
||||
auto shared_ptr_clone(const std::shared_ptr<Type> &p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Specific version of shared_ptr_clone just for Proxy_Functions
|
||||
template<typename Type>
|
||||
std::shared_ptr<typename std::remove_const<Type>::type> shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
|
||||
{
|
||||
std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<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.
|
||||
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 {
|
||||
@ -188,34 +148,23 @@ namespace chaiscript
|
||||
|
||||
/// Class consisting of only static functions. All default bootstrapping occurs
|
||||
/// from this class.
|
||||
class Bootstrap
|
||||
{
|
||||
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())
|
||||
{
|
||||
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)
|
||||
{
|
||||
fwrite(s.c_str(), 1, s.size(), stdout);
|
||||
}
|
||||
|
||||
static void println(const std::string &s)
|
||||
{
|
||||
puts(s.c_str());
|
||||
}
|
||||
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)
|
||||
{
|
||||
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), ">");
|
||||
@ -253,35 +202,29 @@ namespace chaiscript
|
||||
|
||||
/// 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> ¶ms)
|
||||
{
|
||||
static Boxed_Value bind_function(const Function_Params ¶ms) {
|
||||
if (params.empty()) {
|
||||
throw exception::arity_error(0, 1);
|
||||
}
|
||||
|
||||
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||
|
||||
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1)
|
||||
{
|
||||
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(std::make_shared<dispatch::Bound_Function>(std::move(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()))));
|
||||
}
|
||||
|
||||
|
||||
static bool has_guard(const Const_Proxy_Function &t_pf)
|
||||
{
|
||||
static bool has_guard(const Const_Proxy_Function &t_pf) noexcept {
|
||||
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
return pf && pf->get_guard();
|
||||
return pf && pf->has_guard();
|
||||
}
|
||||
|
||||
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
|
||||
{
|
||||
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) {
|
||||
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf && pf->get_guard())
|
||||
{
|
||||
if (pf && pf->get_guard()) {
|
||||
return pf->get_guard();
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a guard");
|
||||
@ -289,33 +232,26 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (pf) {
|
||||
return pf->get_parse_tree();
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a parse tree");
|
||||
@ -323,20 +259,15 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
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 auto return_boxed_value_vector(const Function &f) {
|
||||
return [f](const dispatch::Proxy_Function_Base *b) { return do_return_boxed_value_vector(f, b); };
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
static void bootstrap(Module &m) {
|
||||
m.add(user_type<void>(), "void");
|
||||
m.add(user_type<bool>(), "bool");
|
||||
m.add(user_type<Boxed_Value>(), "Object");
|
||||
@ -348,11 +279,10 @@ namespace chaiscript
|
||||
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(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");
|
||||
@ -363,25 +293,30 @@ namespace chaiscript
|
||||
m.add(user_type<std::runtime_error>(), "runtime_error");
|
||||
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||
|
||||
m.add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
|
||||
m.add(constructor<std::runtime_error(const std::string &)>(), "runtime_error");
|
||||
|
||||
m.add(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(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::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::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.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() {
|
||||
@ -437,8 +372,7 @@ namespace chaiscript
|
||||
|
||||
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<Type_Info(const Type_Info &)>(), "Type_Info");
|
||||
|
||||
operators::equal<Type_Info>(m);
|
||||
|
||||
@ -452,21 +386,19 @@ namespace chaiscript
|
||||
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([](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");
|
||||
|
||||
|
||||
bootstrap_pod_type<double>("double", m);
|
||||
bootstrap_pod_type<long double>("long_double", m);
|
||||
bootstrap_pod_type<float>("float", m);
|
||||
@ -490,12 +422,10 @@ namespace chaiscript
|
||||
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
|
||||
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
|
||||
|
||||
|
||||
operators::logical_compliment<bool>(m);
|
||||
|
||||
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");
|
||||
@ -505,7 +435,6 @@ namespace chaiscript
|
||||
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");
|
||||
|
||||
@ -515,16 +444,13 @@ namespace chaiscript
|
||||
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) {
|
||||
m.add(fun([](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
|
||||
t_lhs.assign(t_rhs);
|
||||
}
|
||||
), "="
|
||||
);
|
||||
}),
|
||||
"=");
|
||||
|
||||
m.add(fun(&Boxed_Value::type_match), "type_match");
|
||||
|
||||
|
||||
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
|
||||
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
|
||||
|
||||
@ -535,38 +461,34 @@ namespace chaiscript
|
||||
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
|
||||
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
|
||||
|
||||
|
||||
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
|
||||
|
||||
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> >
|
||||
// >("AST_NodeVector", m);
|
||||
|
||||
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
|
||||
"eval_error",
|
||||
{ },
|
||||
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
||||
{},
|
||||
{{fun(&chaiscript::exception::eval_error::reason), "reason"},
|
||||
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
|
||||
{fun([](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::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"} }
|
||||
);
|
||||
|
||||
}),
|
||||
"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"} }
|
||||
);
|
||||
|
||||
{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::text), "text"},
|
||||
{fun(&AST_Node::identifier), "identifier"},
|
||||
{fun(&AST_Node::filename), "filename"},
|
||||
{fun(&AST_Node::start), "start"},
|
||||
@ -575,18 +497,15 @@ namespace chaiscript
|
||||
{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::transform(children.begin(),
|
||||
children.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
}), "children"}
|
||||
}
|
||||
);
|
||||
|
||||
}),
|
||||
"children"}});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace chaiscript::bootstrap
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,19 +1,17 @@
|
||||
// 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)
|
||||
// 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
|
||||
|
||||
|
||||
/// \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_
|
||||
|
||||
@ -31,62 +29,44 @@
|
||||
#include "register_function.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace bootstrap
|
||||
{
|
||||
namespace standard_library
|
||||
{
|
||||
|
||||
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
|
||||
{
|
||||
typedef Container container_type;
|
||||
struct Bidir_Range {
|
||||
using container_type = Container;
|
||||
|
||||
Bidir_Range(Container &c)
|
||||
: m_begin(c.begin()), m_end(c.end())
|
||||
{
|
||||
constexpr Bidir_Range(Container &c)
|
||||
: m_begin(c.begin())
|
||||
, m_end(c.end()) {
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return m_begin == m_end;
|
||||
}
|
||||
constexpr bool empty() const noexcept { return m_begin == m_end; }
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
constexpr void pop_front() {
|
||||
if (empty()) {
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
++m_begin;
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
constexpr void pop_back() {
|
||||
if (empty()) {
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
--m_end;
|
||||
}
|
||||
|
||||
decltype(auto) front() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
constexpr decltype(auto) front() const {
|
||||
if (empty()) {
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
return (*m_begin);
|
||||
}
|
||||
|
||||
decltype(auto) back() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
constexpr decltype(auto) back() const {
|
||||
if (empty()) {
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
auto pos = m_end;
|
||||
@ -99,36 +79,29 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
size_t count(const T &t_target, const typename T::key_type &t_key)
|
||||
{
|
||||
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
|
||||
template<typename Bidir_Type>
|
||||
void input_range_type_impl(const std::string &type, Module& m)
|
||||
{
|
||||
void input_range_type_impl(const std::string &type, Module &m) {
|
||||
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_internal");
|
||||
|
||||
m.add(fun(&Bidir_Type::empty), "empty");
|
||||
m.add(fun(&Bidir_Type::pop_front), "pop_front");
|
||||
@ -137,16 +110,13 @@ namespace chaiscript
|
||||
m.add(fun(&Bidir_Type::back), "back");
|
||||
}
|
||||
|
||||
|
||||
/// 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)
|
||||
{
|
||||
void insert_at(Type &container, int pos, const typename Type::value_type &v) {
|
||||
auto itr = container.begin();
|
||||
auto 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");
|
||||
}
|
||||
|
||||
@ -154,165 +124,96 @@ namespace chaiscript
|
||||
container.insert(itr, v);
|
||||
}
|
||||
|
||||
|
||||
/// Algorithm for erasing a specific position from a container
|
||||
template<typename Type>
|
||||
void erase_at(Type &container, int pos)
|
||||
{
|
||||
void erase_at(Type &container, int pos) {
|
||||
auto itr = container.begin();
|
||||
auto end = container.end();
|
||||
|
||||
if (pos < 0 || std::distance(itr, end) < (pos-1))
|
||||
{
|
||||
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);
|
||||
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);
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr input_range_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
input_range_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// 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)
|
||||
{
|
||||
//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 prefering to keep the key as 'int' to avoid runtime conversions
|
||||
void random_access_container_type(const std::string & /*type*/, Module &m) {
|
||||
// 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(
|
||||
[](const ContainerType &c, int index) -> typename ContainerType::const_reference {
|
||||
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
|
||||
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));
|
||||
}), "[]");
|
||||
}),
|
||||
"[]");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr random_access_container_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
random_access_container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 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)
|
||||
{
|
||||
void assignable_type(const std::string &type, Module &m) {
|
||||
copy_constructor<ContainerType>(type, m);
|
||||
operators::assign<ContainerType>(m);
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr assignable_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
assignable_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add container resize concept to the given ContainerType
|
||||
/// http://www.cplusplus.com/reference/stl/
|
||||
template<typename ContainerType>
|
||||
void resizable_type(const std::string &/*type*/, Module& m)
|
||||
{
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type& val) { return a->resize(n, val); } ), "resize");
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); } ), "resize");
|
||||
void resizable_type(const std::string & /*type*/, Module &m) {
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type &val) {
|
||||
return a->resize(n, val);
|
||||
}),
|
||||
"resize");
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); }), "resize");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr resizable_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
resizable_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add container reserve concept to the given ContainerType
|
||||
/// http://www.cplusplus.com/reference/stl/
|
||||
template<typename ContainerType>
|
||||
void reservable_type(const std::string &/*type*/, Module& m)
|
||||
{
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); } ), "reserve");
|
||||
m.add(fun([](const ContainerType *a) { return a->capacity(); } ), "capacity");
|
||||
void reservable_type(const std::string & /*type*/, Module &m) {
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); }), "reserve");
|
||||
m.add(fun([](const ContainerType *a) { return a->capacity(); }), "capacity");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr reservable_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
reservable_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// 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");
|
||||
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");
|
||||
}
|
||||
template <typename ContainerType>
|
||||
ModulePtr container_type(const std::string& type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add default constructable concept to the given Type
|
||||
/// 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);
|
||||
void default_constructible_type(const std::string &type, Module &m) {
|
||||
m.add(constructor<Type()>(), type);
|
||||
}
|
||||
template <typename Type>
|
||||
ModulePtr default_constructible_type(const std::string& type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
default_constructible_type<Type>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 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{
|
||||
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";
|
||||
} else {
|
||||
@ -322,46 +223,35 @@ namespace chaiscript
|
||||
|
||||
m.add(fun(&detail::erase_at<ContainerType>), "erase_at");
|
||||
}
|
||||
template <typename ContainerType>
|
||||
ModulePtr sequence_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
sequence_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/// 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){
|
||||
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");
|
||||
} else {
|
||||
return (container.back());
|
||||
}
|
||||
}
|
||||
)
|
||||
, "back");
|
||||
m.add(fun([](const ContainerType &container)->decltype(auto){
|
||||
}),
|
||||
"back");
|
||||
m.add(fun([](const ContainerType &container) -> decltype(auto) {
|
||||
if (container.empty()) {
|
||||
throw std::range_error("Container empty");
|
||||
} else {
|
||||
return (container.back());
|
||||
}
|
||||
}
|
||||
)
|
||||
, "back");
|
||||
}),
|
||||
"back");
|
||||
|
||||
|
||||
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
||||
m.add(fun(static_cast<push_back>(&ContainerType::push_back)),
|
||||
[&]()->std::string{
|
||||
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"
|
||||
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"
|
||||
@ -369,8 +259,7 @@ namespace chaiscript
|
||||
" } else { \n"
|
||||
" container.push_back_ref(clone(x)); \n"
|
||||
" }\n"
|
||||
"} \n"
|
||||
);
|
||||
"} \n");
|
||||
|
||||
return "push_back_ref";
|
||||
} else {
|
||||
@ -380,51 +269,38 @@ namespace chaiscript
|
||||
|
||||
m.add(fun(&ContainerType::pop_back), "pop_back");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr back_insertion_sequence_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
back_insertion_sequence_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 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)
|
||||
{
|
||||
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference);
|
||||
typedef void (ContainerType::*pop_ptr)();
|
||||
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::*)();
|
||||
|
||||
m.add(fun([](ContainerType &container)->decltype(auto){
|
||||
m.add(fun([](ContainerType &container) -> decltype(auto) {
|
||||
if (container.empty()) {
|
||||
throw std::range_error("Container empty");
|
||||
} else {
|
||||
return (container.front());
|
||||
}
|
||||
}
|
||||
)
|
||||
, "front");
|
||||
}),
|
||||
"front");
|
||||
|
||||
m.add(fun([](const ContainerType &container)->decltype(auto){
|
||||
m.add(fun([](const ContainerType &container) -> decltype(auto) {
|
||||
if (container.empty()) {
|
||||
throw std::range_error("Container empty");
|
||||
} else {
|
||||
return (container.front());
|
||||
}
|
||||
}
|
||||
)
|
||||
, "front");
|
||||
}),
|
||||
"front");
|
||||
|
||||
|
||||
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
|
||||
[&]()->std::string{
|
||||
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"
|
||||
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"
|
||||
@ -432,8 +308,7 @@ namespace chaiscript
|
||||
" } else { \n"
|
||||
" container.push_front_ref(clone(x)); \n"
|
||||
" }\n"
|
||||
"} \n"
|
||||
);
|
||||
"} \n");
|
||||
return "push_front_ref";
|
||||
} else {
|
||||
return "push_front";
|
||||
@ -442,70 +317,41 @@ namespace chaiscript
|
||||
|
||||
m.add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr front_insertion_sequence_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
front_insertion_sequence_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// bootstrap a given PairType
|
||||
/// http://www.sgi.com/tech/stl/pair.html
|
||||
template<typename PairType>
|
||||
void pair_type(const std::string &type, Module& m)
|
||||
{
|
||||
void pair_type(const std::string &type, Module &m) {
|
||||
m.add(user_type<PairType>(), type);
|
||||
|
||||
m.add(fun(&PairType::first), "first");
|
||||
m.add(fun(&PairType::second), "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);
|
||||
}
|
||||
template<typename PairType>
|
||||
ModulePtr pair_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
pair_type<PairType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 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)
|
||||
{
|
||||
void pair_associative_container_type(const std::string &type, Module &m) {
|
||||
pair_type<typename ContainerType::value_type>(type + "_Pair", m);
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr pair_associative_container_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
pair_associative_container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// 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)
|
||||
{
|
||||
void unique_associative_container_type(const std::string & /*type*/, Module &m) {
|
||||
m.add(fun(detail::count<ContainerType>), "count");
|
||||
|
||||
typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &);
|
||||
using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &);
|
||||
|
||||
m.add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
|
||||
|
||||
m.add(fun(&detail::insert<ContainerType>), "insert");
|
||||
|
||||
m.add(fun(&detail::insert_ref<ContainerType>),
|
||||
[]()->std::string{
|
||||
m.add(fun(&detail::insert_ref<ContainerType>), []() -> std::string {
|
||||
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
|
||||
return "insert_ref";
|
||||
} else {
|
||||
@ -513,32 +359,22 @@ namespace chaiscript
|
||||
}
|
||||
}());
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr unique_associative_container_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
unique_associative_container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add a MapType container
|
||||
/// http://www.sgi.com/tech/stl/Map.html
|
||||
template<typename MapType>
|
||||
void map_type(const std::string &type, Module& m)
|
||||
{
|
||||
void map_type(const std::string &type, Module &m) {
|
||||
m.add(user_type<MapType>(), type);
|
||||
|
||||
typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &);
|
||||
typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const;
|
||||
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>))
|
||||
{
|
||||
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>)) {
|
||||
m.eval(R"(
|
||||
def Map::`==`(Map rhs) {
|
||||
if ( rhs.size() != this.size() ) {
|
||||
@ -557,8 +393,7 @@ namespace chaiscript
|
||||
}
|
||||
true;
|
||||
}
|
||||
} )"
|
||||
);
|
||||
} )");
|
||||
}
|
||||
|
||||
container_type<MapType>(type, m);
|
||||
@ -568,19 +403,10 @@ namespace chaiscript
|
||||
pair_associative_container_type<MapType>(type, m);
|
||||
input_range_type<MapType>(type, m);
|
||||
}
|
||||
template<typename MapType>
|
||||
ModulePtr map_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
map_type<MapType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// http://www.sgi.com/tech/stl/List.html
|
||||
template<typename ListType>
|
||||
void list_type(const std::string &type, Module& m)
|
||||
{
|
||||
void list_type(const std::string &type, Module &m) {
|
||||
m.add(user_type<ListType>(), type);
|
||||
|
||||
front_insertion_sequence_type<ListType>(type, m);
|
||||
@ -592,44 +418,30 @@ namespace chaiscript
|
||||
assignable_type<ListType>(type, m);
|
||||
input_range_type<ListType>(type, m);
|
||||
}
|
||||
template<typename ListType>
|
||||
ModulePtr list_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
list_type<ListType>(type, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// 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)
|
||||
{
|
||||
void vector_type(const std::string &type, Module &m) {
|
||||
m.add(user_type<VectorType>(), type);
|
||||
|
||||
m.add(fun([](VectorType &container)->decltype(auto){
|
||||
m.add(fun([](VectorType &container) -> decltype(auto) {
|
||||
if (container.empty()) {
|
||||
throw std::range_error("Container empty");
|
||||
} else {
|
||||
return (container.front());
|
||||
}
|
||||
}
|
||||
)
|
||||
, "front");
|
||||
}),
|
||||
"front");
|
||||
|
||||
m.add(fun([](const VectorType &container)->decltype(auto){
|
||||
m.add(fun([](const VectorType &container) -> decltype(auto) {
|
||||
if (container.empty()) {
|
||||
throw std::range_error("Container empty");
|
||||
} else {
|
||||
return (container.front());
|
||||
}
|
||||
}
|
||||
)
|
||||
, "front");
|
||||
|
||||
|
||||
|
||||
}),
|
||||
"front");
|
||||
|
||||
back_insertion_sequence_type<VectorType>(type, m);
|
||||
sequence_type<VectorType>(type, m);
|
||||
@ -641,8 +453,7 @@ namespace chaiscript
|
||||
assignable_type<VectorType>(type, m);
|
||||
input_range_type<VectorType>(type, m);
|
||||
|
||||
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
|
||||
{
|
||||
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) {
|
||||
m.eval(R"(
|
||||
def Vector::`==`(Vector rhs) {
|
||||
if ( rhs.size() != this.size() ) {
|
||||
@ -661,23 +472,14 @@ namespace chaiscript
|
||||
}
|
||||
true;
|
||||
}
|
||||
} )"
|
||||
);
|
||||
} )");
|
||||
}
|
||||
}
|
||||
template<typename VectorType>
|
||||
ModulePtr vector_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
vector_type<VectorType>(type, *m);
|
||||
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)
|
||||
{
|
||||
void string_type(const std::string &type, Module &m) {
|
||||
m.add(user_type<String>(), type);
|
||||
operators::addition<String>(m);
|
||||
operators::assign_sum<String>(m);
|
||||
@ -689,9 +491,8 @@ namespace chaiscript
|
||||
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{
|
||||
// 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";
|
||||
} else {
|
||||
@ -699,57 +500,34 @@ namespace chaiscript
|
||||
}
|
||||
}());
|
||||
|
||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); }), "find");
|
||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->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");
|
||||
|
||||
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");
|
||||
m.add(fun([](String *s, typename String::value_type c) -> decltype(auto) { return (*s += c); }), "+=");
|
||||
|
||||
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([](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([](const String *s) { return s->c_str(); } ), "c_str");
|
||||
m.add(fun([](const String *s) { return s->data(); } ), "data");
|
||||
m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr");
|
||||
m.add(fun([](const String *s) { return s->c_str(); }), "c_str");
|
||||
m.add(fun([](const String *s) { return s->data(); }), "data");
|
||||
m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); }), "substr");
|
||||
}
|
||||
template<typename String>
|
||||
ModulePtr string_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
string_type<String>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Add a MapType container
|
||||
/// http://www.sgi.com/tech/stl/Map.html
|
||||
template<typename FutureType>
|
||||
void future_type(const std::string &type, Module& m)
|
||||
{
|
||||
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");
|
||||
}
|
||||
template<typename FutureType>
|
||||
ModulePtr future_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
future_type<FutureType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chaiscript::bootstrap::standard_library
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_BOXED_CAST_HPP_
|
||||
#define CHAISCRIPT_BOXED_CAST_HPP_
|
||||
|
||||
@ -19,17 +18,13 @@
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
namespace detail {
|
||||
namespace exception {
|
||||
class bad_any_cast;
|
||||
} // namespace exception
|
||||
} // namespace detail
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class Type_Conversions;
|
||||
}
|
||||
namespace chaiscript::detail::exception {
|
||||
class bad_any_cast;
|
||||
} // namespace chaiscript::detail::exception
|
||||
|
||||
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
|
||||
@ -73,26 +68,24 @@ namespace chaiscript
|
||||
/// assert(i == 5);
|
||||
/// \endcode
|
||||
template<typename Type>
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
|
||||
{
|
||||
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>())) {
|
||||
try {
|
||||
return(detail::Cast_Helper<Type>::cast(bv, t_conversions));
|
||||
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (t_conversions && (*t_conversions)->convertable_type<Type>())
|
||||
{
|
||||
if (t_conversions && (*t_conversions)->convertable_type<Type>()) {
|
||||
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));
|
||||
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((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv),
|
||||
t_conversions));
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
@ -102,12 +95,8 @@ namespace chaiscript
|
||||
// attempted dynamic_cast
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_BOXED_CAST_HELPER_HPP_
|
||||
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
||||
|
||||
@ -17,19 +16,17 @@
|
||||
#include "boxed_value.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace chaiscript {
|
||||
class Type_Conversions_State;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
// Cast_Helper_Inner helper classes
|
||||
|
||||
template<typename T>
|
||||
T* throw_if_null(T *t)
|
||||
{
|
||||
if (t) { return t; }
|
||||
constexpr T *throw_if_null(T *t) {
|
||||
if (t) {
|
||||
return t;
|
||||
}
|
||||
throw std::runtime_error("Attempted to dereference null Boxed_Value");
|
||||
}
|
||||
|
||||
@ -51,7 +48,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)) {
|
||||
@ -72,79 +68,60 @@ namespace chaiscript
|
||||
|
||||
/// 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 *)
|
||||
{
|
||||
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()));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
|
||||
{
|
||||
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> {
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const * type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result *>
|
||||
{
|
||||
static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
struct Cast_Helper_Inner<const Result *> {
|
||||
static const Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
/// Cast_Helper_Inner for casting to a * type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result *>
|
||||
{
|
||||
static Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
struct Cast_Helper_Inner<Result *> {
|
||||
static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
|
||||
{
|
||||
struct Cast_Helper_Inner<Result *const &> : public Cast_Helper_Inner<Result *> {
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *>
|
||||
{
|
||||
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 *)
|
||||
{
|
||||
struct Cast_Helper_Inner<const Result &> {
|
||||
static const Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a & type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result &>
|
||||
{
|
||||
static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
struct Cast_Helper_Inner<Result &> {
|
||||
static Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
/// Cast_Helper_Inner for casting to a && type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result &&>
|
||||
{
|
||||
static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
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())));
|
||||
}
|
||||
};
|
||||
@ -152,10 +129,8 @@ namespace chaiscript
|
||||
/// 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 *)
|
||||
{
|
||||
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>>>()));
|
||||
}
|
||||
};
|
||||
@ -163,10 +138,8 @@ namespace chaiscript
|
||||
/// 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 *)
|
||||
{
|
||||
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>>>());
|
||||
}
|
||||
};
|
||||
@ -174,150 +147,114 @@ namespace chaiscript
|
||||
/// 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 *)
|
||||
{
|
||||
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> >();
|
||||
}
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result>> {
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob.get().cast<std::shared_ptr<Result>>(); }
|
||||
};
|
||||
|
||||
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
{
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
|
||||
struct Cast_Helper_Inner<std::shared_ptr<const Result>> {
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||
if (!ob.get_type_info().is_const()) {
|
||||
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result>>());
|
||||
} else {
|
||||
return ob.get().cast<std::shared_ptr<const Result> >();
|
||||
return ob.get().cast<std::shared_ptr<const Result>>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// 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>> {
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result> &>
|
||||
{
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result> &> {
|
||||
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result>>();
|
||||
return ob.pointer_sentinel(res);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
{
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result>> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
{
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a Boxed_Value type
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return ob;
|
||||
}
|
||||
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 *)
|
||||
{
|
||||
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
|
||||
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
|
||||
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 {
|
||||
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
|
||||
return (Cast_Helper_Inner<T>::cast(ob, t_conversions));
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
}
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_BOXED_VALUE_HPP_
|
||||
#define CHAISCRIPT_BOXED_VALUE_HPP_
|
||||
|
||||
@ -19,36 +18,29 @@
|
||||
#include "any.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
namespace chaiscript {
|
||||
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
|
||||
/// \sa chaiscript::boxed_cast
|
||||
class Boxed_Value
|
||||
{
|
||||
class Boxed_Value {
|
||||
public:
|
||||
/// used for explicitly creating a "void" object
|
||||
struct Void_Type
|
||||
{
|
||||
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)
|
||||
: 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)
|
||||
{
|
||||
struct Data {
|
||||
Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value)
|
||||
: m_type_info(ti)
|
||||
, m_obj(std::move(to))
|
||||
, m_data_ptr(ti.is_const() ? nullptr : const_cast<void *>(t_void_ptr))
|
||||
, m_const_data_ptr(t_void_ptr)
|
||||
, m_is_ref(is_ref)
|
||||
, m_return_value(t_return_value) {
|
||||
}
|
||||
|
||||
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;
|
||||
@ -56,8 +48,7 @@ namespace chaiscript
|
||||
m_const_data_ptr = rhs.m_const_data_ptr;
|
||||
m_return_value = rhs.m_return_value;
|
||||
|
||||
if (rhs.m_attrs)
|
||||
{
|
||||
if (rhs.m_attrs) {
|
||||
m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
|
||||
}
|
||||
|
||||
@ -69,7 +60,6 @@ namespace chaiscript
|
||||
Data(Data &&) = default;
|
||||
Data &operator=(Data &&rhs) = default;
|
||||
|
||||
|
||||
Type_Info m_type_info;
|
||||
chaiscript::detail::Any m_obj;
|
||||
void *m_data_ptr;
|
||||
@ -79,197 +69,118 @@ namespace chaiscript
|
||||
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 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);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto get(const std::shared_ptr<T> *obj, bool t_return_value)
|
||||
{
|
||||
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) {
|
||||
return get(*obj, t_return_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto get(const std::shared_ptr<T> &obj, bool t_return_value)
|
||||
{
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(obj),
|
||||
false,
|
||||
obj.get(),
|
||||
t_return_value
|
||||
);
|
||||
static auto get(const std::shared_ptr<T> &obj, bool t_return_value) {
|
||||
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(obj), false, obj.get(), t_return_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto get(std::shared_ptr<T> &&obj, bool t_return_value)
|
||||
{
|
||||
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
|
||||
);
|
||||
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(obj)), false, ptr, t_return_value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
static auto get(T *t, bool t_return_value)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
);
|
||||
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)
|
||||
{
|
||||
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(),
|
||||
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
|
||||
true,
|
||||
ptr,
|
||||
t_return_value
|
||||
);
|
||||
t_return_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto get(T t, bool t_return_value)
|
||||
{
|
||||
static auto get(T t, bool t_return_value) {
|
||||
auto p = std::make_shared<T>(std::move(t));
|
||||
auto ptr = p.get();
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::move(p)),
|
||||
false,
|
||||
ptr,
|
||||
t_return_value
|
||||
);
|
||||
}
|
||||
|
||||
static std::shared_ptr<Data> get()
|
||||
{
|
||||
return std::make_shared<Data>(
|
||||
Type_Info(),
|
||||
chaiscript::detail::Any(),
|
||||
false,
|
||||
nullptr,
|
||||
false
|
||||
);
|
||||
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(p)), false, ptr, t_return_value);
|
||||
}
|
||||
|
||||
static std::shared_ptr<Data> get() { return std::make_shared<Data>(Type_Info(), chaiscript::detail::Any(), false, nullptr, false); }
|
||||
};
|
||||
|
||||
public:
|
||||
/// Basic Boxed_Value constructor
|
||||
template<typename T,
|
||||
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
|
||||
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))
|
||||
{
|
||||
: m_data(Object_Data::get(std::forward<T>(t), t_return_value)) {
|
||||
}
|
||||
|
||||
/// Unknown-type constructor
|
||||
Boxed_Value() = default;
|
||||
|
||||
Boxed_Value(Boxed_Value&&) = default;
|
||||
Boxed_Value& operator=(Boxed_Value&&) = default;
|
||||
Boxed_Value(const Boxed_Value&) = default;
|
||||
Boxed_Value& operator=(const Boxed_Value&) = default;
|
||||
Boxed_Value(Boxed_Value &&) = default;
|
||||
Boxed_Value &operator=(Boxed_Value &&) = default;
|
||||
Boxed_Value(const Boxed_Value &) = default;
|
||||
Boxed_Value &operator=(const Boxed_Value &) = default;
|
||||
|
||||
void swap(Boxed_Value &rhs)
|
||||
{
|
||||
std::swap(m_data, rhs.m_data);
|
||||
}
|
||||
void swap(Boxed_Value &rhs) noexcept { std::swap(m_data, rhs.m_data); }
|
||||
|
||||
/// Copy the values stored in rhs.m_data to m_data.
|
||||
/// m_data pointers are not shared in this case
|
||||
Boxed_Value assign(const Boxed_Value &rhs)
|
||||
{
|
||||
Boxed_Value assign(const Boxed_Value &rhs) noexcept {
|
||||
(*m_data) = (*rhs.m_data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Type_Info &get_type_info() const noexcept
|
||||
{
|
||||
return m_data->m_type_info;
|
||||
}
|
||||
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_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);
|
||||
}
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
: m_ptr(t_ptr)
|
||||
, m_data(data) {
|
||||
}
|
||||
|
||||
~Sentinel()
|
||||
{
|
||||
~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 &operator=(Sentinel &&s) = default;
|
||||
Sentinel(Sentinel &&s) = default;
|
||||
|
||||
operator std::shared_ptr<T>&() const
|
||||
{
|
||||
return m_ptr.get();
|
||||
}
|
||||
operator std::shared_ptr<T> &() const noexcept { return m_ptr.get(); }
|
||||
|
||||
Sentinel &operator=(const Sentinel &) = delete;
|
||||
Sentinel(Sentinel&) = delete;
|
||||
Sentinel(Sentinel &) = delete;
|
||||
|
||||
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
|
||||
std::reference_wrapper<Data> m_data;
|
||||
@ -278,50 +189,24 @@ namespace chaiscript
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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_ref() const noexcept { return m_data->m_is_ref; }
|
||||
|
||||
bool is_return_value() const noexcept
|
||||
{
|
||||
return m_data->m_return_value;
|
||||
}
|
||||
bool is_return_value() const noexcept { return m_data->m_return_value; }
|
||||
|
||||
void reset_return_value() const noexcept
|
||||
{
|
||||
m_data->m_return_value = false;
|
||||
}
|
||||
void reset_return_value() const noexcept { m_data->m_return_value = false; }
|
||||
|
||||
bool is_pointer() const noexcept
|
||||
{
|
||||
return !is_ref();
|
||||
}
|
||||
bool is_pointer() const noexcept { return !is_ref(); }
|
||||
|
||||
void *get_ptr() const noexcept
|
||||
{
|
||||
return m_data->m_data_ptr;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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>>>();
|
||||
}
|
||||
|
||||
@ -329,38 +214,32 @@ namespace chaiscript
|
||||
if (attr) {
|
||||
return Boxed_Value(attr, Internal_Construction());
|
||||
} else {
|
||||
Boxed_Value bv; //default construct a new one
|
||||
Boxed_Value bv; // default construct a new one
|
||||
attr = bv.m_data;
|
||||
return bv;
|
||||
}
|
||||
}
|
||||
|
||||
Boxed_Value ©_attrs(const Boxed_Value &t_obj)
|
||||
{
|
||||
if (t_obj.m_data->m_attrs)
|
||||
{
|
||||
Boxed_Value ©_attrs(const Boxed_Value &t_obj) {
|
||||
if (t_obj.m_data->m_attrs) {
|
||||
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Boxed_Value &clone_attrs(const Boxed_Value &t_obj)
|
||||
{
|
||||
Boxed_Value &clone_attrs(const Boxed_Value &t_obj) {
|
||||
copy_attrs(t_obj);
|
||||
reset_return_value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// \returns true if the two Boxed_Values share the same internal type
|
||||
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept
|
||||
{
|
||||
return l.get_type_info() == r.get_type_info();
|
||||
}
|
||||
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{};
|
||||
struct Internal_Construction {
|
||||
};
|
||||
|
||||
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
|
||||
: m_data(std::move(t_data)) {
|
||||
@ -369,7 +248,8 @@ namespace chaiscript
|
||||
std::shared_ptr<Data> m_data = Object_Data::get();
|
||||
};
|
||||
|
||||
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
|
||||
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or
|
||||
/// std::reference_type
|
||||
/// a copy is not made.
|
||||
/// @param t The value to box
|
||||
///
|
||||
@ -384,8 +264,7 @@ namespace chaiscript
|
||||
///
|
||||
/// @sa @ref adding_objects
|
||||
template<typename T>
|
||||
Boxed_Value var(T &&t)
|
||||
{
|
||||
Boxed_Value var(T &&t) {
|
||||
return Boxed_Value(std::forward<T>(t));
|
||||
}
|
||||
|
||||
@ -395,9 +274,8 @@ 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::make_shared<typename std::add_const<T>::type>(t));
|
||||
}
|
||||
|
||||
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
|
||||
@ -406,9 +284,8 @@ namespace chaiscript
|
||||
/// \returns Immutable Boxed_Value
|
||||
/// \sa Boxed_Value::is_const
|
||||
template<typename T>
|
||||
Boxed_Value const_var_impl(T *t)
|
||||
{
|
||||
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
|
||||
Boxed_Value const_var_impl(T *t) {
|
||||
return Boxed_Value(const_cast<typename std::add_const<T>::type *>(t));
|
||||
}
|
||||
|
||||
/// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
|
||||
@ -417,9 +294,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)
|
||||
{
|
||||
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(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));
|
||||
}
|
||||
|
||||
/// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
|
||||
@ -428,11 +304,10 @@ 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)
|
||||
{
|
||||
return Boxed_Value( std::cref(t.get()) );
|
||||
}
|
||||
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.
|
||||
@ -458,8 +333,7 @@ namespace chaiscript
|
||||
/// \todo support C++11 strongly typed enums
|
||||
/// \sa \ref adding_objects
|
||||
template<typename T>
|
||||
Boxed_Value const_var(const T &t)
|
||||
{
|
||||
Boxed_Value const_var(const T &t) {
|
||||
return detail::const_var_impl(t);
|
||||
}
|
||||
|
||||
@ -479,7 +353,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||
@ -12,49 +12,50 @@
|
||||
namespace chaiscript {
|
||||
namespace dispatch {
|
||||
namespace detail {
|
||||
|
||||
template<typename Class, typename ... Param>
|
||||
struct Constructor
|
||||
{
|
||||
template<typename ... Inner>
|
||||
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
|
||||
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 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 {
|
||||
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 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 {
|
||||
template<typename... Inner>
|
||||
Ret operator()(Inner &&...inner) const {
|
||||
return (m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret(*m_func)(Param...);
|
||||
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 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 {
|
||||
template<typename... Inner>
|
||||
Ret operator()(Class &o, Inner &&...inner) const {
|
||||
return (o.*m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
@ -62,46 +63,37 @@ namespace chaiscript {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Arity
|
||||
{
|
||||
struct Arity {
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Arity<Ret (Params...)>
|
||||
{
|
||||
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 Function_Signature
|
||||
{
|
||||
struct Callable_Traits {
|
||||
using Signature = typename Function_Signature<decltype(&T::operator())>::Signature;
|
||||
using Return_Type = typename Function_Signature<decltype(&T::operator())>::Return_Type;
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Function_Signature<Ret (Params...)>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
template<typename Ret, typename T, typename ... Params>
|
||||
struct Function_Signature<Ret (T::*)(Params...) const>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Callable_Traits
|
||||
{
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Signature Signature;
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Return_Type Return_Type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace dispatch
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_OBJECT_HPP_
|
||||
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||
|
||||
@ -18,21 +17,17 @@
|
||||
#include "boxed_value.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
namespace dispatch {
|
||||
class Proxy_Function_Base;
|
||||
} // namespace dispatch
|
||||
class Type_Conversions;
|
||||
namespace dispatch {
|
||||
class Proxy_Function_Base;
|
||||
} // namespace dispatch
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
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")
|
||||
{
|
||||
|
||||
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") {
|
||||
}
|
||||
|
||||
option_explicit_set(const option_explicit_set &) = default;
|
||||
@ -40,43 +35,26 @@ namespace chaiscript
|
||||
~option_explicit_set() noexcept override = default;
|
||||
};
|
||||
|
||||
class Dynamic_Object
|
||||
{
|
||||
class Dynamic_Object {
|
||||
public:
|
||||
explicit Dynamic_Object(std::string t_type_name)
|
||||
: m_type_name(std::move(t_type_name)), m_option_explicit(false)
|
||||
{
|
||||
: m_type_name(std::move(t_type_name))
|
||||
, m_option_explicit(false) {
|
||||
}
|
||||
|
||||
Dynamic_Object() = default;
|
||||
|
||||
bool is_explicit() const
|
||||
{
|
||||
return m_option_explicit;
|
||||
}
|
||||
bool is_explicit() const noexcept { return m_option_explicit; }
|
||||
|
||||
void set_explicit(const bool t_explicit)
|
||||
{
|
||||
m_option_explicit = t_explicit;
|
||||
}
|
||||
void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; }
|
||||
|
||||
std::string get_type_name() const
|
||||
{
|
||||
return m_type_name;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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
|
||||
{
|
||||
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()) {
|
||||
@ -86,17 +64,11 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
bool has_attr(const std::string &t_attr_name) const {
|
||||
return m_attrs.find(t_attr_name) != m_attrs.end();
|
||||
}
|
||||
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 &get_attr(const std::string &t_attr_name) { return m_attrs[t_attr_name]; }
|
||||
|
||||
Boxed_Value &method_missing(const std::string &t_method_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);
|
||||
}
|
||||
@ -104,8 +76,7 @@ namespace chaiscript
|
||||
return get_attr(t_method_name);
|
||||
}
|
||||
|
||||
const Boxed_Value &method_missing(const std::string &t_method_name) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -113,10 +84,7 @@ namespace chaiscript
|
||||
return get_attr(t_method_name);
|
||||
}
|
||||
|
||||
std::map<std::string, Boxed_Value> get_attrs() const
|
||||
{
|
||||
return m_attrs;
|
||||
}
|
||||
std::map<std::string, Boxed_Value> get_attrs() const { return m_attrs; }
|
||||
|
||||
private:
|
||||
const std::string m_type_name = "";
|
||||
@ -125,7 +93,6 @@ namespace chaiscript
|
||||
std::map<std::string, Boxed_Value> m_attrs;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace dispatch
|
||||
} // namespace chaiscript
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
|
||||
@ -19,118 +19,97 @@
|
||||
#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"
|
||||
#include "dynamic_object.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
namespace dispatch {
|
||||
class Proxy_Function_Base;
|
||||
} // namespace dispatch
|
||||
class Type_Conversions;
|
||||
namespace dispatch {
|
||||
class Proxy_Function_Base;
|
||||
} // namespace dispatch
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
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)
|
||||
Dynamic_Object_Function(std::string t_type_name, const Proxy_Function &t_func, const Type_Info &t_ti, bool t_is_attribute = false)
|
||||
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity())
|
||||
, m_type_name(std::move(t_type_name))
|
||||
, m_func(t_func)
|
||||
, m_ti(t_ti.is_undef() ? nullptr : new Type_Info(t_ti))
|
||||
, m_doti(user_type<Dynamic_Object>())
|
||||
, m_is_attribute(t_is_attribute) {
|
||||
assert((t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
|
||||
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
|
||||
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
|
||||
|
||||
bool operator==(const Proxy_Function_Base &f) const override
|
||||
{
|
||||
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
|
||||
{
|
||||
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 override { return m_is_attribute; }
|
||||
bool is_attribute_function() const noexcept override { return m_is_attribute; }
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
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};
|
||||
}
|
||||
std::vector<Const_Proxy_Function> get_contained_functions() const override { return {m_func}; }
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
Boxed_Value do_call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override {
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) {
|
||||
return (*m_func)(params, t_conversions);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
}
|
||||
|
||||
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
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)
|
||||
{
|
||||
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>()));
|
||||
// assert(types[1].bare_equal(user_type<Boxed_Value>()));
|
||||
types[1] = t_objectti;
|
||||
return types;
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (bv.get_type_info().bare_equal(m_doti))
|
||||
{
|
||||
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;
|
||||
@ -138,21 +117,19 @@ namespace chaiscript
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ti)
|
||||
{
|
||||
if (ti) {
|
||||
return bv.get_type_info().bare_equal(*ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (!bvs.empty())
|
||||
{
|
||||
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;
|
||||
@ -166,61 +143,52 @@ namespace chaiscript
|
||||
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
|
||||
{
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (begin != end) {
|
||||
++begin;
|
||||
}
|
||||
|
||||
return std::vector<Type_Info>(begin, end);
|
||||
}
|
||||
|
||||
bool operator==(const Proxy_Function_Base &f) const override
|
||||
{
|
||||
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
||||
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 std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
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(new_vals, t_conversions);
|
||||
return m_func->call_match(chaiscript::Function_Params{new_vals}, t_conversions);
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
Boxed_Value do_call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override {
|
||||
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
|
||||
std::vector<Boxed_Value> new_params{bv};
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
(*m_func)(new_params, t_conversions);
|
||||
(*m_func)(chaiscript::Function_Params{new_params}, t_conversions);
|
||||
|
||||
return bv;
|
||||
}
|
||||
@ -228,10 +196,8 @@ namespace chaiscript
|
||||
private:
|
||||
const std::string m_type_name;
|
||||
const Proxy_Function m_func;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace dispatch
|
||||
} // namespace chaiscript
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_EXCEPTION_SPECIFICATION_HPP_
|
||||
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||
|
||||
@ -17,39 +16,28 @@
|
||||
#include "boxed_cast.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Boxed_Value;
|
||||
namespace exception {
|
||||
class bad_boxed_cast;
|
||||
} // namespace exception
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Exception_Handler_Base
|
||||
{
|
||||
namespace detail {
|
||||
struct Exception_Handler_Base {
|
||||
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
|
||||
|
||||
virtual ~Exception_Handler_Base() = default;
|
||||
|
||||
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 &) {}
|
||||
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 &) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ... T>
|
||||
struct Exception_Handler_Impl : Exception_Handler_Base
|
||||
{
|
||||
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override
|
||||
{
|
||||
(void)std::initializer_list<int>{(throw_type<T>(bv, t_engine), 0)...};
|
||||
}
|
||||
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), ...); }
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
|
||||
///
|
||||
@ -61,7 +49,8 @@ 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) {
|
||||
@ -101,17 +90,14 @@ namespace chaiscript
|
||||
///
|
||||
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
|
||||
/// \sa \ref exceptions
|
||||
typedef std::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
|
||||
using Exception_Handler = std::shared_ptr<detail::Exception_Handler_Base>;
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename ... T>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
template<typename... T>
|
||||
Exception_Handler exception_specification() {
|
||||
return std::make_shared<detail::Exception_Handler_Impl<T...>>();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_FUNCTION_CALL_HPP_
|
||||
#define CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||
|
||||
@ -18,20 +17,25 @@
|
||||
#include "boxed_cast.hpp"
|
||||
#include "function_call_detail.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "callable_traits.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Boxed_Value;
|
||||
class Type_Conversions_State;
|
||||
namespace detail {
|
||||
template <typename T> struct Cast_Helper;
|
||||
} // namespace detail
|
||||
class Boxed_Value;
|
||||
class Type_Conversions_State;
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
struct Cast_Helper;
|
||||
} // namespace detail
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace chaiscript {
|
||||
namespace dispatch {
|
||||
namespace detail {
|
||||
template<typename Ret, typename... Param>
|
||||
constexpr auto arity(Ret (*)(Param...)) noexcept {
|
||||
return sizeof...(Param);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// Build a function caller that knows how to dispatch on a set of functions
|
||||
/// example:
|
||||
/// std::function<void (int)> f =
|
||||
@ -39,18 +43,16 @@ namespace chaiscript
|
||||
/// \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()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
|
||||
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>));
|
||||
}
|
||||
|
||||
FunctionType *p=nullptr;
|
||||
FunctionType *p = nullptr;
|
||||
return detail::build_function_caller_helper(p, funcs, t_conversions);
|
||||
}
|
||||
|
||||
@ -66,29 +68,24 @@ namespace chaiscript
|
||||
/// \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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/// 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, const Type_Conversions_State *t_conversions) {
|
||||
return functor<FunctionType>(boxed_cast<Const_Proxy_Function>(bv, t_conversions), t_conversions);
|
||||
}
|
||||
} // namespace dispatch
|
||||
|
||||
namespace detail{
|
||||
namespace detail {
|
||||
/// 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>()))
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
|
||||
@ -98,35 +95,28 @@ namespace chaiscript
|
||||
|
||||
/// 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>()))
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions);
|
||||
return Cast_Helper_Inner<std::function<Signature>>::cast(ob, t_conversions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// 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>()))
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions);
|
||||
return Cast_Helper_Inner<const std::function<Signature>>::cast(ob, t_conversions);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_FUNCTION_CALL_DETAIL_HPP_
|
||||
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||
|
||||
@ -20,131 +19,61 @@
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_number.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "type_conversions.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "type_conversions.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// Internal helper class for handling the return
|
||||
/// value of a build_function_caller
|
||||
template<typename Ret, bool is_arithmetic>
|
||||
struct Function_Caller_Ret
|
||||
{
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (t_conversions != nullptr) {
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions);
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, state), t_conversions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialization for arithmetic return types
|
||||
*/
|
||||
template<typename Ret>
|
||||
struct Function_Caller_Ret<Ret, true>
|
||||
{
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (t_conversions != nullptr) {
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>();
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, state)).get_as<Ret>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Specialization for void return types
|
||||
*/
|
||||
template<>
|
||||
struct Function_Caller_Ret<void, false>
|
||||
{
|
||||
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (t_conversions != nullptr) {
|
||||
dispatch::dispatch(t_funcs, params, *t_conversions);
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
dispatch::dispatch(t_funcs, params, state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* used internally for unwrapping a function call's types
|
||||
*/
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Build_Function_Caller_Helper
|
||||
{
|
||||
namespace chaiscript::dispatch::detail {
|
||||
/// 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)
|
||||
{
|
||||
: m_funcs(std::move(t_funcs))
|
||||
, m_conversions(t_conversions) {
|
||||
}
|
||||
|
||||
template<typename ... P>
|
||||
Ret operator()(P&& ... param)
|
||||
{
|
||||
Ret call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_state) {
|
||||
if constexpr (std::is_arithmetic_v<Ret> && !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Ret>>, bool>) {
|
||||
return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as<Ret>();
|
||||
} else if constexpr (std::is_same_v<void, Ret>) {
|
||||
dispatch::dispatch(m_funcs, params, t_state);
|
||||
} else {
|
||||
return boxed_cast<Ret>(dispatch::dispatch(m_funcs, params, t_state), &t_state);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... P>
|
||||
Ret operator()(P &&...param) {
|
||||
std::array<Boxed_Value, sizeof...(P)> params{box<P>(std::forward<P>(param))...};
|
||||
|
||||
if (m_conversions) {
|
||||
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
|
||||
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||
box<P>(std::forward<P>(param))...
|
||||
}, &state
|
||||
);
|
||||
return call(chaiscript::Function_Params{params}, state);
|
||||
} else {
|
||||
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||
box<P>(std::forward<P>(param))...
|
||||
}, nullptr
|
||||
);
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return call(chaiscript::Function_Params{params}, state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
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)));
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<!std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
} else {
|
||||
return Boxed_Value(std::forward<Q>(q));
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
static Boxed_Value box(Boxed_Value bv)
|
||||
{
|
||||
return bv;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Const_Proxy_Function> m_funcs;
|
||||
const Type_Conversions *m_conversions;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// \todo what happens if t_conversions is deleted out from under us?!
|
||||
template<typename Ret, typename ... Params>
|
||||
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
template<typename Ret, typename... Params>
|
||||
std::function<Ret(Params...)>
|
||||
build_function_caller_helper(Ret(Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
|
||||
/*
|
||||
if (funcs.size() == 1)
|
||||
{
|
||||
@ -159,13 +88,10 @@ namespace chaiscript
|
||||
// looks like this either wasn't a Proxy_Function_Impl or the types didn't match
|
||||
// we cannot make any other guesses or assumptions really, so continuing
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?t_conversions->get():nullptr));
|
||||
return std::function<Ret(Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions ? t_conversions->get() : nullptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace chaiscript::dispatch::detail
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
67
include/chaiscript/dispatchkit/function_params.hpp
Normal file
67
include/chaiscript/dispatchkit/function_params.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
// 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
|
||||
149
include/chaiscript/dispatchkit/function_signature.hpp
Normal file
149
include/chaiscript/dispatchkit/function_signature.hpp
Normal file
@ -0,0 +1,149 @@
|
||||
#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
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_HANDLE_RETURN_HPP_
|
||||
#define CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||
|
||||
@ -19,238 +18,178 @@
|
||||
#include "boxed_value.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Boxed_Number;
|
||||
class Boxed_Number;
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
template<class T, class U> class Proxy_Function_Callable_Impl;
|
||||
template<class T> class Assignable_Proxy_Function_Impl;
|
||||
namespace chaiscript {
|
||||
namespace dispatch {
|
||||
template<class T, class U>
|
||||
class Proxy_Function_Callable_Impl;
|
||||
template<class T>
|
||||
class Assignable_Proxy_Function_Impl;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
/// Used internally for handling a return value from a Proxy_Function call
|
||||
template<typename Ret>
|
||||
struct Handle_Return
|
||||
{
|
||||
template<typename T,
|
||||
typename = typename std::enable_if<std::is_pod<typename std::decay<T>::type>::value>::type>
|
||||
static Boxed_Value handle(T r)
|
||||
{
|
||||
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<!std::is_pod<typename std::decay<T>::type>::value>::type>
|
||||
static Boxed_Value handle(T &&r)
|
||||
{
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const std::function<Ret> &>
|
||||
{
|
||||
struct Handle_Return<const std::function<Ret> &> {
|
||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<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>>>
|
||||
{
|
||||
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)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f), f));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>>
|
||||
{
|
||||
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>>>
|
||||
{
|
||||
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> &>
|
||||
{
|
||||
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>>())
|
||||
);
|
||||
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)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret *&>
|
||||
{
|
||||
static Boxed_Value handle(Ret *p)
|
||||
{
|
||||
return Boxed_Value(p, true);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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> &>
|
||||
{
|
||||
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> &>
|
||||
{
|
||||
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);
|
||||
}
|
||||
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &> {
|
||||
static Boxed_Value handle(std::unique_ptr<Ret> &&r) { return Boxed_Value(std::move(r), true); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret &>
|
||||
{
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
template<typename Ret, bool Ptr>
|
||||
struct Handle_Return_Ref {
|
||||
template<typename T>
|
||||
static Boxed_Value handle(T &&r) {
|
||||
return Boxed_Value(std::cref(r), true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret>
|
||||
{
|
||||
static Boxed_Value handle(Ret r)
|
||||
{
|
||||
return Boxed_Value(std::move(r));
|
||||
struct Handle_Return_Ref<Ret, true> {
|
||||
template<typename T>
|
||||
static Boxed_Value handle(T &&r) {
|
||||
return Boxed_Value(typename std::remove_reference<decltype(r)>::type{r}, true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret &>
|
||||
{
|
||||
static Boxed_Value handle(Ret &r)
|
||||
{
|
||||
return Boxed_Value(std::ref(r));
|
||||
}
|
||||
struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> {
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret> {
|
||||
static Boxed_Value handle(Ret r) { return Boxed_Value(std::move(r)); }
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret &> {
|
||||
static Boxed_Value handle(Ret &r) { return Boxed_Value(std::ref(r)); }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Handle_Return<Boxed_Value>
|
||||
{
|
||||
static Boxed_Value handle(const Boxed_Value &r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
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>
|
||||
{
|
||||
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> {
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value>
|
||||
{
|
||||
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> {
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value>
|
||||
{
|
||||
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value> {
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
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<const Boxed_Number> : Handle_Return<Boxed_Number> {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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<void> {
|
||||
static Boxed_Value handle() { return void_var(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace dispatch
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,224 +1,184 @@
|
||||
// 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)
|
||||
// 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_OPERATORS_HPP_
|
||||
#define CHAISCRIPT_OPERATORS_HPP_
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "../dispatchkit/dispatchkit.hpp"
|
||||
#include "register_function.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace bootstrap
|
||||
{
|
||||
namespace operators
|
||||
{
|
||||
namespace chaiscript::bootstrap::operators {
|
||||
template<typename T>
|
||||
void assign(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "=");
|
||||
void assign(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs = rhs; }), "=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_bitwise_and(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&=");
|
||||
void assign_bitwise_and(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs &= rhs; }), "&=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_xor(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^=");
|
||||
void assign_xor(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs ^= rhs; }), "^=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_bitwise_or(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|=");
|
||||
void assign_bitwise_or(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs |= rhs; }), "|=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_difference(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-=");
|
||||
void assign_difference(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs -= rhs; }), "-=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_left_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<=");
|
||||
void assign_left_shift(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "<<=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_product(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*=");
|
||||
void assign_product(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "*=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_quotient(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/=");
|
||||
void assign_quotient(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs /= rhs; }), "/=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_remainder(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%=");
|
||||
void assign_remainder(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs %= rhs; }), "%=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_right_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>=");
|
||||
void assign_right_shift(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs >>= rhs; }), ">>=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_sum(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+=");
|
||||
void assign_sum(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs += rhs; }), "+=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void prefix_decrement(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--");
|
||||
void prefix_decrement(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs) -> T & { return --lhs; }), "--");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void prefix_increment(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++");
|
||||
void prefix_increment(Module &m) {
|
||||
m.add(chaiscript::fun([](T &lhs) -> T & { return ++lhs; }), "++");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "==");
|
||||
void equal(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs == rhs; }), "==");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void greater_than(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">");
|
||||
void greater_than(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs > rhs; }), ">");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void greater_than_equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">=");
|
||||
void greater_than_equal(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >= rhs; }), ">=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void less_than(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<");
|
||||
void less_than(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs < rhs; }), "<");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void less_than_equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<=");
|
||||
void less_than_equal(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs <= rhs; }), "<=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void logical_compliment(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!");
|
||||
void logical_compliment(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs) { return !lhs; }), "!");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void not_equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!=");
|
||||
void not_equal(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs != rhs; }), "!=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void addition(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+");
|
||||
void addition(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs + rhs; }), "+");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void unary_plus(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+");
|
||||
void unary_plus(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs) { return +lhs; }), "+");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void subtraction(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-");
|
||||
void subtraction(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs - rhs; }), "-");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void unary_minus(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-");
|
||||
void unary_minus(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs) { return -lhs; }), "-");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_and(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&");
|
||||
void bitwise_and(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs & rhs; }), "&");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_compliment(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~");
|
||||
void bitwise_compliment(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs) { return ~lhs; }), "~");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_xor(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^");
|
||||
void bitwise_xor(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs ^ rhs; }), "^");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_or(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|");
|
||||
void bitwise_or(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs | rhs; }), "|");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void division(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/");
|
||||
void division(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs / rhs; }), "/");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void left_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<");
|
||||
void left_shift(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs << rhs; }), "<<");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void multiplication(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*");
|
||||
void multiplication(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs * rhs; }), "*");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void remainder(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%");
|
||||
void remainder(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs % rhs; }), "%");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void right_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>");
|
||||
void right_shift(Module &m) {
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >> rhs; }), ">>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace chaiscript::bootstrap::operators
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,37 +1,37 @@
|
||||
// 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)
|
||||
// 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_PROXY_CONSTRUCTORS_HPP_
|
||||
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||
|
||||
#include "proxy_functions.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename Class, typename ... Params >
|
||||
Proxy_Function build_constructor_(Class (*)(Params...))
|
||||
{
|
||||
auto call = dispatch::detail::Constructor<Class, Params...>();
|
||||
namespace chaiscript::dispatch::detail {
|
||||
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)...); };
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
|
||||
}
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
} // 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,13 +44,10 @@ namespace chaiscript
|
||||
/// chai.add(constructor<MyClass (int, float)>(), "MyClass");
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
Proxy_Function constructor()
|
||||
{
|
||||
Proxy_Function constructor() {
|
||||
T *f = nullptr;
|
||||
return (dispatch::detail::build_constructor_(f));
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,49 +1,45 @@
|
||||
// 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)
|
||||
// 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_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "function_params.hpp"
|
||||
#include "handle_return.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "callable_traits.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions_State;
|
||||
namespace exception {
|
||||
class bad_boxed_cast;
|
||||
} // namespace exception
|
||||
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;
|
||||
@ -53,87 +49,63 @@ namespace chaiscript
|
||||
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...))
|
||||
{
|
||||
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>()... };
|
||||
return {user_type<Ret>(), user_type<Params>()...};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
||||
* Proxy_Function_Impl object. This function is primarily used to prevent
|
||||
* registration of two functions with the exact same signatures
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
bool compare_types_cast(Ret (*)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
template<typename Ret, typename... Params>
|
||||
bool compare_types_cast(Ret (*)(Params...), const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) noexcept {
|
||||
try {
|
||||
std::vector<Boxed_Value>::size_type i = 0;
|
||||
(void)i;
|
||||
(void)params; (void)t_conversions;
|
||||
// this is ok because the order of evaluation of initializer lists is well defined
|
||||
(void)std::initializer_list<int>{(boxed_cast<Params>(params[i++], &t_conversions), 0)...};
|
||||
(boxed_cast<Params>(params[i++], &t_conversions), ...);
|
||||
return true;
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &,
|
||||
std::index_sequence<I...>, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
(void)params; (void)t_conversions;
|
||||
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 ¶ms,
|
||||
[[maybe_unused]] const Type_Conversions_State &t_conversions) {
|
||||
return f(boxed_cast<Params>(params[I], &t_conversions)...);
|
||||
}
|
||||
|
||||
|
||||
/// Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||
/// The function attempts to unbox each parameter to the expected type.
|
||||
/// if any unboxing fails the execution of the function fails and
|
||||
/// the bad_boxed_cast is passed up to the caller.
|
||||
template<typename Callable, typename Ret, typename ... Params>
|
||||
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
template<typename Callable, typename Ret, typename... Params>
|
||||
Boxed_Value
|
||||
call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params ¶ms, 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);
|
||||
return Handle_Return<void>::handle();
|
||||
} else {
|
||||
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
|
||||
}
|
||||
|
||||
template<typename Callable, typename ... Params>
|
||||
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<void (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4702)
|
||||
#endif
|
||||
// MSVC is reporting that this is unreachable code - and it's wrong.
|
||||
return Handle_Return<void>::handle();
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace dispatch
|
||||
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,23 +1,61 @@
|
||||
// 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)
|
||||
// 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_REGISTER_FUNCTION_HPP_
|
||||
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "bind_first.hpp"
|
||||
#include "function_signature.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace chaiscript {
|
||||
namespace dispatch::detail {
|
||||
template<typename Obj, typename Param1, typename... Rest>
|
||||
Param1 get_first_param(Function_Params<Param1, Rest...>, Obj &&obj) {
|
||||
return static_cast<Param1>(std::forward<Obj>(obj));
|
||||
}
|
||||
|
||||
template<typename Func, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject, bool Is_Object, typename Ret, typename... Param>
|
||||
auto make_callable_impl(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) {
|
||||
if constexpr (Is_MemberObject) {
|
||||
// we now that the Param pack will have only one element, so we are safe expanding it here
|
||||
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<Ret, std::decay_t<Param>...>>(
|
||||
std::forward<Func>(func)));
|
||||
} else if constexpr (Is_Member) {
|
||||
// TODO some kind of bug is preventing forwarding of this noexcept for the lambda
|
||||
auto call = [func = std::forward<Func>(func)](auto &&obj, auto &&...param) /* noexcept(Is_Noexcept) */ -> decltype(auto) {
|
||||
return ((get_first_param(Function_Params<Param...>{}, obj).*func)(std::forward<decltype(param)>(param)...));
|
||||
};
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), decltype(call)>>(
|
||||
std::move(call)));
|
||||
} else {
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), std::decay_t<Func>>>(
|
||||
std::forward<Func>(func)));
|
||||
}
|
||||
}
|
||||
|
||||
// this version peels off the function object itself from the function signature, when used
|
||||
// on a callable object
|
||||
template<typename Func, typename Ret, typename Object, typename... Param, bool Is_Noexcept>
|
||||
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Object, Param...>, Is_Noexcept, false, false, true>) {
|
||||
return make_callable_impl(std::forward<Func>(func), Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, false, false, true>{});
|
||||
}
|
||||
|
||||
template<typename Func, typename Ret, typename... Param, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject>
|
||||
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) {
|
||||
return make_callable_impl(std::forward<Func>(func), fs);
|
||||
}
|
||||
} // namespace dispatch::detail
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
|
||||
/// \param[in] t Function / member to expose
|
||||
@ -40,86 +78,10 @@ namespace chaiscript
|
||||
///
|
||||
/// \sa \ref adding_functions
|
||||
template<typename T>
|
||||
Proxy_Function fun(const T &t)
|
||||
{
|
||||
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
|
||||
Proxy_Function fun(T &&t) {
|
||||
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t));
|
||||
}
|
||||
|
||||
|
||||
template<typename Ret, typename ... Param>
|
||||
Proxy_Function fun(Ret (*func)(Param...))
|
||||
{
|
||||
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
|
||||
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...) const)
|
||||
{
|
||||
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...))
|
||||
{
|
||||
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
|
||||
|
||||
}
|
||||
|
||||
template<typename T, typename Class /*, typename = typename std::enable_if<std::is_member_object_pointer<T>::value>::type*/>
|
||||
Proxy_Function fun(T Class::* m /*, typename std::enable_if<std::is_member_object_pointer<T>::value>::type* = 0*/ )
|
||||
{
|
||||
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<T, Class>>(m));
|
||||
}
|
||||
|
||||
// only compile this bit if noexcept is part of the type system
|
||||
//
|
||||
#if (defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510) || (defined(_NOEXCEPT_TYPES_SUPPORTED) && _MSC_VER >= 1912)
|
||||
template<typename Ret, typename ... Param>
|
||||
Proxy_Function fun(Ret (*func)(Param...) noexcept)
|
||||
{
|
||||
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
|
||||
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...) const noexcept)
|
||||
{
|
||||
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...) noexcept)
|
||||
{
|
||||
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
|
||||
/// \param[in] t Function / member to expose
|
||||
/// \param[in] q Value to bind to first parameter
|
||||
@ -139,14 +101,10 @@ namespace chaiscript
|
||||
///
|
||||
/// \sa \ref adding_functions
|
||||
template<typename T, typename Q>
|
||||
Proxy_Function fun(T &&t, const Q &q)
|
||||
{
|
||||
Proxy_Function fun(T &&t, const Q &q) {
|
||||
return fun(detail::bind_first(std::forward<T>(t), q));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -23,80 +23,70 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
template <std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
|
||||
class arena
|
||||
{
|
||||
template<std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
|
||||
class arena {
|
||||
alignas(alignment) char buf_[N];
|
||||
char* ptr_;
|
||||
char *ptr_;
|
||||
|
||||
public:
|
||||
~arena() {ptr_ = nullptr;}
|
||||
arena() noexcept : ptr_(buf_) {}
|
||||
arena(const arena&) = delete;
|
||||
arena& operator=(const arena&) = delete;
|
||||
~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;
|
||||
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_;}
|
||||
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);}
|
||||
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;}
|
||||
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)
|
||||
{
|
||||
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_;
|
||||
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 "
|
||||
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));
|
||||
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
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (pointer_in_buffer(p)) {
|
||||
n = align_up(n);
|
||||
if (p + n == ptr_) {
|
||||
ptr_ = p;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
::operator delete(p);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
|
||||
class short_alloc
|
||||
{
|
||||
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;
|
||||
@ -104,56 +94,44 @@ public:
|
||||
using arena_type = arena<size, alignment>;
|
||||
|
||||
private:
|
||||
arena_type& a_;
|
||||
arena_type &a_;
|
||||
|
||||
public:
|
||||
short_alloc(const short_alloc&) = default;
|
||||
short_alloc& operator=(const short_alloc&) = delete;
|
||||
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");
|
||||
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 U>
|
||||
explicit short_alloc(const short_alloc<U, N, alignment> &a) noexcept
|
||||
: a_(a.a_) {
|
||||
}
|
||||
|
||||
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 _Up>
|
||||
struct rebind {
|
||||
using other = short_alloc<_Up, N, alignment>;
|
||||
};
|
||||
|
||||
template <class U, std::size_t M, std::size_t A> friend class short_alloc;
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
@ -1,16 +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-2017, Jason Turner (jason@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>
|
||||
@ -20,32 +20,37 @@
|
||||
#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
|
||||
{
|
||||
class bad_boxed_dynamic_cast : public bad_boxed_cast
|
||||
{
|
||||
namespace chaiscript {
|
||||
namespace exception {
|
||||
/// \brief Error thrown when there's a problem with type conversion
|
||||
class conversion_error : 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
: bad_boxed_cast(t_from, t_to) {
|
||||
}
|
||||
|
||||
explicit bad_boxed_dynamic_cast(const std::string &w) noexcept
|
||||
: bad_boxed_cast(w)
|
||||
{
|
||||
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;
|
||||
@ -53,108 +58,78 @@ namespace chaiscript
|
||||
~bad_boxed_dynamic_cast() noexcept override = default;
|
||||
};
|
||||
|
||||
class bad_boxed_type_cast : public bad_boxed_cast
|
||||
{
|
||||
class bad_boxed_type_cast : public bad_boxed_cast {
|
||||
public:
|
||||
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
|
||||
const std::string &t_what) noexcept
|
||||
: bad_boxed_cast(t_from, t_to, t_what)
|
||||
{
|
||||
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, 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)
|
||||
{
|
||||
: bad_boxed_cast(t_from, t_to) {
|
||||
}
|
||||
|
||||
explicit bad_boxed_type_cast(const std::string &w) noexcept
|
||||
: bad_boxed_cast(w)
|
||||
{
|
||||
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
|
||||
{
|
||||
namespace detail {
|
||||
class Type_Conversion_Base {
|
||||
public:
|
||||
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
|
||||
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
|
||||
|
||||
const Type_Info &to() const
|
||||
{
|
||||
return m_to;
|
||||
}
|
||||
const Type_Info &from() const
|
||||
{
|
||||
return m_from;
|
||||
}
|
||||
const Type_Info &to() const noexcept { return m_to; }
|
||||
const Type_Info &from() const noexcept { return m_from; }
|
||||
|
||||
virtual bool bidir() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
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))
|
||||
{
|
||||
: 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
|
||||
{
|
||||
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())
|
||||
{
|
||||
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)))
|
||||
{
|
||||
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 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())
|
||||
{
|
||||
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));
|
||||
@ -168,44 +143,33 @@ namespace chaiscript
|
||||
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
|
||||
{
|
||||
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())
|
||||
{
|
||||
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)))
|
||||
{
|
||||
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 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);
|
||||
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);
|
||||
}
|
||||
@ -213,13 +177,11 @@ namespace chaiscript
|
||||
#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())
|
||||
{
|
||||
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));
|
||||
@ -233,126 +195,91 @@ namespace chaiscript
|
||||
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
|
||||
{
|
||||
class Dynamic_Conversion_Impl : public Type_Conversion_Base {
|
||||
public:
|
||||
Dynamic_Conversion_Impl()
|
||||
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
|
||||
{
|
||||
: 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_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);
|
||||
}
|
||||
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
|
||||
{
|
||||
class Static_Conversion_Impl : public Type_Conversion_Base {
|
||||
public:
|
||||
Static_Conversion_Impl()
|
||||
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
|
||||
{
|
||||
: 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),
|
||||
Boxed_Value convert_down(const Boxed_Value &t_base) const override {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(),
|
||||
typeid(Derived),
|
||||
"Unable to cast down inheritance hierarchy with non-polymorphic types");
|
||||
}
|
||||
|
||||
bool bidir() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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
|
||||
{
|
||||
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))
|
||||
{
|
||||
: Type_Conversion_Base(t_to, t_from)
|
||||
, m_func(std::move(t_func)) {
|
||||
}
|
||||
|
||||
Boxed_Value convert_down(const Boxed_Value &) const override
|
||||
{
|
||||
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
|
||||
{
|
||||
Boxed_Value convert(const Boxed_Value &t_from) const override {
|
||||
/// \todo better handling of errors from the conversion function
|
||||
return m_func(t_from);
|
||||
}
|
||||
|
||||
bool bidir() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bidir() const noexcept override { return false; }
|
||||
|
||||
private:
|
||||
Callable m_func;
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
class Type_Conversions
|
||||
{
|
||||
class Type_Conversions {
|
||||
public:
|
||||
struct Conversion_Saves
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
: m_mutex()
|
||||
, m_conversions()
|
||||
, m_convertableTypes()
|
||||
, m_num_types(0) {
|
||||
}
|
||||
|
||||
Type_Conversions(const Type_Conversions &t_other) = delete;
|
||||
Type_Conversions(Type_Conversions &&) = default;
|
||||
Type_Conversions(Type_Conversions &&) = delete;
|
||||
|
||||
Type_Conversions &operator=(const Type_Conversions &) = delete;
|
||||
Type_Conversions &operator=(Type_Conversions &&) = default;
|
||||
Type_Conversions &operator=(Type_Conversions &&) = delete;
|
||||
|
||||
const std::set<const std::type_info *, Less_Than> &thread_cache() const
|
||||
{
|
||||
const std::set<const std::type_info *, Less_Than> &thread_cache() const {
|
||||
auto &cache = *m_thread_cache;
|
||||
if (cache.size() != m_num_types)
|
||||
{
|
||||
if (cache.size() != m_num_types) {
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
cache = m_convertableTypes;
|
||||
}
|
||||
@ -360,32 +287,30 @@ namespace chaiscript
|
||||
return cache;
|
||||
}
|
||||
|
||||
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
|
||||
{
|
||||
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
/// \todo error if a conversion already exists
|
||||
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
|
||||
{
|
||||
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
|
||||
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
|
||||
{
|
||||
bool converts() const noexcept {
|
||||
return converts(user_type<To>(), user_type<From>());
|
||||
}
|
||||
|
||||
bool converts(const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) {
|
||||
return has_conversion(to, from);
|
||||
} else {
|
||||
return false;
|
||||
@ -393,23 +318,21 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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); }
|
||||
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");
|
||||
@ -418,11 +341,12 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const
|
||||
{
|
||||
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); }
|
||||
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");
|
||||
@ -431,75 +355,57 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val)
|
||||
{
|
||||
t_saves.enabled = t_val;
|
||||
}
|
||||
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> 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
|
||||
{
|
||||
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
|
||||
{
|
||||
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())
|
||||
{
|
||||
if (itr != m_conversions.end()) {
|
||||
return *itr;
|
||||
} else {
|
||||
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
|
||||
throw std::out_of_range(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name());
|
||||
}
|
||||
}
|
||||
|
||||
Conversion_Saves &conversion_saves() const {
|
||||
return *m_conversion_saves;
|
||||
}
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
@ -508,34 +414,25 @@ namespace chaiscript
|
||||
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
|
||||
};
|
||||
|
||||
class Type_Conversions_State
|
||||
{
|
||||
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)
|
||||
{
|
||||
Type_Conversions_State(const Type_Conversions &t_conversions, Type_Conversions::Conversion_Saves &t_saves)
|
||||
: m_conversions(t_conversions)
|
||||
, m_saves(t_saves) {
|
||||
}
|
||||
|
||||
const Type_Conversions *operator->() const {
|
||||
return &m_conversions.get();
|
||||
}
|
||||
const Type_Conversions *operator->() const noexcept { return &m_conversions.get(); }
|
||||
|
||||
const Type_Conversions *get() const {
|
||||
return &m_conversions.get();
|
||||
}
|
||||
const Type_Conversions *get() const noexcept { return &m_conversions.get(); }
|
||||
|
||||
Type_Conversions::Conversion_Saves &saves() const {
|
||||
return m_saves;
|
||||
}
|
||||
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;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
|
||||
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.
|
||||
@ -559,59 +456,50 @@ namespace chaiscript
|
||||
/// \endcode
|
||||
///
|
||||
template<typename Base, typename Derived>
|
||||
Type_Conversion base_class(typename std::enable_if<std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||
{
|
||||
//Can only be used with related polymorphic types
|
||||
//may be expanded some day to support conversions other than child -> parent
|
||||
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
||||
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>>();
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
Type_Conversion base_class(typename std::enable_if<!std::is_polymorphic<Base>::value || !std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||
{
|
||||
//Can only be used with related polymorphic types
|
||||
//may be expanded some day to support conversions other than child -> parent
|
||||
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
||||
|
||||
} 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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()
|
||||
{
|
||||
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);
|
||||
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()
|
||||
{
|
||||
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);
|
||||
|
||||
@ -624,26 +512,28 @@ namespace chaiscript
|
||||
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);
|
||||
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()
|
||||
{
|
||||
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);
|
||||
const std::map<std::string, Boxed_Value> &from_map
|
||||
= detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
|
||||
|
||||
To map;
|
||||
for (const std::pair<std::string, Boxed_Value> &p : from_map) {
|
||||
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);
|
||||
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
|
||||
|
||||
@ -1,87 +1,64 @@
|
||||
// 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)
|
||||
// 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_TYPE_INFO_HPP_
|
||||
#define CHAISCRIPT_TYPE_INFO_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <string>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace chaiscript {
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
struct Bare_Type
|
||||
{
|
||||
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
|
||||
struct Bare_Type {
|
||||
using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::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)
|
||||
: 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))
|
||||
{
|
||||
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)) {
|
||||
}
|
||||
|
||||
constexpr Type_Info() = default;
|
||||
constexpr Type_Info() noexcept = default;
|
||||
|
||||
bool operator<(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return m_type_info->before(*ti.m_type_info);
|
||||
bool operator<(const Type_Info &ti) const noexcept { return m_type_info->before(*ti.m_type_info); }
|
||||
|
||||
constexpr bool operator!=(const Type_Info &ti) const noexcept { return !(operator==(ti)); }
|
||||
|
||||
constexpr bool operator!=(const std::type_info &ti) const noexcept { return !(operator==(ti)); }
|
||||
|
||||
constexpr bool operator==(const Type_Info &ti) const noexcept {
|
||||
return ti.m_type_info == m_type_info || *ti.m_type_info == *m_type_info;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return !(operator==(ti));
|
||||
constexpr bool operator==(const std::type_info &ti) const noexcept { return !is_undef() && (*m_type_info) == ti; }
|
||||
|
||||
constexpr bool bare_equal(const Type_Info &ti) const noexcept {
|
||||
return ti.m_bare_type_info == m_bare_type_info || *ti.m_bare_type_info == *m_bare_type_info;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const std::type_info &ti) const noexcept
|
||||
{
|
||||
return !(operator==(ti));
|
||||
}
|
||||
|
||||
constexpr bool operator==(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return ti.m_type_info == m_type_info
|
||||
|| *ti.m_type_info == *m_type_info;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const std::type_info &ti) const noexcept
|
||||
{
|
||||
return !is_undef() && (*m_type_info) == ti;
|
||||
}
|
||||
|
||||
constexpr bool bare_equal(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return ti.m_bare_type_info == m_bare_type_info
|
||||
|| *ti.m_bare_type_info == *m_bare_type_info;
|
||||
}
|
||||
|
||||
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept
|
||||
{
|
||||
return !is_undef() && (*m_bare_type_info) == ti;
|
||||
}
|
||||
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept { return !is_undef() && (*m_bare_type_info) == ti; }
|
||||
|
||||
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; }
|
||||
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; }
|
||||
@ -90,33 +67,27 @@ namespace chaiscript
|
||||
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; }
|
||||
|
||||
std::string name() const
|
||||
{
|
||||
if (!is_undef())
|
||||
{
|
||||
const char *name() const noexcept {
|
||||
if (!is_undef()) {
|
||||
return m_type_info->name();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string bare_name() const
|
||||
{
|
||||
if (!is_undef())
|
||||
{
|
||||
const char *bare_name() const noexcept {
|
||||
if (!is_undef()) {
|
||||
return m_bare_type_info->name();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const std::type_info *bare_type_info() const
|
||||
{
|
||||
return m_bare_type_info;
|
||||
}
|
||||
constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; }
|
||||
|
||||
private:
|
||||
struct Unknown_Type {};
|
||||
struct Unknown_Type {
|
||||
};
|
||||
|
||||
const std::type_info *m_type_info = &typeid(Unknown_Type);
|
||||
const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
|
||||
@ -129,16 +100,14 @@ namespace chaiscript
|
||||
unsigned int m_flags = (1 << is_undef_flag);
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
/// Helper used to create a Type_Info object
|
||||
template<typename T>
|
||||
struct Get_Type_Info
|
||||
{
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
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,
|
||||
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,
|
||||
@ -148,65 +117,66 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<std::shared_ptr<T> >
|
||||
{
|
||||
// typedef T type;
|
||||
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
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>> {
|
||||
constexpr static Type_Info get() noexcept {
|
||||
return Type_Info(std::is_const<T>::value,
|
||||
std::is_reference<T>::value,
|
||||
std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(std::shared_ptr<T> ),
|
||||
std::is_arithmetic<T>::value
|
||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(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<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>> {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::shared_ptr<T> &>
|
||||
{
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
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,
|
||||
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<typename std::remove_reference<T>::type>::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> >
|
||||
{
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
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>> {
|
||||
constexpr static Type_Info get() noexcept {
|
||||
return Type_Info(std::is_const<T>::value,
|
||||
std::is_reference<T>::value,
|
||||
std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(std::reference_wrapper<T> ),
|
||||
std::is_arithmetic<T>::value
|
||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(std::reference_wrapper<T>),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::reference_wrapper<T> &>
|
||||
{
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
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> &> {
|
||||
constexpr static Type_Info get() noexcept {
|
||||
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<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(const std::reference_wrapper<T> &),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// \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
|
||||
@ -218,12 +188,10 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
constexpr Type_Info user_type(const T &/*t*/)
|
||||
{
|
||||
constexpr Type_Info user_type(const T & /*t*/) noexcept {
|
||||
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
|
||||
@ -233,12 +201,10 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
constexpr Type_Info user_type()
|
||||
{
|
||||
constexpr Type_Info user_type() noexcept {
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,108 +1,167 @@
|
||||
// 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)
|
||||
// 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_ALGEBRAIC_HPP_
|
||||
#define CHAISCRIPT_ALGEBRAIC_HPP_
|
||||
|
||||
#include "../utility/fnv1a.hpp"
|
||||
#include "../utility/hash.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
namespace chaiscript {
|
||||
struct Operators {
|
||||
enum class 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,
|
||||
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,
|
||||
invalid
|
||||
};
|
||||
|
||||
static const char *to_string(Opers t_oper) {
|
||||
static const char *opers[] = {
|
||||
"",
|
||||
"==", "<", ">", "<=", ">=", "!=",
|
||||
"",
|
||||
"=", "++", "--", "*=", "+=",
|
||||
"/=", "-=",
|
||||
"",
|
||||
"&=", "|=", "<<=", ">>=",
|
||||
"%=", "^=",
|
||||
"",
|
||||
"<<", ">>", "%", "&", "|", "^", "~",
|
||||
"",
|
||||
"+", "/", "*", "-", "+", "-",
|
||||
""
|
||||
};
|
||||
constexpr static const char *to_string(Opers t_oper) noexcept {
|
||||
constexpr const char *opers[]
|
||||
= {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""};
|
||||
return opers[static_cast<int>(t_oper)];
|
||||
}
|
||||
|
||||
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
|
||||
{
|
||||
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::fnv1a_32(t_str.c_str());
|
||||
const auto op_hash = utility::hash(t_str);
|
||||
switch (op_hash) {
|
||||
case utility::fnv1a_32("=="): { return Opers::equals; }
|
||||
case utility::fnv1a_32("<"): { return Opers::less_than; }
|
||||
case utility::fnv1a_32(">"): { return Opers::greater_than; }
|
||||
case utility::fnv1a_32("<="): { return Opers::less_than_equal; }
|
||||
case utility::fnv1a_32(">="): { return Opers::greater_than_equal; }
|
||||
case utility::fnv1a_32("!="): { return Opers::not_equal; }
|
||||
case utility::fnv1a_32("="): { return Opers::assign; }
|
||||
case utility::fnv1a_32("++"): { return Opers::pre_increment; }
|
||||
case utility::fnv1a_32("--"): { return Opers::pre_decrement; }
|
||||
case utility::fnv1a_32("*="): { return Opers::assign_product; }
|
||||
case utility::fnv1a_32("+="): { return Opers::assign_sum; }
|
||||
case utility::fnv1a_32("-="): { return Opers::assign_difference; }
|
||||
case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; }
|
||||
case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; }
|
||||
case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; }
|
||||
case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; }
|
||||
case utility::fnv1a_32("%="): { return Opers::assign_remainder; }
|
||||
case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; }
|
||||
case utility::fnv1a_32("<<"): { return Opers::shift_left; }
|
||||
case utility::fnv1a_32(">>"): { return Opers::shift_right; }
|
||||
case utility::fnv1a_32("%"): { return Opers::remainder; }
|
||||
case utility::fnv1a_32("&"): { return Opers::bitwise_and; }
|
||||
case utility::fnv1a_32("|"): { return Opers::bitwise_or; }
|
||||
case utility::fnv1a_32("^"): { return Opers::bitwise_xor; }
|
||||
case utility::fnv1a_32("~"): { return Opers::bitwise_complement; }
|
||||
case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; }
|
||||
case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; }
|
||||
case utility::fnv1a_32("/"): { return Opers::quotient; }
|
||||
case utility::fnv1a_32("*"): { return Opers::product; }
|
||||
default: { return Opers::invalid; }
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */
|
||||
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_COMMON_HPP_
|
||||
#define CHAISCRIPT_COMMON_HPP_
|
||||
|
||||
@ -23,134 +22,172 @@
|
||||
#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;
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace chaiscript {
|
||||
struct Name_Validator {
|
||||
static bool is_reserved_word(const std::string &name)
|
||||
{
|
||||
static const std::set<std::string> m_reserved_words
|
||||
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
|
||||
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_",
|
||||
"__LINE__", "__FILE__", "__FUNC__", "__CLASS__"};
|
||||
return m_reserved_words.count(name) > 0;
|
||||
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;
|
||||
}
|
||||
|
||||
static bool valid_object_name(const std::string &name)
|
||||
{
|
||||
template<typename T>
|
||||
static bool valid_object_name(const T &name) noexcept {
|
||||
return name.find("::") == std::string::npos && !is_reserved_word(name);
|
||||
}
|
||||
|
||||
static void validate_object_name(const std::string &name)
|
||||
{
|
||||
template<typename T>
|
||||
static void validate_object_name(const T &name) {
|
||||
if (is_reserved_word(name)) {
|
||||
throw exception::reserved_word_error(name);
|
||||
throw exception::reserved_word_error(std::string(name));
|
||||
}
|
||||
|
||||
if (name.find("::") != std::string::npos) {
|
||||
throw exception::illegal_name_error(name);
|
||||
throw exception::illegal_name_error(std::string(name));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Signature of module entry point that all binary loadable modules must implement.
|
||||
typedef ModulePtr (*Create_Module_Func)();
|
||||
|
||||
using Create_Module_Func = ModulePtr (*)();
|
||||
|
||||
/// 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
|
||||
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
|
||||
};
|
||||
|
||||
enum class Operator_Precidence { Ternary_Cond, Logical_Or,
|
||||
Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And,
|
||||
Equality, Comparison, Shift, Addition, Multiplication, Prefix };
|
||||
enum class Operator_Precedence {
|
||||
Ternary_Cond,
|
||||
Logical_Or,
|
||||
Logical_And,
|
||||
Bitwise_Or,
|
||||
Bitwise_Xor,
|
||||
Bitwise_And,
|
||||
Equality,
|
||||
Comparison,
|
||||
Shift,
|
||||
Addition,
|
||||
Multiplication,
|
||||
Prefix
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
/// Helper lookup to get the name of each node type
|
||||
inline const char *ast_node_type_to_string(AST_Node_Type ast_node_type) {
|
||||
static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "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"};
|
||||
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)];
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/// \brief Convenience type for file positions
|
||||
struct File_Position {
|
||||
int line;
|
||||
int column;
|
||||
int line = 0;
|
||||
int column = 0;
|
||||
|
||||
File_Position(int t_file_line, int t_file_column)
|
||||
: line(t_file_line), column(t_file_column) { }
|
||||
constexpr File_Position(int t_file_line, int t_file_column) noexcept
|
||||
: line(t_file_line)
|
||||
, column(t_file_column) {
|
||||
}
|
||||
|
||||
File_Position() : line(0), column(0) { }
|
||||
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::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))
|
||||
{
|
||||
Parse_Location(std::shared_ptr<std::string> t_fname,
|
||||
const int t_start_line = 0,
|
||||
const int t_start_col = 0,
|
||||
const int t_end_line = 0,
|
||||
const int t_end_col = 0)
|
||||
: start(t_start_line, t_start_col)
|
||||
, end(t_end_line, t_end_col)
|
||||
, filename(std::move(t_fname)) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
File_Position start;
|
||||
File_Position end;
|
||||
std::shared_ptr<std::string> filename;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
|
||||
typedef std::unique_ptr<AST_Node> AST_NodePtr;
|
||||
typedef std::unique_ptr<const AST_Node> AST_NodePtr_Const;
|
||||
using AST_NodePtr = std::unique_ptr<AST_Node>;
|
||||
using AST_NodePtr_Const = std::unique_ptr<const AST_Node>;
|
||||
|
||||
struct AST_Node_Trace;
|
||||
|
||||
|
||||
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
|
||||
namespace exception
|
||||
{
|
||||
namespace exception {
|
||||
/// \brief Thrown if an error occurs while attempting to load a binary module
|
||||
struct load_module_error : std::runtime_error
|
||||
{
|
||||
explicit load_module_error(const std::string &t_reason) noexcept
|
||||
: std::runtime_error(t_reason)
|
||||
{
|
||||
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))
|
||||
{
|
||||
: 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)
|
||||
{
|
||||
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";
|
||||
@ -163,7 +200,6 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Errors generated during parsing or evaluation
|
||||
struct eval_error : std::runtime_error {
|
||||
std::string reason;
|
||||
@ -172,48 +208,55 @@ namespace chaiscript
|
||||
std::string detail;
|
||||
std::vector<AST_Node_Trace> 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,
|
||||
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), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
|
||||
{}
|
||||
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept
|
||||
: std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss))
|
||||
, reason(t_why)
|
||||
, start_position(t_where)
|
||||
, filename(t_fname)
|
||||
, detail(format_detail(t_functions, t_dot_notation, t_ss)) {
|
||||
}
|
||||
|
||||
eval_error(const std::string &t_why,
|
||||
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_parameters, t_dot_notation, t_ss)),
|
||||
reason(t_why), 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 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)
|
||||
, filename(t_fname) {
|
||||
}
|
||||
|
||||
explicit eval_error(const std::string &t_why) noexcept
|
||||
: std::runtime_error("Error: \"" + t_why + "\" "),
|
||||
reason(t_why)
|
||||
{}
|
||||
: 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';
|
||||
ss << '\n'
|
||||
<< detail << '\n';
|
||||
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)
|
||||
{
|
||||
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block && id(call_stack[j]) != chaiscript::AST_Node_Type::File) {
|
||||
ss << '\n';
|
||||
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
|
||||
}
|
||||
@ -226,52 +269,39 @@ namespace chaiscript
|
||||
~eval_error() noexcept override = default;
|
||||
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
static AST_Node_Type id(const T& t)
|
||||
{
|
||||
static AST_Node_Type id(const T &t) noexcept {
|
||||
return t.identifier;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string pretty(const T& t)
|
||||
{
|
||||
static std::string pretty(const T &t) {
|
||||
return t.pretty_print();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static const std::string &fname(const T& t)
|
||||
{
|
||||
static const std::string &fname(const T &t) noexcept {
|
||||
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;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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) {
|
||||
@ -282,18 +312,13 @@ namespace chaiscript
|
||||
|
||||
std::string paramstr;
|
||||
|
||||
for (size_t index = 1;
|
||||
index != types.size();
|
||||
++index)
|
||||
{
|
||||
paramstr += (types[index].is_const()?"const ":"");
|
||||
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 {
|
||||
@ -307,19 +332,15 @@ 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 && dynfun->has_parse_tree()) {
|
||||
Proxy_Function f = dynfun->get_guard();
|
||||
|
||||
if (f)
|
||||
{
|
||||
if (f) {
|
||||
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
|
||||
if (dynfunguard && dynfunguard->has_parse_tree())
|
||||
{
|
||||
if (dynfunguard && dynfunguard->has_parse_tree()) {
|
||||
retval += " : " + format_guard(dynfunguard->get_parse_tree());
|
||||
}
|
||||
}
|
||||
@ -331,14 +352,12 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string format_guard(const T &t)
|
||||
{
|
||||
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 << ")";
|
||||
return oss.str();
|
||||
@ -346,50 +365,37 @@ namespace chaiscript
|
||||
|
||||
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)
|
||||
{
|
||||
if (t_functions.size() == 1) {
|
||||
assert(t_functions[0]);
|
||||
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
|
||||
} else {
|
||||
ss << " " << t_functions.size() << " overloads available:\n";
|
||||
|
||||
for (const auto & t_function : t_functions)
|
||||
{
|
||||
for (const auto &t_function : t_functions) {
|
||||
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
paramstr += (itr->is_const()?"const ":"");
|
||||
for (auto 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 {
|
||||
@ -404,12 +410,10 @@ 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 ";
|
||||
@ -418,16 +422,18 @@ 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);
|
||||
@ -447,8 +453,7 @@ 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);
|
||||
@ -460,8 +465,7 @@ 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);
|
||||
@ -476,13 +480,12 @@ 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) noexcept
|
||||
: std::runtime_error("File Not Found: " + t_filename),
|
||||
filename(t_filename)
|
||||
{ }
|
||||
explicit file_not_found_error(const std::string &t_filename)
|
||||
: std::runtime_error("File Not Found: " + t_filename)
|
||||
, filename(t_filename) {
|
||||
}
|
||||
|
||||
file_not_found_error(const file_not_found_error &) = default;
|
||||
~file_not_found_error() noexcept override = default;
|
||||
@ -490,8 +493,7 @@ namespace chaiscript
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace exception
|
||||
|
||||
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
||||
struct AST_Node {
|
||||
@ -500,25 +502,18 @@ namespace chaiscript
|
||||
const std::string text;
|
||||
Parse_Location location;
|
||||
|
||||
const std::string &filename() const {
|
||||
return *location.filename;
|
||||
}
|
||||
const std::string &filename() const noexcept { return *location.filename; }
|
||||
|
||||
const File_Position &start() const {
|
||||
return location.start;
|
||||
}
|
||||
const File_Position &start() const noexcept { return location.start; }
|
||||
|
||||
const File_Position &end() const {
|
||||
return location.end;
|
||||
}
|
||||
const File_Position &end() const noexcept { return location.end; }
|
||||
|
||||
std::string pretty_print() const
|
||||
{
|
||||
std::string pretty_print() const {
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << text;
|
||||
|
||||
for (auto & elem : get_children()) {
|
||||
for (auto &elem : get_children()) {
|
||||
oss << elem.get().pretty_print() << ' ';
|
||||
}
|
||||
|
||||
@ -528,99 +523,81 @@ namespace chaiscript
|
||||
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';
|
||||
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()) {
|
||||
for (auto &elem : get_children()) {
|
||||
oss << elem.get().to_string(t_prepend + " ");
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
static bool 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 &) {
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("Condition not boolean");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual ~AST_Node() = default;
|
||||
virtual ~AST_Node() noexcept = default;
|
||||
AST_Node(AST_Node &&) = default;
|
||||
AST_Node &operator=(AST_Node &&) = default;
|
||||
AST_Node &operator=(AST_Node &&) = delete;
|
||||
AST_Node(const AST_Node &) = delete;
|
||||
AST_Node& operator=(const AST_Node &) = delete;
|
||||
|
||||
AST_Node &operator=(const AST_Node &) = delete;
|
||||
|
||||
protected:
|
||||
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
|
||||
: identifier(t_id), text(std::move(t_ast_node_text)),
|
||||
location(std::move(t_loc))
|
||||
{
|
||||
: identifier(t_id)
|
||||
, text(std::move(t_ast_node_text))
|
||||
, location(std::move(t_loc)) {
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct AST_Node_Trace
|
||||
{
|
||||
struct AST_Node_Trace {
|
||||
const AST_Node_Type identifier;
|
||||
const std::string text;
|
||||
Parse_Location location;
|
||||
|
||||
const std::string &filename() const {
|
||||
return *location.filename;
|
||||
}
|
||||
const std::string &filename() const noexcept { return *location.filename; }
|
||||
|
||||
const File_Position &start() const {
|
||||
return location.start;
|
||||
}
|
||||
const File_Position &start() const noexcept { return location.start; }
|
||||
|
||||
const File_Position &end() const {
|
||||
return location.end;
|
||||
}
|
||||
const File_Position &end() const noexcept { return location.end; }
|
||||
|
||||
std::string pretty_print() const
|
||||
{
|
||||
std::string pretty_print() const {
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << text;
|
||||
|
||||
for (const auto & elem : children) {
|
||||
for (const auto &elem : children) {
|
||||
oss << elem.pretty_print() << ' ';
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::vector<AST_Node_Trace> get_children(const AST_Node &node)
|
||||
{
|
||||
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))
|
||||
{
|
||||
: identifier(node.identifier)
|
||||
, text(node.text)
|
||||
, location(node.location)
|
||||
, children(get_children(node)) {
|
||||
}
|
||||
|
||||
|
||||
std::vector<AST_Node_Trace> children;
|
||||
|
||||
};
|
||||
|
||||
namespace parser {
|
||||
class ChaiScript_Parser_Base
|
||||
{
|
||||
class ChaiScript_Parser_Base {
|
||||
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;
|
||||
@ -632,123 +609,88 @@ namespace chaiscript
|
||||
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
|
||||
|
||||
template<typename T>
|
||||
T &get_tracer()
|
||||
{
|
||||
T &get_tracer() noexcept {
|
||||
// to do type check this somehow?
|
||||
return *static_cast<T*>(get_tracer_ptr());
|
||||
return *static_cast<T *>(get_tracer_ptr());
|
||||
}
|
||||
|
||||
protected:
|
||||
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
|
||||
};
|
||||
}
|
||||
} // namespace parser
|
||||
|
||||
namespace eval
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace eval {
|
||||
namespace detail {
|
||||
/// Special type for returned values
|
||||
struct Return_Value {
|
||||
Boxed_Value retval;
|
||||
};
|
||||
|
||||
|
||||
/// Special type indicating a call to 'break'
|
||||
struct Break_Loop {
|
||||
Break_Loop() = default;
|
||||
};
|
||||
|
||||
|
||||
/// Special type indicating a call to 'continue'
|
||||
struct Continue_Loop {
|
||||
Continue_Loop() = default;
|
||||
};
|
||||
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Scope_Push_Pop
|
||||
{
|
||||
struct Scope_Push_Pop {
|
||||
Scope_Push_Pop(Scope_Push_Pop &&) = default;
|
||||
Scope_Push_Pop& operator=(Scope_Push_Pop &&) = default;
|
||||
Scope_Push_Pop &operator=(Scope_Push_Pop &&) = delete;
|
||||
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
|
||||
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
|
||||
Scope_Push_Pop &operator=(const Scope_Push_Pop &) = delete;
|
||||
|
||||
explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
: m_ds(t_ds) {
|
||||
m_ds->new_scope(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Scope_Push_Pop()
|
||||
{
|
||||
m_ds->pop_scope(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Scope_Push_Pop() { m_ds->pop_scope(m_ds.stack_holder()); }
|
||||
|
||||
private:
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new function call and pops it on destruction
|
||||
struct Function_Push_Pop
|
||||
{
|
||||
struct Function_Push_Pop {
|
||||
Function_Push_Pop(Function_Push_Pop &&) = default;
|
||||
Function_Push_Pop& operator=(Function_Push_Pop &&) = default;
|
||||
Function_Push_Pop &operator=(Function_Push_Pop &&) = delete;
|
||||
Function_Push_Pop(const Function_Push_Pop &) = delete;
|
||||
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
|
||||
Function_Push_Pop &operator=(const Function_Push_Pop &) = delete;
|
||||
|
||||
explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
: m_ds(t_ds) {
|
||||
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
||||
}
|
||||
|
||||
~Function_Push_Pop()
|
||||
{
|
||||
m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
||||
}
|
||||
|
||||
void save_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
m_ds->save_function_params(t_params);
|
||||
}
|
||||
|
||||
void save_params(std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
m_ds->save_function_params(t_params);
|
||||
}
|
||||
~Function_Push_Pop() { m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); }
|
||||
|
||||
void save_params(const Function_Params &t_params) { m_ds->save_function_params(t_params); }
|
||||
|
||||
private:
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Stack_Push_Pop
|
||||
{
|
||||
struct Stack_Push_Pop {
|
||||
Stack_Push_Pop(Stack_Push_Pop &&) = default;
|
||||
Stack_Push_Pop& operator=(Stack_Push_Pop &&) = default;
|
||||
Stack_Push_Pop &operator=(Stack_Push_Pop &&) = delete;
|
||||
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
|
||||
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
|
||||
Stack_Push_Pop &operator=(const Stack_Push_Pop &) = delete;
|
||||
|
||||
explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
: m_ds(t_ds) {
|
||||
m_ds->new_stack(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Stack_Push_Pop()
|
||||
{
|
||||
m_ds->pop_stack(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Stack_Push_Pop() { m_ds->pop_stack(m_ds.stack_holder()); }
|
||||
|
||||
private:
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace eval
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif /* _CHAISCRIPT_COMMON_HPP */
|
||||
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
// 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)
|
||||
// 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_ENGINE_HPP_
|
||||
#define CHAISCRIPT_ENGINE_HPP_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
@ -21,15 +21,15 @@
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "../chaiscript_threading.hpp"
|
||||
#include "../dispatchkit/boxed_cast_helper.hpp"
|
||||
#include "../dispatchkit/boxed_value.hpp"
|
||||
#include "../dispatchkit/dispatchkit.hpp"
|
||||
#include "../dispatchkit/type_conversions.hpp"
|
||||
#include "../dispatchkit/proxy_functions.hpp"
|
||||
#include "../dispatchkit/register_function.hpp"
|
||||
#include "../dispatchkit/type_conversions.hpp"
|
||||
#include "chaiscript_common.hpp"
|
||||
|
||||
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
|
||||
@ -50,23 +50,18 @@
|
||||
#include "chaiscript_unknown.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#include "../dispatchkit/exception_specification.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace chaiscript {
|
||||
/// Namespace alias to provide cleaner and more explicit syntax to users.
|
||||
using Namespace = dispatch::Dynamic_Object;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
|
||||
namespace detail {
|
||||
using Loadable_Module_Ptr = std::shared_ptr<Loadable_Module>;
|
||||
}
|
||||
|
||||
|
||||
/// \brief The main object that the ChaiScript user will use.
|
||||
class ChaiScript_Basic {
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
mutable chaiscript::detail::threading::recursive_mutex m_use_mutex;
|
||||
|
||||
@ -81,26 +76,21 @@ namespace chaiscript
|
||||
|
||||
chaiscript::detail::Dispatch_Engine m_engine;
|
||||
|
||||
std::map<std::string, std::function<Namespace&()>> m_namespace_generators;
|
||||
std::map<std::string, std::function<Namespace &()>> m_namespace_generators;
|
||||
|
||||
/// Evaluates the given string in by parsing it and running the results through the evaluator
|
||||
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
|
||||
{
|
||||
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) {
|
||||
try {
|
||||
const auto p = m_parser->parse(t_input, t_filename);
|
||||
return p->eval(chaiscript::detail::Dispatch_State(m_engine));
|
||||
}
|
||||
catch (chaiscript::eval::detail::Return_Value &rv) {
|
||||
} catch (chaiscript::eval::detail::Return_Value &rv) {
|
||||
return rv.retval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Evaluates the given file and looks in the 'use' paths
|
||||
const Boxed_Value internal_eval_file(const std::string &t_filename) {
|
||||
for (const auto &path : m_use_paths)
|
||||
{
|
||||
Boxed_Value internal_eval_file(const std::string &t_filename) {
|
||||
for (const auto &path : m_use_paths) {
|
||||
try {
|
||||
const auto appendedpath = path + t_filename;
|
||||
return do_eval(load_file(appendedpath), appendedpath, true);
|
||||
@ -113,13 +103,10 @@ namespace chaiscript
|
||||
|
||||
// failed to load by any name
|
||||
throw exception::file_not_found_error(t_filename);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Evaluates the given string, used during eval() inside of a script
|
||||
const Boxed_Value internal_eval(const std::string &t_e) {
|
||||
Boxed_Value internal_eval(const std::string &t_e) {
|
||||
try {
|
||||
return do_eval(t_e, "__EVAL__", true);
|
||||
} catch (const exception::eval_error &t_ee) {
|
||||
@ -128,80 +115,70 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Returns the current evaluation m_engine
|
||||
chaiscript::detail::Dispatch_Engine &get_eval_engine() {
|
||||
return m_engine;
|
||||
}
|
||||
chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { return m_engine; }
|
||||
|
||||
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
||||
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) {
|
||||
if (t_lib)
|
||||
{
|
||||
if (t_lib) {
|
||||
add(t_lib);
|
||||
}
|
||||
|
||||
m_engine.add(fun([this](){ m_engine.dump_system(); }), "dump_system");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv){ m_engine.dump_object(t_bv); }), "dump_object");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type){ return m_engine.is_type(t_bv, t_type); }), "is_type");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv){ return m_engine.type_name(t_bv); }), "type_name");
|
||||
m_engine.add(fun([this](const std::string &t_f){ return m_engine.function_exists(t_f); }), "function_exists");
|
||||
m_engine.add(fun([this](){ return m_engine.get_function_objects(); }), "get_functions");
|
||||
m_engine.add(fun([this](){ return m_engine.get_scripting_objects(); }), "get_objects");
|
||||
m_engine.add(fun([this]() { m_engine.dump_system(); }), "dump_system");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv) { m_engine.dump_object(t_bv); }), "dump_object");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type) { return m_engine.is_type(t_bv, t_type); }), "is_type");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv) { return m_engine.type_name(t_bv); }), "type_name");
|
||||
m_engine.add(fun([this](const std::string &t_f) { return m_engine.function_exists(t_f); }), "function_exists");
|
||||
m_engine.add(fun([this]() { return m_engine.get_function_objects(); }), "get_functions");
|
||||
m_engine.add(fun([this]() { return m_engine.get_scripting_objects(); }), "get_objects");
|
||||
|
||||
m_engine.add(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[this](const std::vector<Boxed_Value> &t_params) {
|
||||
return m_engine.call_exists(t_params);
|
||||
})
|
||||
, "call_exists");
|
||||
m_engine.add(dispatch::make_dynamic_proxy_function([this](const Function_Params &t_params) { return m_engine.call_exists(t_params); }),
|
||||
"call_exists");
|
||||
|
||||
|
||||
m_engine.add(fun(
|
||||
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
|
||||
m_engine.add(fun([this](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
|
||||
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves());
|
||||
return t_fun(t_params, s);
|
||||
}), "call");
|
||||
return t_fun(Function_Params{t_params}, s);
|
||||
}),
|
||||
"call");
|
||||
|
||||
m_engine.add(fun([this](const Type_Info &t_ti) { return m_engine.get_type_name(t_ti); }), "name");
|
||||
|
||||
m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name");
|
||||
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw) { return m_engine.get_type(t_type_name, t_throw); }), "type");
|
||||
m_engine.add(fun([this](const std::string &t_type_name) { return m_engine.get_type(t_type_name, true); }), "type");
|
||||
|
||||
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type");
|
||||
m_engine.add(fun([this](const std::string &t_type_name){ return m_engine.get_type(t_type_name, true); }), "type");
|
||||
|
||||
m_engine.add(fun(
|
||||
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
|
||||
m_engine.add(fun([this](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value(const Boxed_Value &)> &t_func) {
|
||||
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
|
||||
}
|
||||
), "add_type_conversion");
|
||||
|
||||
|
||||
}),
|
||||
"add_type_conversion");
|
||||
|
||||
if (std::find(t_opts.begin(), t_opts.end(), Options::No_Load_Modules) == t_opts.end()
|
||||
&& std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end())
|
||||
{
|
||||
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return load_module(t_module, t_file); }), "load_module");
|
||||
m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module");
|
||||
&& std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end()) {
|
||||
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file) { load_module(t_module, t_file); }), "load_module");
|
||||
m_engine.add(fun([this](const std::string &t_module) { return load_module(t_module); }), "load_module");
|
||||
}
|
||||
|
||||
if (std::find(t_opts.begin(), t_opts.end(), Options::No_External_Scripts) == t_opts.end()
|
||||
&& std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end())
|
||||
{
|
||||
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use");
|
||||
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
|
||||
&& std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end()) {
|
||||
m_engine.add(fun([this](const std::string &t_file) { return use(t_file); }), "use");
|
||||
m_engine.add(fun([this](const std::string &t_file) { return internal_eval_file(t_file); }), "eval_file");
|
||||
}
|
||||
|
||||
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
|
||||
m_engine.add(fun([this](const AST_Node &t_ast){ return eval(t_ast); }), "eval");
|
||||
m_engine.add(fun([this](const std::string &t_str) { return internal_eval(t_str); }), "eval");
|
||||
m_engine.add(fun([this](const AST_Node &t_ast) { return eval(t_ast); }), "eval");
|
||||
|
||||
m_engine.add(fun([this](const std::string &t_str, const bool t_dump){ return parse(t_str, t_dump); }), "parse");
|
||||
m_engine.add(fun([this](const std::string &t_str){ return parse(t_str); }), "parse");
|
||||
m_engine.add(fun([this](const std::string &t_str, const bool t_dump) { return parse(t_str, t_dump); }), "parse");
|
||||
m_engine.add(fun([this](const std::string &t_str) { return parse(t_str); }), "parse");
|
||||
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name) { add_global_const(t_bv, t_name); }), "add_global_const");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name) { add_global(t_bv, t_name); }), "add_global");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name) { set_global(t_bv, t_name); }), "set_global");
|
||||
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
|
||||
|
||||
m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([](Namespace& /*space*/) {}, t_namespace_name); import(t_namespace_name); }), "namespace");
|
||||
m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import");
|
||||
// why this unused parameter to Namespace?
|
||||
m_engine.add(fun([this](const std::string &t_namespace_name) {
|
||||
register_namespace([](Namespace & /*space*/) noexcept {}, t_namespace_name);
|
||||
import(t_namespace_name);
|
||||
}),
|
||||
"namespace");
|
||||
m_engine.add(fun([this](const std::string &t_namespace_name) { import(t_namespace_name); }), "import");
|
||||
}
|
||||
|
||||
/// Skip BOM at the beginning of file
|
||||
@ -213,10 +190,7 @@ namespace chaiscript
|
||||
|
||||
infile.read(buffer, static_cast<std::streamsize>(bytes_needed));
|
||||
|
||||
if ((buffer[0] == '\xef')
|
||||
&& (buffer[1] == '\xbb')
|
||||
&& (buffer[2] == '\xbf')) {
|
||||
|
||||
if ((buffer[0] == '\xef') && (buffer[1] == '\xbb') && (buffer[2] == '\xbf')) {
|
||||
infile.seekg(3);
|
||||
return true;
|
||||
}
|
||||
@ -228,7 +202,7 @@ namespace chaiscript
|
||||
|
||||
/// Helper function for loading a file
|
||||
static std::string load_file(const std::string &t_filename) {
|
||||
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary );
|
||||
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
|
||||
|
||||
if (!infile.is_open()) {
|
||||
throw chaiscript::exception::file_not_found_error(t_filename);
|
||||
@ -240,12 +214,11 @@ namespace chaiscript
|
||||
assert(size >= 0);
|
||||
|
||||
if (skip_bom(infile)) {
|
||||
size-=3; // decrement the BOM size from file size, otherwise we'll get parsing errors
|
||||
assert(size >= 0); //and check if there's more text
|
||||
size -= 3; // decrement the BOM size from file size, otherwise we'll get parsing errors
|
||||
assert(size >= 0); // and check if there's more text
|
||||
}
|
||||
|
||||
if (size == std::streampos(0))
|
||||
{
|
||||
if (size == std::streampos(0)) {
|
||||
return std::string();
|
||||
} else {
|
||||
std::vector<char> v(static_cast<size_t>(size));
|
||||
@ -254,14 +227,15 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths)
|
||||
{
|
||||
if (paths.empty()) { return {""}; }
|
||||
else { return paths; }
|
||||
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths) {
|
||||
if (paths.empty()) {
|
||||
return {""};
|
||||
} else {
|
||||
return paths;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor for ChaiScript
|
||||
/// \param[in] t_lib Standard library to apply to this ChaiScript instance
|
||||
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
|
||||
@ -271,42 +245,38 @@ namespace chaiscript
|
||||
std::vector<std::string> t_module_paths = {},
|
||||
std::vector<std::string> t_use_paths = {},
|
||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
|
||||
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths))),
|
||||
m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths))),
|
||||
m_parser(std::move(parser)),
|
||||
m_engine(*m_parser)
|
||||
{
|
||||
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths)))
|
||||
, m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths)))
|
||||
, m_parser(std::move(parser))
|
||||
, m_engine(*m_parser) {
|
||||
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
||||
// If on Unix, add the path of the current executable to the module search path
|
||||
// as windows would do
|
||||
|
||||
union cast_union
|
||||
{
|
||||
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&);
|
||||
union cast_union {
|
||||
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string &);
|
||||
void *out_ptr;
|
||||
};
|
||||
|
||||
Dl_info rInfo;
|
||||
memset( &rInfo, 0, sizeof(rInfo) );
|
||||
memset(&rInfo, 0, sizeof(rInfo));
|
||||
cast_union u;
|
||||
u.in_ptr = &ChaiScript_Basic::use;
|
||||
if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) {
|
||||
if ((dladdr(static_cast<void *>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr)) {
|
||||
std::string dllpath(rInfo.dli_fname);
|
||||
const size_t lastslash = dllpath.rfind('/');
|
||||
if (lastslash != std::string::npos)
|
||||
{
|
||||
if (lastslash != std::string::npos) {
|
||||
dllpath.erase(lastslash);
|
||||
}
|
||||
|
||||
// Let's see if this is a link that we should expand
|
||||
std::vector<char> buf(2048);
|
||||
const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
|
||||
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size())
|
||||
{
|
||||
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size()) {
|
||||
dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen));
|
||||
}
|
||||
|
||||
m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
|
||||
m_module_paths.insert(m_module_paths.begin(), dllpath + "/");
|
||||
}
|
||||
#endif
|
||||
build_eval_system(t_lib, t_opts);
|
||||
@ -324,38 +294,35 @@ namespace chaiscript
|
||||
std::vector<std::string> t_module_paths = {},
|
||||
std::vector<std::string> t_use_paths = {},
|
||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
|
||||
: ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts)
|
||||
{
|
||||
: ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts) {
|
||||
try {
|
||||
// attempt to load the stdlib
|
||||
load_module("chaiscript_stdlib-" + Build_Info::version());
|
||||
} catch (const exception::load_module_error &t_err) {
|
||||
std::cout << "An error occured while trying to load the chaiscript standard library.\n"
|
||||
<< "\n"
|
||||
<< "You must either provide a standard library, or compile it in.\n"
|
||||
<< "For an example of compiling the standard library in,\n"
|
||||
<< "see: https://gist.github.com/lefticus/9456197\n"
|
||||
<< "Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n"
|
||||
<< "\n"
|
||||
<< "\n"
|
||||
std::cout << "An error occurred while trying to load the chaiscript standard library.\n"
|
||||
"\n"
|
||||
"You must either provide a standard library, or compile it in.\n"
|
||||
"For an example of compiling the standard library in,\n"
|
||||
"see: https://gist.github.com/lefticus/9456197\n"
|
||||
"Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n"
|
||||
"\n\n"
|
||||
<< t_err.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#else // CHAISCRIPT_NO_DYNLOAD
|
||||
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
|
||||
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
|
||||
std::vector<std::string> t_module_paths = {},
|
||||
std::vector<std::string> t_use_paths = {},
|
||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) = delete;
|
||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
|
||||
= delete;
|
||||
#endif
|
||||
|
||||
parser::ChaiScript_Parser_Base &get_parser()
|
||||
{
|
||||
parser::ChaiScript_Parser_Base &get_parser() noexcept {
|
||||
return *m_parser;
|
||||
}
|
||||
|
||||
const Boxed_Value eval(const AST_Node &t_ast)
|
||||
{
|
||||
const Boxed_Value eval(const AST_Node &t_ast) {
|
||||
try {
|
||||
return t_ast.eval(chaiscript::detail::Dispatch_State(m_engine));
|
||||
} catch (const exception::eval_error &t_ee) {
|
||||
@ -363,8 +330,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
}
|
||||
}
|
||||
|
||||
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false)
|
||||
{
|
||||
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false) {
|
||||
auto ast = m_parser->parse(t_input, "PARSE");
|
||||
if (t_debug_print) {
|
||||
m_parser->debug_print(*ast);
|
||||
@ -372,38 +338,28 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
return ast;
|
||||
}
|
||||
|
||||
|
||||
std::string get_type_name(const Type_Info &ti) const
|
||||
{
|
||||
return m_engine.get_type_name(ti);
|
||||
}
|
||||
std::string get_type_name(const Type_Info &ti) const { return m_engine.get_type_name(ti); }
|
||||
|
||||
template<typename T>
|
||||
std::string get_type_name() const
|
||||
{
|
||||
std::string get_type_name() const {
|
||||
return get_type_name(user_type<T>());
|
||||
}
|
||||
|
||||
|
||||
/// \brief Loads and parses a file. If the file is already, it is not reloaded
|
||||
/// The use paths specified at ChaiScript construction time are searched for the
|
||||
/// requested file.
|
||||
/// \brief Loads and parses a file. If the file is already open, it is not
|
||||
/// reloaded. The use paths specified at ChaiScript construction time are
|
||||
/// searched for the requested file.
|
||||
///
|
||||
/// \param[in] t_filename Filename to load and evaluate
|
||||
Boxed_Value use(const std::string &t_filename)
|
||||
{
|
||||
for (const auto &path : m_use_paths)
|
||||
{
|
||||
Boxed_Value use(const std::string &t_filename) {
|
||||
for (const auto &path : m_use_paths) {
|
||||
const auto appendedpath = path + t_filename;
|
||||
try {
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
|
||||
Boxed_Value retval;
|
||||
|
||||
if (m_used_files.count(appendedpath) == 0)
|
||||
{
|
||||
if (m_used_files.count(appendedpath) == 0) {
|
||||
l2.unlock();
|
||||
retval = eval_file(appendedpath);
|
||||
l2.lock();
|
||||
@ -429,8 +385,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// \param[in] t_name Name of the value to add
|
||||
/// \throw chaiscript::exception::global_non_const If t_bv is not a constant object
|
||||
/// \sa Boxed_Value::is_const
|
||||
ChaiScript_Basic &add_global_const(const Boxed_Value &t_bv, const std::string &t_name)
|
||||
{
|
||||
ChaiScript_Basic &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) {
|
||||
Name_Validator::validate_object_name(t_name);
|
||||
m_engine.add_global_const(t_bv, t_name);
|
||||
return *this;
|
||||
@ -441,15 +396,13 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// \param[in] t_name Name of the value to add
|
||||
/// \warning The user is responsible for making sure the object is thread-safe if necessary
|
||||
/// ChaiScript is thread-safe but provides no threading locking mechanism to the script
|
||||
ChaiScript_Basic &add_global(const Boxed_Value &t_bv, const std::string &t_name)
|
||||
{
|
||||
ChaiScript_Basic &add_global(const Boxed_Value &t_bv, const std::string &t_name) {
|
||||
Name_Validator::validate_object_name(t_name);
|
||||
m_engine.add_global(t_bv, t_name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChaiScript_Basic &set_global(const Boxed_Value &t_bv, const std::string &t_name)
|
||||
{
|
||||
ChaiScript_Basic &set_global(const Boxed_Value &t_bv, const std::string &t_name) {
|
||||
Name_Validator::validate_object_name(t_name);
|
||||
m_engine.set_global(t_bv, t_name);
|
||||
return *this;
|
||||
@ -460,8 +413,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// are left out due to performance considerations involved in tracking the state
|
||||
/// \sa ChaiScript::get_state
|
||||
/// \sa ChaiScript::set_state
|
||||
struct State
|
||||
{
|
||||
struct State {
|
||||
std::set<std::string> used_files;
|
||||
chaiscript::detail::Dispatch_Engine::State engine_state;
|
||||
std::set<std::string> active_loaded_modules;
|
||||
@ -480,8 +432,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state
|
||||
/// \endcode
|
||||
State get_state() const
|
||||
{
|
||||
State get_state() const {
|
||||
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
|
||||
@ -506,8 +457,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// chai.add(chaiscript::fun(&somefunction), "somefunction");
|
||||
/// chai.set_state(s); // restore initial state, which does not have the recently added "somefunction"
|
||||
/// \endcode
|
||||
void set_state(const State &t_state)
|
||||
{
|
||||
void set_state(const State &t_state) {
|
||||
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
|
||||
@ -517,20 +467,14 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
}
|
||||
|
||||
/// \returns All values in the local thread state, added through the add() function
|
||||
std::map<std::string, Boxed_Value> get_locals() const
|
||||
{
|
||||
return m_engine.get_locals();
|
||||
}
|
||||
std::map<std::string, Boxed_Value> get_locals() const { return m_engine.get_locals(); }
|
||||
|
||||
/// \brief Sets all of the locals for the current thread state.
|
||||
///
|
||||
/// \param[in] t_locals The map<name, value> set of variables to replace the current state with
|
||||
///
|
||||
/// Any existing locals are removed and the given set of variables is added
|
||||
void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
|
||||
{
|
||||
m_engine.set_locals(t_locals);
|
||||
}
|
||||
void set_locals(const std::map<std::string, Boxed_Value> &t_locals) { m_engine.set_locals(t_locals); }
|
||||
|
||||
/// \brief Adds a type, function or object to ChaiScript. Objects are added to the local thread state.
|
||||
/// \param[in] t_t Item to add
|
||||
@ -548,8 +492,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
///
|
||||
/// \sa \ref adding_items
|
||||
template<typename T>
|
||||
ChaiScript_Basic &add(const T &t_t, const std::string &t_name)
|
||||
{
|
||||
ChaiScript_Basic &add(const T &t_t, const std::string &t_name) {
|
||||
Name_Validator::validate_object_name(t_name);
|
||||
m_engine.add(t_t, t_name);
|
||||
return *this;
|
||||
@ -564,8 +507,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
|
||||
/// \endcode
|
||||
ChaiScript_Basic &add(const Type_Conversion &d)
|
||||
{
|
||||
ChaiScript_Basic &add(const Type_Conversion &d) {
|
||||
m_engine.add(d);
|
||||
return *this;
|
||||
}
|
||||
@ -573,8 +515,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// \brief Adds all elements of a module to ChaiScript runtime
|
||||
/// \param[in] t_p The module to add.
|
||||
/// \sa chaiscript::Module
|
||||
ChaiScript_Basic &add(const ModulePtr &t_p)
|
||||
{
|
||||
ChaiScript_Basic &add(const ModulePtr &t_p) {
|
||||
t_p->apply(*this, this->get_eval_engine());
|
||||
return *this;
|
||||
}
|
||||
@ -591,17 +532,14 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// (the symbol mentioned above), an exception is thrown.
|
||||
///
|
||||
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
|
||||
std::string load_module(const std::string &t_module_name)
|
||||
{
|
||||
std::string load_module(const std::string &t_module_name) {
|
||||
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||
(void)t_module_name; // -Wunused-parameter
|
||||
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
|
||||
#else
|
||||
std::vector<exception::load_module_error> errors;
|
||||
std::string version_stripped_name = t_module_name;
|
||||
size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
|
||||
if (version_pos != std::string::npos)
|
||||
{
|
||||
if (version_pos != std::string::npos) {
|
||||
version_stripped_name.erase(version_pos);
|
||||
}
|
||||
|
||||
@ -609,12 +547,9 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
|
||||
std::vector<std::string> postfixes{".dll", ".so", ".bundle", ""};
|
||||
|
||||
for (auto & elem : m_module_paths)
|
||||
{
|
||||
for (auto & prefix : prefixes)
|
||||
{
|
||||
for (auto & postfix : postfixes)
|
||||
{
|
||||
for (auto &elem : m_module_paths) {
|
||||
for (auto &prefix : prefixes) {
|
||||
for (auto &postfix : postfixes) {
|
||||
try {
|
||||
const auto name = elem + prefix + t_module_name + postfix;
|
||||
// std::cerr << "trying location: " << name << '\n';
|
||||
@ -640,12 +575,10 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// \param[in] t_filename Ignore normal filename search process and use specific filename
|
||||
///
|
||||
/// \sa ChaiScript::load_module(const std::string &t_module_name)
|
||||
void load_module(const std::string &t_module_name, const std::string &t_filename)
|
||||
{
|
||||
void load_module(const std::string &t_module_name, const std::string &t_filename) {
|
||||
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
if (m_loaded_modules.count(t_module_name) == 0)
|
||||
{
|
||||
if (m_loaded_modules.count(t_module_name) == 0) {
|
||||
detail::Loadable_Module_Ptr lm(new detail::Loadable_Module(t_module_name, t_filename));
|
||||
m_loaded_modules[t_module_name] = lm;
|
||||
m_active_loaded_modules.insert(t_module_name);
|
||||
@ -656,7 +589,6 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// \brief Evaluates a string. Equivalent to ChaiScript::eval.
|
||||
///
|
||||
/// \param[in] t_script Script to execute
|
||||
@ -665,8 +597,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// \return result of the script execution
|
||||
///
|
||||
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler())
|
||||
{
|
||||
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler()) {
|
||||
return eval(t_script, t_handler);
|
||||
}
|
||||
|
||||
@ -684,19 +615,16 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
|
||||
/// to the requested type.
|
||||
template<typename T>
|
||||
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
|
||||
{
|
||||
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename = "__EVAL__") {
|
||||
return m_engine.boxed_cast<T>(eval(t_input, t_handler, t_filename));
|
||||
}
|
||||
|
||||
/// \brief casts an object while applying any Dynamic_Conversion available
|
||||
template<typename Type>
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv) const
|
||||
{
|
||||
return(m_engine.boxed_cast<Type>(bv));
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv) const {
|
||||
return (m_engine.boxed_cast<Type>(bv));
|
||||
}
|
||||
|
||||
|
||||
/// \brief Evaluates a string.
|
||||
///
|
||||
/// \param[in] t_input Script to execute
|
||||
@ -707,8 +635,8 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// \return result of the script execution
|
||||
///
|
||||
/// \throw exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
|
||||
{
|
||||
Boxed_Value
|
||||
eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename = "__EVAL__") {
|
||||
try {
|
||||
return do_eval(t_input, t_filename);
|
||||
} catch (Boxed_Value &bv) {
|
||||
@ -744,39 +672,35 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
|
||||
/// \brief Imports a namespace object into the global scope of this ChaiScript instance.
|
||||
/// \param[in] t_namespace_name Name of the namespace to import.
|
||||
/// \throw std::runtime_error In the case that the namespace name was never registered.
|
||||
void import(const std::string& t_namespace_name)
|
||||
{
|
||||
void import(const std::string &t_namespace_name) {
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
if (m_engine.get_scripting_objects().count(t_namespace_name)) {
|
||||
throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined");
|
||||
}
|
||||
else if (m_namespace_generators.count(t_namespace_name)) {
|
||||
} else if (m_namespace_generators.count(t_namespace_name)) {
|
||||
m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw std::runtime_error("No registered namespace: " + t_namespace_name);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never used.
|
||||
/// \param[in] t_namespace_generator Namespace generator function.
|
||||
/// \param[in] t_namespace_name Name of the Namespace function being registered.
|
||||
/// \throw std::runtime_error In the case that the namespace name was already registered.
|
||||
void register_namespace(const std::function<void(Namespace&)>& t_namespace_generator, const std::string& t_namespace_name)
|
||||
{
|
||||
/// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never
|
||||
/// used. \param[in] t_namespace_generator Namespace generator function. \param[in] t_namespace_name Name of the Namespace function
|
||||
/// being registered. \throw std::runtime_error In the case that the namespace name was already registered.
|
||||
void register_namespace(const std::function<void(Namespace &)> &t_namespace_generator, const std::string &t_namespace_name) {
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
if (!m_namespace_generators.count(t_namespace_name)) {
|
||||
// contain the namespace object memory within the m_namespace_generators map
|
||||
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace& { t_namespace_generator(space); return space; }));
|
||||
}
|
||||
else {
|
||||
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace & {
|
||||
t_namespace_generator(space);
|
||||
return space;
|
||||
}));
|
||||
} else {
|
||||
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace chaiscript
|
||||
#endif /* CHAISCRIPT_ENGINE_HPP_ */
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
|
||||
@ -9,28 +9,24 @@
|
||||
|
||||
#include "chaiscript_eval.hpp"
|
||||
|
||||
|
||||
namespace chaiscript {
|
||||
namespace optimizer {
|
||||
|
||||
template<typename ... T>
|
||||
struct Optimizer : T...
|
||||
{
|
||||
template<typename... T>
|
||||
struct Optimizer : T... {
|
||||
Optimizer() = default;
|
||||
explicit Optimizer(T ... t)
|
||||
: T(std::move(t))...
|
||||
{
|
||||
explicit Optimizer(T... t)
|
||||
: T(std::move(t))... {
|
||||
}
|
||||
|
||||
template<typename Tracer>
|
||||
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
|
||||
(void)std::initializer_list<int>{ (p = static_cast<T&>(*this).optimize(std::move(p)), 0)... };
|
||||
((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) {
|
||||
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 {
|
||||
@ -39,14 +35,13 @@ namespace chaiscript {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) {
|
||||
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];
|
||||
@ -57,28 +52,25 @@ namespace chaiscript {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto child_count(const eval::AST_Node_Impl<T> &node) {
|
||||
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();
|
||||
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));
|
||||
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 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();
|
||||
@ -95,9 +87,9 @@ namespace chaiscript {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node)
|
||||
{
|
||||
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl || node.identifier == AST_Node_Type::Reference) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -105,10 +97,8 @@ namespace chaiscript {
|
||||
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -119,14 +109,13 @@ namespace chaiscript {
|
||||
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->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,
|
||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text,
|
||||
node->location,
|
||||
std::move(node->children));
|
||||
}
|
||||
}
|
||||
@ -139,16 +128,14 @@ namespace chaiscript {
|
||||
struct Dead_Code {
|
||||
template<typename T>
|
||||
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
||||
if (node->identifier == AST_Node_Type::Block)
|
||||
{
|
||||
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
|
||||
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);
|
||||
@ -158,10 +145,9 @@ namespace chaiscript {
|
||||
if (keepers.size() == num_children) {
|
||||
return node;
|
||||
} else {
|
||||
const auto new_children = [&](){
|
||||
const auto new_children = [&]() {
|
||||
std::vector<eval::AST_Node_Impl_Ptr<T>> retval;
|
||||
for (const auto x : keepers)
|
||||
{
|
||||
for (const auto x : keepers) {
|
||||
retval.push_back(std::move(node->children[x]));
|
||||
}
|
||||
return retval;
|
||||
@ -178,29 +164,25 @@ namespace chaiscript {
|
||||
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) {
|
||||
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,
|
||||
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) {
|
||||
} 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)
|
||||
{
|
||||
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));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -212,31 +194,24 @@ namespace chaiscript {
|
||||
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
|
||||
)
|
||||
{
|
||||
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) );
|
||||
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)
|
||||
{
|
||||
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)) {
|
||||
@ -254,25 +229,21 @@ namespace chaiscript {
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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
|
||||
// failure to fold, that's OK
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,11 +254,7 @@ namespace chaiscript {
|
||||
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)
|
||||
{
|
||||
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);
|
||||
@ -296,38 +263,42 @@ namespace chaiscript {
|
||||
|
||||
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));
|
||||
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)));
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
&& 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); }
|
||||
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));
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
} 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);
|
||||
@ -337,26 +308,26 @@ namespace chaiscript {
|
||||
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));
|
||||
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
|
||||
// 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) {
|
||||
|
||||
} 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 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));
|
||||
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") {
|
||||
@ -370,10 +341,7 @@ namespace chaiscript {
|
||||
} else if (fun_name == "size_t") {
|
||||
return make_constant(Boxed_Number(arg).get_as<size_t>());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return node;
|
||||
@ -383,7 +351,6 @@ namespace chaiscript {
|
||||
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;
|
||||
}
|
||||
@ -392,30 +359,18 @@ namespace chaiscript {
|
||||
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)
|
||||
{
|
||||
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>())) {
|
||||
|
||||
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);
|
||||
|
||||
@ -426,8 +381,10 @@ namespace chaiscript {
|
||||
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) {
|
||||
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);
|
||||
|
||||
@ -450,8 +407,7 @@ namespace chaiscript {
|
||||
}
|
||||
|
||||
return void_var();
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return for_node;
|
||||
}
|
||||
@ -461,11 +417,17 @@ namespace chaiscript {
|
||||
}
|
||||
};
|
||||
|
||||
typedef 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> Optimizer_Default;
|
||||
|
||||
}
|
||||
}
|
||||
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
@ -1,25 +1,18 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_POSIX_HPP_
|
||||
#define CHAISCRIPT_POSIX_HPP_
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
struct DLModule
|
||||
{
|
||||
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)
|
||||
{
|
||||
: m_data(dlopen(t_filename.c_str(), RTLD_NOW)) {
|
||||
if (m_data == nullptr) {
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
@ -29,22 +22,16 @@ namespace chaiscript
|
||||
DLModule(const DLModule &) = delete;
|
||||
DLModule &operator=(const DLModule &) = delete;
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
dlclose(m_data);
|
||||
}
|
||||
~DLModule() { dlclose(m_data); }
|
||||
|
||||
void *m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
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)
|
||||
{
|
||||
: m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str()))) {
|
||||
if (!m_symbol) {
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
@ -53,16 +40,14 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
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())
|
||||
{
|
||||
: 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
|
||||
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and 2009-2017, Jason Turner (jason@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(
|
||||
struct ChaiScript_Prelude {
|
||||
static std::string chaiscript_prelude() {
|
||||
return R"chaiscript(
|
||||
|
||||
def lt(l, r) {
|
||||
if (call_exists(`<`, l, r)) {
|
||||
@ -554,9 +555,8 @@ def find(container, value) {
|
||||
|
||||
|
||||
)chaiscript";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif /* CHAISCRIPT_PRELUDE_HPP_ */
|
||||
|
||||
@ -2,26 +2,22 @@
|
||||
/// 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
|
||||
{
|
||||
namespace ChaiScript_Language {
|
||||
/// \page LangStandardLibraryRef ChaiScript Language Standard Library 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
|
||||
/// to all standard ChaiScript applications, and provides a simple foundation for using numbers, strings, and ranges
|
||||
/// (the general category of Range cs and their iteration).
|
||||
///
|
||||
|
||||
/// \page LangStandardLibraryRef ChaiScript Language Standard Library 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
|
||||
/// to all standard ChaiScript applications, and provides a simple foundation for using numbers, strings, and ranges
|
||||
/// (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
|
||||
{
|
||||
/// \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 {
|
||||
public:
|
||||
/// \brief Returns the Type_Info value for this Object
|
||||
Type_Info get_type_info() const;
|
||||
@ -51,42 +47,39 @@ class Object
|
||||
///
|
||||
/// \sa Type_Info::name();
|
||||
string type_name() const;
|
||||
};
|
||||
};
|
||||
|
||||
/// \brief Item returned from a Range object from a Map
|
||||
class Map_Pair
|
||||
{
|
||||
/// \brief Item returned from a Range object from a Map
|
||||
class Map_Pair {
|
||||
public:
|
||||
/// \brief Returns the key of the Map entry
|
||||
const string first();
|
||||
|
||||
/// \brief Returns the value Object of the Map entry
|
||||
Object second();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/// \brief Maps strings to Objects
|
||||
///
|
||||
/// ChaiScript has a built in shortcut for generating Map objects:
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> var m = ["a":1, "b":2];
|
||||
/// [<a,1>, <b,2>]
|
||||
/// eval> m.count("a");
|
||||
/// 1
|
||||
/// eval> m.count("c");
|
||||
/// 0
|
||||
/// eval> m.size();
|
||||
/// 2
|
||||
/// \endcode
|
||||
///
|
||||
/// Implemented as std::map<Boxed_Value>
|
||||
///
|
||||
/// \sa Map_Pair
|
||||
/// \sa chaiscript::bootstrap::standard_library::map_type
|
||||
class Map
|
||||
{
|
||||
/// \brief Maps strings to Objects
|
||||
///
|
||||
/// ChaiScript has a built in shortcut for generating Map objects:
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> var m = ["a":1, "b":2];
|
||||
/// [<a,1>, <b,2>]
|
||||
/// eval> m.count("a");
|
||||
/// 1
|
||||
/// eval> m.count("c");
|
||||
/// 0
|
||||
/// eval> m.size();
|
||||
/// 2
|
||||
/// \endcode
|
||||
///
|
||||
/// Implemented as std::map<Boxed_Value>
|
||||
///
|
||||
/// \sa Map_Pair
|
||||
/// \sa chaiscript::bootstrap::standard_library::map_type
|
||||
class Map {
|
||||
public:
|
||||
/// \brief Returns an object that implements the Range concept for the Map_Pair's in this Map
|
||||
Range range();
|
||||
@ -108,64 +101,57 @@ class Map
|
||||
|
||||
/// \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 convertible 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
|
||||
/// eval> to_string(3).is_type("string") <br>
|
||||
/// true<br>
|
||||
/// \endcode
|
||||
string to_string(Object o);
|
||||
|
||||
/// \brief Converts o into a string.
|
||||
///
|
||||
/// \code
|
||||
/// eval> to_string(3).is_type("string") <br>
|
||||
/// true<br>
|
||||
/// \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")
|
||||
/// hi, thereeval>
|
||||
/// \endcode
|
||||
/// \sa to_string
|
||||
/// \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")
|
||||
/// hello
|
||||
/// eval>
|
||||
/// \endcode
|
||||
/// \sa to_string
|
||||
/// \sa puts
|
||||
void print(Object o);
|
||||
|
||||
/// \brief Prints o to the terminal, without a trailing carriage return. Applies conversions to string automatically.
|
||||
/// \code
|
||||
/// eval> puts("hi, "); puts("there")
|
||||
/// hi, thereeval>
|
||||
/// \endcode
|
||||
/// \sa to_string
|
||||
/// \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")
|
||||
/// hello
|
||||
/// eval>
|
||||
/// \endcode
|
||||
/// \sa to_string
|
||||
/// \sa puts
|
||||
void print(Object o);
|
||||
|
||||
/// \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
|
||||
/// 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
|
||||
/// std::string of the same name.
|
||||
///
|
||||
/// \note Object and function notations are equivalent in ChaiScript. This means that
|
||||
/// \c "bob".find("b") and \c find("bob", "b") are exactly the same. Most examples below follow the
|
||||
/// 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
|
||||
{
|
||||
/// \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
|
||||
/// 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
|
||||
/// std::string of the same name.
|
||||
///
|
||||
/// \note Object and function notations are equivalent in ChaiScript. This means that
|
||||
/// \c "bob".find("b") and \c find("bob", "b") are exactly the same. Most examples below follow the
|
||||
/// 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 {
|
||||
public:
|
||||
/// \brief Finds the first instance of substr.
|
||||
/// \code
|
||||
@ -174,7 +160,6 @@ class string
|
||||
/// \endcode
|
||||
int find(string s) const;
|
||||
|
||||
|
||||
/// \brief Finds the last instance of substr.
|
||||
/// \code
|
||||
/// eval> rfind("abab", "ab")
|
||||
@ -281,16 +266,15 @@ class string
|
||||
|
||||
/// \brief Returns an object that implements the Const_Range concept for the characters of this string
|
||||
Const_Range range() const;
|
||||
};
|
||||
};
|
||||
|
||||
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
|
||||
/// easy iteration over the elements in a container.
|
||||
///
|
||||
/// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range
|
||||
///
|
||||
/// \sa Const_Range
|
||||
class Range
|
||||
{
|
||||
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
|
||||
/// easy iteration over the elements in a container.
|
||||
///
|
||||
/// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range
|
||||
///
|
||||
/// \sa Const_Range
|
||||
class Range {
|
||||
public:
|
||||
/// \brief Returns the last item of the range
|
||||
Object back();
|
||||
@ -311,17 +295,15 @@ class Range
|
||||
///
|
||||
/// \post front() returns the element at front() + 1;
|
||||
void pop_front();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
|
||||
/// easy iteration over the elements in a container. Contained values are const.
|
||||
///
|
||||
/// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range
|
||||
///
|
||||
/// \sa Range
|
||||
class Const_Range
|
||||
{
|
||||
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
|
||||
/// easy iteration over the elements in a container. Contained values are const.
|
||||
///
|
||||
/// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range
|
||||
///
|
||||
/// \sa Range
|
||||
class Const_Range {
|
||||
public:
|
||||
/// \brief Returns the last item of the range
|
||||
const Object back();
|
||||
@ -342,28 +324,26 @@ class Const_Range
|
||||
///
|
||||
/// \post front() returns the element at front() + 1;
|
||||
void pop_front();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/// \brief A vector of Objects
|
||||
///
|
||||
/// ChaiScript includes a shortcut for creating a Vector of Objects
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> var v = [1,2,3,4]
|
||||
/// [1, 2, 3, 4]
|
||||
/// eval> v[0];
|
||||
/// 1
|
||||
/// eval> v.size();
|
||||
/// 4
|
||||
/// \endcode
|
||||
///
|
||||
/// Implemented with std::vector<chaiscript::Boxed_Value>
|
||||
///
|
||||
/// \sa chaiscript::bootstrap::standard_library::vector_type
|
||||
class Vector
|
||||
{
|
||||
/// \brief A vector of Objects
|
||||
///
|
||||
/// ChaiScript includes a shortcut for creating a Vector of Objects
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> var v = [1,2,3,4]
|
||||
/// [1, 2, 3, 4]
|
||||
/// eval> v[0];
|
||||
/// 1
|
||||
/// eval> v.size();
|
||||
/// 4
|
||||
/// \endcode
|
||||
///
|
||||
/// Implemented with std::vector<chaiscript::Boxed_Value>
|
||||
///
|
||||
/// \sa chaiscript::bootstrap::standard_library::vector_type
|
||||
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);
|
||||
@ -417,11 +397,9 @@ class Vector
|
||||
|
||||
/// \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.
|
||||
@ -450,32 +428,29 @@ class Type_Info
|
||||
|
||||
/// \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:
|
||||
/// \code
|
||||
/// var f = fun(x) { return x; }
|
||||
/// \endcode
|
||||
///
|
||||
/// Or it may represent multiple functions
|
||||
/// \code
|
||||
/// var f2 = `-`; // represents the unary - as well as the set of binary - operators
|
||||
/// \endcode
|
||||
///
|
||||
/// Guarded function example
|
||||
/// \code
|
||||
/// def f3(x) : x > 2 {
|
||||
/// return x;
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// Examples in the function definitions below will reference these examples
|
||||
class Function
|
||||
{
|
||||
/// \brief Represents a function object in ChaiScript
|
||||
///
|
||||
/// A function object may be one function, such as:
|
||||
/// \code
|
||||
/// var f = fun(x) { return x; }
|
||||
/// \endcode
|
||||
///
|
||||
/// Or it may represent multiple functions
|
||||
/// \code
|
||||
/// var f2 = `-`; // represents the unary - as well as the set of binary - operators
|
||||
/// \endcode
|
||||
///
|
||||
/// Guarded function example
|
||||
/// \code
|
||||
/// def f3(x) : x > 2 {
|
||||
/// return x;
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// Examples in the function definitions below will reference these examples
|
||||
class Function {
|
||||
public:
|
||||
/// \brief Returns the annotation description of the function
|
||||
string get_annotation() const;
|
||||
@ -545,286 +520,264 @@ class Function
|
||||
/// 1
|
||||
/// \endcode
|
||||
Object call(Vector t_params) const;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Returns the max of a or b. Requires that operator>(a, b) exists
|
||||
/// Equivalent to
|
||||
/// \code
|
||||
/// return a>b?a:b;
|
||||
/// \endcode
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> max(4, 10)
|
||||
/// 10
|
||||
/// \endcode
|
||||
Object
|
||||
max(Object a, Object b);
|
||||
|
||||
/// \brief Returns the min of a or b. Requires that operator<(a, b) exists
|
||||
///
|
||||
/// Equivalent to
|
||||
/// \code
|
||||
/// return a<b?a:b;
|
||||
/// \endcode
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> min(4, 10)
|
||||
/// 4
|
||||
/// \endcode
|
||||
Object min(Object a, Object b);
|
||||
|
||||
/// \brief Returns the max of a or b. Requires that operator>(a, b) exists
|
||||
/// Equivalent to
|
||||
/// \code
|
||||
/// return a>b?a:b;
|
||||
/// \endcode
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> max(4, 10)
|
||||
/// 10
|
||||
/// \endcode
|
||||
Object max(Object a, Object b);
|
||||
/// \brief Returns true if x is an even integer.
|
||||
///
|
||||
/// Will also work on any non-integer type for which an operator%(x, int) exists
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> even(4)
|
||||
/// true
|
||||
/// \endcode
|
||||
bool even(Object x);
|
||||
|
||||
/// \brief Returns the min of a or b. Requires that operator<(a, b) exists
|
||||
///
|
||||
/// Equivalent to
|
||||
/// \code
|
||||
/// return a<b?a:b;
|
||||
/// \endcode
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> min(4, 10)
|
||||
/// 4
|
||||
/// \endcode
|
||||
Object min(Object a, Object b);
|
||||
/// \brief Returns true if x is an odd integer.
|
||||
///
|
||||
/// Will also work on any non-integer type for which an operator%(x, int) exists
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> odd(4)
|
||||
/// false
|
||||
/// \endcode
|
||||
bool even(Object x);
|
||||
|
||||
/// \brief Returns true if x is an even integer.
|
||||
///
|
||||
/// Will also work on any non-integer type for which an operator%(x, int) exists
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> even(4)
|
||||
/// true
|
||||
/// \endcode
|
||||
bool even(Object x);
|
||||
/// \brief Applies the function f over each element in the Range c.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> for_each([1, 2, 3], print)
|
||||
/// 1
|
||||
/// 2
|
||||
/// 3
|
||||
/// \endcode
|
||||
void for_each(Range c, Function f);
|
||||
|
||||
/// \brief Returns true if x is an odd integer.
|
||||
///
|
||||
/// Will also work on any non-integer type for which an operator%(x, int) exists
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> odd(4)
|
||||
/// false
|
||||
/// \endcode
|
||||
bool even(Object x);
|
||||
/// \brief Applies f over each element in the Range c, joining all the results.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> map([1, 2, 3], odd)
|
||||
/// [true, false, true]
|
||||
/// \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.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> foldl([1, 2, 3, 4], `+`, 0)
|
||||
/// 10
|
||||
/// \endcode
|
||||
Object foldl(Range c, Function f, Object initial);
|
||||
|
||||
/// \brief Applies the function f over each element in the Range c.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> for_each([1, 2, 3], print)
|
||||
/// 1
|
||||
/// 2
|
||||
/// 3
|
||||
/// \endcode
|
||||
void for_each(Range c, Function f);
|
||||
/// \brief Returns the sum total of the values in the Range c.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> sum([1, 2, 3, 4])
|
||||
/// 10
|
||||
/// \endcode
|
||||
///
|
||||
/// Equivalent to:
|
||||
/// \code
|
||||
/// foldl(c, `+`, 0.0);
|
||||
/// \endcode
|
||||
Numeric sum(Range c);
|
||||
|
||||
/// \brief Returns the product of the value in the Range c.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> product([1, 2, 3, 4])
|
||||
/// 24
|
||||
/// \endcode
|
||||
///
|
||||
/// Equivalent to:
|
||||
/// \code
|
||||
/// foldl(c, `*`, 1.0);
|
||||
/// \endcode
|
||||
Numeric product(Range c);
|
||||
|
||||
/// \brief Applies f over each element in the Range c, joining all the results.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> map([1, 2, 3], odd)
|
||||
/// [true, false, true]
|
||||
/// \endcode
|
||||
Object map(Range c, Function f);
|
||||
/// \brief Takes num elements from the Range c, returning them.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> take([1, 2, 3, 4], 2)
|
||||
/// [1, 2]
|
||||
/// \endcode
|
||||
///
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> take_while([1, 2, 3], odd)
|
||||
/// [1]
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns A container of the same type that was passed in
|
||||
Object take_while(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.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> foldl([1, 2, 3, 4], `+`, 0)
|
||||
/// 10
|
||||
/// \endcode
|
||||
Object foldl(Range c, Function f, Object initial);
|
||||
/// \brief Drops num elements from the Range c, returning the remainder.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> drop([1, 2, 3, 4], 2)
|
||||
/// [3, 4]
|
||||
/// \endcode
|
||||
///
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> drop_while([1, 2, 3], odd)
|
||||
/// [2, 3]
|
||||
/// \endcode
|
||||
Object drop_while(Range c, Function f);
|
||||
|
||||
/// \brief Returns the sum total of the values in the Range c.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> sum([1, 2, 3, 4])
|
||||
/// 10
|
||||
/// \endcode
|
||||
///
|
||||
/// Equivalent to:
|
||||
/// \code
|
||||
/// foldl(c, `+`, 0.0);
|
||||
/// \endcode
|
||||
Numeric sum(Range c);
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> reduce([1, 2, 3, 4], `+`)
|
||||
/// 10
|
||||
/// \endcode
|
||||
Object reduce(Range c, Function f);
|
||||
|
||||
/// \brief Takes elements from Container 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);
|
||||
|
||||
/// \brief Returns the product of the value in the Range c.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> product([1, 2, 3, 4])
|
||||
/// 24
|
||||
/// \endcode
|
||||
///
|
||||
/// Equivalent to:
|
||||
/// \code
|
||||
/// foldl(c, `*`, 1.0);
|
||||
/// \endcode
|
||||
Numeric product(Range c);
|
||||
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> join([1, 2, 3], "*")
|
||||
/// 1*2*3
|
||||
/// \endcode
|
||||
string join(Range c, string delim);
|
||||
|
||||
/// \brief Returns the contents of the Container c in reversed order.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> reverse([1, 2, 3, 4, 5, 6, 7])
|
||||
/// [7, 6, 5, 4, 3, 2, 1]
|
||||
/// \endcode
|
||||
Container reverse(Container c);
|
||||
|
||||
/// \brief Takes num elements from the Range c, returning them.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> take([1, 2, 3, 4], 2)
|
||||
/// [1, 2]
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns A container of the same type that was passed in
|
||||
Object take(Range c, int num);
|
||||
/// \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)
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> generate_range(1, 10)
|
||||
/// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
/// \endcode
|
||||
Vector generate_range(Object x, Object y);
|
||||
|
||||
/// \brief Returns a new Range with x and y concatenated.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> concat([1, 2, 3], [4, 5, 6])
|
||||
/// [1, 2, 3, 4, 5, 6]
|
||||
/// \endcode
|
||||
Object concat(Range x, Range y);
|
||||
|
||||
/// \brief Takes elements from the Range c that match function f, stopping at the first non-match, returning them as a new Vector.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> take_while([1, 2, 3], odd)
|
||||
/// [1]
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns A container of the same type that was passed in
|
||||
Object take_while(Range c, Function f);
|
||||
/// \brief Returns a new Vector with x and y as its values.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> collate(1, 2)
|
||||
/// [1, 2]
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> zip_with(`+`, [1, 2, 3], [4, 5, 6])
|
||||
/// [5, 7, 9]
|
||||
/// \endcode
|
||||
Vector zip_with(Function f, Range x, Range y);
|
||||
|
||||
/// \brief Drops num elements from the Range c, returning the remainder.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> drop([1, 2, 3, 4], 2)
|
||||
/// [3, 4]
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns A container of the same type that was passed in
|
||||
Object drop(Range c, int num);
|
||||
/// \brief Collates elements of x and y, returning a new Vector with the result.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> zip([1, 2, 3], [4, 5, 6])
|
||||
/// [[1, 4], [2, 5], [3, 6]]
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> call_exists(`+`, 1, 2)
|
||||
/// true
|
||||
/// \endcode
|
||||
bool call_exists(Function f, ...);
|
||||
|
||||
/// \brief Drops elements from the Range c that match f, stopping at the first non-match, returning the remainder.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> drop_while([1, 2, 3], odd)
|
||||
/// [2, 3]
|
||||
/// \endcode
|
||||
Object drop_while(Range c, Function f);
|
||||
/// \brief Reverses a Range object so that the elements are accessed in reverse
|
||||
Range retro(Range);
|
||||
|
||||
/// \brief Reverses a Const_Range object so that the elements are accessed in reverse
|
||||
Const_Range retro(Const_Range);
|
||||
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> reduce([1, 2, 3, 4], `+`)
|
||||
/// 10
|
||||
/// \endcode
|
||||
Object reduce(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Takes elements from Container 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);
|
||||
|
||||
|
||||
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> join([1, 2, 3], "*")
|
||||
/// 1*2*3
|
||||
/// \endcode
|
||||
string join(Range c, string delim);
|
||||
|
||||
|
||||
/// \brief Returns the contents of the Container c in reversed order.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> reverse([1, 2, 3, 4, 5, 6, 7])
|
||||
/// [7, 6, 5, 4, 3, 2, 1]
|
||||
/// \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)
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> generate_range(1, 10)
|
||||
/// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
/// \endcode
|
||||
Vector generate_range(Object x, Object y);
|
||||
|
||||
|
||||
/// \brief Returns a new Range with x and y concatenated.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> concat([1, 2, 3], [4, 5, 6])
|
||||
/// [1, 2, 3, 4, 5, 6]
|
||||
/// \endcode
|
||||
Object concat(Range x, Range y);
|
||||
|
||||
|
||||
/// \brief Returns a new Vector with x and y as its values.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> collate(1, 2)
|
||||
/// [1, 2]
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> zip_with(`+`, [1, 2, 3], [4, 5, 6])
|
||||
/// [5, 7, 9]
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> zip([1, 2, 3], [4, 5, 6])
|
||||
/// [[1, 4], [2, 5], [3, 6]]
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> call_exists(`+`, 1, 2)
|
||||
/// true
|
||||
/// \endcode
|
||||
bool call_exists(Function f, ...);
|
||||
|
||||
/// \brief Reverses a Range object so that the elements are accessed in reverse
|
||||
Range retro(Range);
|
||||
|
||||
/// \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:
|
||||
/// \code
|
||||
/// eval> try { throw(1); } catch (e) { print("Exception caught: " + to_string(e)); }
|
||||
/// Exception caught: 1
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keywordtry
|
||||
void throw(Object);
|
||||
}
|
||||
|
||||
/// \brief Raises the given object as an exception. Any type of object can be thrown.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> try { throw(1); } catch (e) { print("Exception caught: " + to_string(e)); }
|
||||
/// Exception caught: 1
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keywordtry
|
||||
void throw(Object);
|
||||
} // namespace ChaiScript_Language
|
||||
|
||||
@ -1,35 +1,28 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_TRACER_HPP_
|
||||
#define CHAISCRIPT_TRACER_HPP_
|
||||
|
||||
namespace chaiscript {
|
||||
namespace eval {
|
||||
|
||||
|
||||
struct Noop_Tracer_Detail
|
||||
{
|
||||
namespace chaiscript::eval {
|
||||
struct Noop_Tracer_Detail {
|
||||
template<typename T>
|
||||
void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
|
||||
{
|
||||
constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *) noexcept {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ... T>
|
||||
struct Tracer : T...
|
||||
{
|
||||
template<typename... T>
|
||||
struct Tracer : T... {
|
||||
Tracer() = default;
|
||||
explicit Tracer(T ... t)
|
||||
: T(std::move(t))...
|
||||
{
|
||||
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) {
|
||||
(void)std::initializer_list<int>{ (static_cast<T&>(*this).trace(ds, node), 0)... };
|
||||
(static_cast<T &>(*this).trace(ds, node), ...);
|
||||
}
|
||||
|
||||
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
|
||||
@ -37,10 +30,8 @@ namespace chaiscript {
|
||||
}
|
||||
};
|
||||
|
||||
typedef Tracer<Noop_Tracer_Detail> Noop_Tracer;
|
||||
using Noop_Tracer = Tracer<Noop_Tracer_Detail>;
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace chaiscript::eval
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,21 +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-2017, Jason Turner (jason@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 &)
|
||||
{
|
||||
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
|
||||
@ -25,7 +20,6 @@ namespace chaiscript
|
||||
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace chaiscript
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_WINDOWS_HPP_
|
||||
@ -17,42 +17,33 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
namespace chaiscript {
|
||||
namespace detail {
|
||||
struct Loadable_Module {
|
||||
template<typename T>
|
||||
static std::wstring to_wstring(const T &t_str)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
static std::string to_proper_string(const T &t_str) {
|
||||
return to_string(t_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string get_error_message(DWORD t_err)
|
||||
{
|
||||
typedef LPTSTR StringType;
|
||||
static std::string get_error_message(DWORD t_err) {
|
||||
using StringType = LPTSTR;
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
std::wstring retval = L"Unknown Error";
|
||||
@ -61,16 +52,15 @@ namespace chaiscript
|
||||
#endif
|
||||
StringType lpMsgBuf = nullptr;
|
||||
|
||||
if (FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
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)
|
||||
{
|
||||
0,
|
||||
nullptr)
|
||||
!= 0
|
||||
&& lpMsgBuf) {
|
||||
retval = lpMsgBuf;
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
@ -78,13 +68,10 @@ namespace chaiscript
|
||||
return to_string(retval);
|
||||
}
|
||||
|
||||
struct DLModule
|
||||
{
|
||||
struct DLModule {
|
||||
explicit DLModule(const std::string &t_filename)
|
||||
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
: m_data(LoadLibrary(to_proper_string(t_filename).c_str())) {
|
||||
if (!m_data) {
|
||||
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
|
||||
}
|
||||
}
|
||||
@ -94,22 +81,16 @@ namespace chaiscript
|
||||
DLModule(const DLModule &) = delete;
|
||||
DLModule &operator=(const DLModule &) = delete;
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
FreeLibrary(m_data);
|
||||
}
|
||||
~DLModule() { FreeLibrary(m_data); }
|
||||
|
||||
HMODULE m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
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)
|
||||
{
|
||||
: 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()));
|
||||
}
|
||||
}
|
||||
@ -118,16 +99,15 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
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())
|
||||
{
|
||||
: 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
|
||||
|
||||
|
||||
@ -1,25 +1,17 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
|
||||
namespace utility
|
||||
{
|
||||
|
||||
|
||||
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
|
||||
@ -30,7 +22,7 @@ namespace chaiscript
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4307)
|
||||
#endif
|
||||
return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193));
|
||||
return (*s == 0) ? h : fnv1a_32(s + 1, ((h ^ (*s)) * 0x01000193));
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
@ -38,13 +30,9 @@ namespace chaiscript
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} // namespace utility
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
94
include/chaiscript/utility/hash.hpp
Normal file
94
include/chaiscript/utility/hash.hpp
Normal file
@ -0,0 +1,94 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace chaiscript {
|
||||
namespace utility {
|
||||
namespace fnv1a {
|
||||
template<typename Itr>
|
||||
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4307)
|
||||
#endif
|
||||
std::uint32_t h = 0x811c9dc5;
|
||||
|
||||
while (begin != end) {
|
||||
h = (h ^ (*begin)) * 0x01000193;
|
||||
++begin;
|
||||
}
|
||||
return h;
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
|
||||
return hash(std::begin(str), std::end(str) - 1);
|
||||
}
|
||||
|
||||
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
|
||||
return hash(sv.begin(), sv.end());
|
||||
}
|
||||
|
||||
static inline std::uint32_t hash(const std::string &s) noexcept {
|
||||
return hash(s.begin(), s.end());
|
||||
}
|
||||
} // namespace fnv1a
|
||||
|
||||
namespace jenkins_one_at_a_time {
|
||||
template<typename Itr>
|
||||
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
|
||||
std::uint32_t hash = 0;
|
||||
|
||||
while (begin != end) {
|
||||
hash += std::uint32_t(*begin);
|
||||
hash += hash << 10;
|
||||
hash ^= hash >> 6;
|
||||
++begin;
|
||||
}
|
||||
|
||||
hash += hash << 3;
|
||||
hash ^= hash >> 11;
|
||||
hash += hash << 15;
|
||||
return hash;
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
|
||||
return hash(std::begin(str), std::end(str) - 1);
|
||||
}
|
||||
|
||||
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
|
||||
return hash(sv.begin(), sv.end());
|
||||
}
|
||||
|
||||
static inline std::uint32_t hash(const std::string &s) noexcept {
|
||||
return hash(s.begin(), s.end());
|
||||
}
|
||||
} // namespace jenkins_one_at_a_time
|
||||
|
||||
using fnv1a::hash;
|
||||
} // namespace utility
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,46 +3,34 @@
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class json_wrap
|
||||
{
|
||||
namespace chaiscript {
|
||||
class json_wrap {
|
||||
public:
|
||||
|
||||
static Module& library(Module& m)
|
||||
{
|
||||
|
||||
static Module &library(Module &m) {
|
||||
m.add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
|
||||
m.add(chaiscript::fun(&json_wrap::to_json), "to_json");
|
||||
|
||||
return m;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static Boxed_Value from_json(const json::JSON &t_json)
|
||||
{
|
||||
switch( t_json.JSONType() ) {
|
||||
static Boxed_Value from_json(const json::JSON &t_json) {
|
||||
switch (t_json.JSONType()) {
|
||||
case json::JSON::Class::Null:
|
||||
return Boxed_Value();
|
||||
case json::JSON::Class::Object:
|
||||
{
|
||||
case json::JSON::Class::Object: {
|
||||
std::map<std::string, Boxed_Value> m;
|
||||
|
||||
for (const auto &p : t_json.object_range())
|
||||
{
|
||||
for (const auto &p : t_json.object_range()) {
|
||||
m.insert(std::make_pair(p.first, from_json(p.second)));
|
||||
}
|
||||
|
||||
return Boxed_Value(m);
|
||||
}
|
||||
case json::JSON::Class::Array:
|
||||
{
|
||||
case json::JSON::Class::Array: {
|
||||
std::vector<Boxed_Value> vec;
|
||||
|
||||
for (const auto &p : t_json.array_range())
|
||||
{
|
||||
for (const auto &p : t_json.array_range()) {
|
||||
vec.emplace_back(from_json(p));
|
||||
}
|
||||
|
||||
@ -61,28 +49,22 @@ namespace chaiscript
|
||||
throw std::runtime_error("Unknown JSON type");
|
||||
}
|
||||
|
||||
static Boxed_Value from_json(const std::string &t_json)
|
||||
{
|
||||
static Boxed_Value from_json(const std::string &t_json) {
|
||||
try {
|
||||
return from_json( json::JSON::Load(t_json) );
|
||||
} catch (const std::out_of_range& ) {
|
||||
return from_json(json::JSON::Load(t_json));
|
||||
} catch (const std::out_of_range &) {
|
||||
throw std::runtime_error("Unparsed JSON input");
|
||||
}
|
||||
}
|
||||
|
||||
static std::string to_json(const Boxed_Value &t_bv)
|
||||
{
|
||||
return to_json_object(t_bv).dump();
|
||||
}
|
||||
static std::string to_json(const Boxed_Value &t_bv) { return to_json_object(t_bv).dump(); }
|
||||
|
||||
static json::JSON to_json_object(const Boxed_Value &t_bv)
|
||||
{
|
||||
static json::JSON to_json_object(const Boxed_Value &t_bv) {
|
||||
try {
|
||||
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv);
|
||||
|
||||
json::JSON obj(json::JSON::Class::Object);
|
||||
for (const auto &o : m)
|
||||
{
|
||||
for (const auto &o : m) {
|
||||
obj[o.first] = to_json_object(o.second);
|
||||
}
|
||||
return obj;
|
||||
@ -94,8 +76,7 @@ namespace chaiscript
|
||||
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
|
||||
|
||||
json::JSON obj(json::JSON::Class::Array);
|
||||
for (size_t i = 0; i < v.size(); ++i)
|
||||
{
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
obj[i] = to_json_object(v[i]);
|
||||
}
|
||||
return obj;
|
||||
@ -103,11 +84,9 @@ namespace chaiscript
|
||||
// not a vector
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
Boxed_Number bn(t_bv);
|
||||
if (Boxed_Number::is_floating_point(t_bv))
|
||||
{
|
||||
if (Boxed_Number::is_floating_point(t_bv)) {
|
||||
return json::JSON(bn.get_as<double>());
|
||||
} else {
|
||||
return json::JSON(bn.get_as<std::int64_t>());
|
||||
@ -128,13 +107,11 @@ namespace chaiscript
|
||||
// not a string
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
|
||||
|
||||
json::JSON obj(json::JSON::Class::Object);
|
||||
for (const auto &attr : o.get_attrs())
|
||||
{
|
||||
for (const auto &attr : o.get_attrs()) {
|
||||
obj[attr.first] = to_json_object(attr.second);
|
||||
}
|
||||
return obj;
|
||||
@ -142,15 +119,13 @@ namespace chaiscript
|
||||
// not a dynamic object
|
||||
}
|
||||
|
||||
if (t_bv.is_null()) return json::JSON(); // a null value
|
||||
if (t_bv.is_null())
|
||||
return json::JSON(); // a null value
|
||||
|
||||
throw std::runtime_error("Unknown object type to convert to JSON");
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
} // namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
133
include/chaiscript/utility/quick_flat_map.hpp
Normal file
133
include/chaiscript/utility/quick_flat_map.hpp
Normal file
@ -0,0 +1,133 @@
|
||||
#ifndef CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP
|
||||
#define CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP
|
||||
|
||||
namespace chaiscript::utility {
|
||||
template<typename Key, typename Value, typename Comparator = std::equal_to<>>
|
||||
struct QuickFlatMap {
|
||||
Comparator comparator;
|
||||
|
||||
template<typename Lookup>
|
||||
auto find(const Lookup &s) noexcept {
|
||||
return std::find_if(std::begin(data), std::end(data), [&s, this](const auto &d) { return comparator(d.first, s); });
|
||||
}
|
||||
|
||||
template<typename Lookup>
|
||||
auto find(const Lookup &s) const noexcept {
|
||||
return std::find_if(std::cbegin(data), std::cend(data), [&s, this](const auto &d) { return comparator(d.first, s); });
|
||||
}
|
||||
|
||||
template<typename Lookup>
|
||||
auto find(const Lookup &s, const std::size_t t_hint) const noexcept {
|
||||
if (data.size() > t_hint && comparator(data[t_hint].first, s)) {
|
||||
const auto begin = std::cbegin(data);
|
||||
return std::next(begin, static_cast<typename std::iterator_traits<std::decay_t<decltype(begin)>>::difference_type>(t_hint));
|
||||
} else {
|
||||
return find(s);
|
||||
}
|
||||
}
|
||||
|
||||
auto size() const noexcept { return data.size(); }
|
||||
|
||||
auto begin() const noexcept { return data.begin(); }
|
||||
|
||||
auto end() const noexcept { return data.end(); }
|
||||
|
||||
auto begin() noexcept { return data.begin(); }
|
||||
|
||||
auto end() noexcept { return data.end(); }
|
||||
|
||||
auto &back() noexcept { return data.back(); }
|
||||
|
||||
const auto &back() const noexcept { return data.back(); }
|
||||
|
||||
Value &operator[](const Key &s) {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
grow();
|
||||
return data.emplace_back(s, Value()).second;
|
||||
}
|
||||
}
|
||||
|
||||
Value &at_index(const std::size_t idx) noexcept { return data[idx].second; }
|
||||
|
||||
const Value &at_index(const std::size_t idx) const noexcept { return data[idx].second; }
|
||||
|
||||
bool empty() const noexcept { return data.empty(); }
|
||||
|
||||
template<typename Itr>
|
||||
void assign(Itr begin, Itr end) {
|
||||
data.assign(begin, end);
|
||||
}
|
||||
|
||||
Value &at(const Key &s) {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
throw std::out_of_range("Unknown key: " + s);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
auto insert_or_assign(Key &&key, M &&m) {
|
||||
if (auto itr = find(key); itr != data.end()) {
|
||||
*itr = std::forward<M>(m);
|
||||
return std::pair{itr, false};
|
||||
} else {
|
||||
grow();
|
||||
return std::pair{data.emplace(data.end(), std::move(key), std::forward<M>(m)), true};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M>
|
||||
auto insert_or_assign(const Key &key, M &&m) {
|
||||
if (auto itr = find(key); itr != data.end()) {
|
||||
itr->second = std::forward<M>(m);
|
||||
return std::pair{itr, false};
|
||||
} else {
|
||||
grow();
|
||||
return std::pair{data.emplace(data.end(), key, std::forward<M>(m)), true};
|
||||
}
|
||||
}
|
||||
|
||||
const Value &at(const Key &s) const {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
throw std::out_of_range("Unknown key: " + s);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Lookup>
|
||||
size_t count(const Lookup &s) const noexcept {
|
||||
return (find(s) != data.end()) ? 1 : 0;
|
||||
}
|
||||
|
||||
std::vector<std::pair<Key, Value>> data;
|
||||
|
||||
using value_type = std::pair<Key, Value>;
|
||||
using iterator = typename decltype(data)::iterator;
|
||||
using const_iterator = typename decltype(data)::const_iterator;
|
||||
|
||||
std::pair<iterator, bool> insert(value_type &&value) {
|
||||
if (const auto itr = find(value.first); itr != data.end()) {
|
||||
return std::pair{itr, false};
|
||||
} else {
|
||||
grow();
|
||||
return std::pair{data.insert(data.end(), std::move(value)), true};
|
||||
}
|
||||
}
|
||||
|
||||
void grow() {
|
||||
if ((data.capacity() - data.size()) == 0) {
|
||||
data.reserve(data.size() + 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace chaiscript::utility
|
||||
|
||||
#endif
|
||||
49
include/chaiscript/utility/stack_vector.hpp
Normal file
49
include/chaiscript/utility/stack_vector.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
#ifndef CHAISCRIPT_STACK_VECTOR_HPP_
|
||||
#define CHAISCRIPT_STACK_VECTOR_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
template<typename T, std::size_t MaxSize>
|
||||
struct Stack_Vector {
|
||||
constexpr static auto aligned_size = sizeof(T) + (sizeof(T) & std::alignment_of_v<T>) > 0 ? std::alignment_of_v<T> : 0;
|
||||
|
||||
alignas(std::alignment_of_v<T>) char data[aligned_size * MaxSize];
|
||||
|
||||
[[nodiscard]] T &operator[](const std::size_t idx) noexcept { return *reinterpret_cast<T *>(&data + aligned_size * idx); }
|
||||
|
||||
[[nodiscard]] const T &operator[](const std::size_t idx) const noexcept {
|
||||
return *reinterpret_cast<const T *>(&data + aligned_size * idx);
|
||||
}
|
||||
|
||||
template<typename... Param>
|
||||
T &emplace_back(Param &&...param) {
|
||||
auto *p = new (&(*this)[m_size++]) T(std::forward<Param>(param)...);
|
||||
return *p;
|
||||
};
|
||||
|
||||
auto size() const noexcept { return m_size; };
|
||||
|
||||
void pop_back() noexcept(std::is_nothrow_destructible_v<T>) { (*this)[--m_size].~T(); }
|
||||
|
||||
~Stack_Vector() noexcept(std::is_nothrow_destructible_v<T>) {
|
||||
auto loc = m_size - 1;
|
||||
for (std::size_t pos = 0; pos < m_size; ++pos) {
|
||||
(*this)[loc--].~T();
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t m_size{0};
|
||||
};
|
||||
|
||||
#endif CHAISCRIPT_STACK_VECTOR_HPP_
|
||||
@ -1,37 +1,54 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
|
||||
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
|
||||
struct Static_String
|
||||
{
|
||||
namespace chaiscript::utility {
|
||||
struct Static_String {
|
||||
template<size_t N>
|
||||
constexpr Static_String(const char (&str)[N])
|
||||
: m_size(N-1), data(&str[0])
|
||||
{
|
||||
constexpr Static_String(const char (&str)[N]) noexcept
|
||||
: m_size(N - 1)
|
||||
, data(&str[0]) {
|
||||
}
|
||||
|
||||
constexpr size_t size() const {
|
||||
return m_size;
|
||||
constexpr size_t size() const noexcept { return m_size; }
|
||||
|
||||
constexpr const char *c_str() const noexcept { return data; }
|
||||
|
||||
constexpr auto begin() const noexcept { return data; }
|
||||
|
||||
constexpr auto end() const noexcept { return data + m_size; }
|
||||
|
||||
constexpr bool operator==(std::string_view other) const noexcept {
|
||||
// return std::string_view(data, m_size) == other;
|
||||
auto b1 = begin();
|
||||
const auto e1 = end();
|
||||
auto b2 = other.begin();
|
||||
const auto e2 = other.end();
|
||||
|
||||
if (e1 - b1 != e2 - b2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr const char *c_str() const {
|
||||
return data;
|
||||
while (b1 != e1) {
|
||||
if (*b1 != *b2) {
|
||||
return false;
|
||||
}
|
||||
++b1;
|
||||
++b2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator==(const std::string &t_str) const noexcept { return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str)); }
|
||||
|
||||
const size_t m_size;
|
||||
const char *data = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace chaiscript::utility
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// 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_UTILITY_UTILITY_HPP_
|
||||
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
|
||||
|
||||
@ -16,16 +15,11 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../language/chaiscript_common.hpp"
|
||||
#include "../dispatchkit/register_function.hpp"
|
||||
#include "../dispatchkit/operators.hpp"
|
||||
#include "../dispatchkit/register_function.hpp"
|
||||
#include "../language/chaiscript_common.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
|
||||
namespace chaiscript::utility {
|
||||
/// Single step command for registering a class with ChaiScript
|
||||
///
|
||||
/// \param[in,out] t_module Model to add class to
|
||||
@ -53,17 +47,14 @@ namespace chaiscript
|
||||
void add_class(ModuleType &t_module,
|
||||
const std::string &t_class_name,
|
||||
const std::vector<chaiscript::Proxy_Function> &t_constructors,
|
||||
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs)
|
||||
{
|
||||
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs) {
|
||||
t_module.add(chaiscript::user_type<Class>(), t_class_name);
|
||||
|
||||
for(const chaiscript::Proxy_Function &ctor: t_constructors)
|
||||
{
|
||||
for (const chaiscript::Proxy_Function &ctor : t_constructors) {
|
||||
t_module.add(ctor, t_class_name);
|
||||
}
|
||||
|
||||
for(const auto &fun: t_funcs)
|
||||
{
|
||||
for (const auto &fun : t_funcs) {
|
||||
t_module.add(fun.first, fun.second);
|
||||
}
|
||||
}
|
||||
@ -72,13 +63,11 @@ namespace chaiscript
|
||||
typename std::enable_if<std::is_enum<Enum>::value, void>::type
|
||||
add_class(ModuleType &t_module,
|
||||
const std::string &t_class_name,
|
||||
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants
|
||||
)
|
||||
{
|
||||
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants) {
|
||||
t_module.add(chaiscript::user_type<Enum>(), t_class_name);
|
||||
|
||||
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name);
|
||||
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
|
||||
t_module.add(chaiscript::constructor<Enum()>(), t_class_name);
|
||||
t_module.add(chaiscript::constructor<Enum(const Enum &)>(), t_class_name);
|
||||
|
||||
using namespace chaiscript::bootstrap::operators;
|
||||
equal<Enum>(t_module);
|
||||
@ -88,19 +77,14 @@ namespace chaiscript
|
||||
t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "==");
|
||||
t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "==");
|
||||
|
||||
for (const auto &constant : t_constants)
|
||||
{
|
||||
for (const auto &constant : t_constants) {
|
||||
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename EnumClass, typename ModuleType>
|
||||
typename std::enable_if<std::is_enum<EnumClass>::value, void>::type
|
||||
add_class(ModuleType &t_module,
|
||||
const std::string &t_class_name,
|
||||
const std::vector<std::pair<EnumClass, std::string>> &t_constants
|
||||
)
|
||||
{
|
||||
add_class(ModuleType &t_module, const std::string &t_class_name, const std::vector<std::pair<EnumClass, std::string>> &t_constants) {
|
||||
t_module.add(chaiscript::user_type<EnumClass>(), t_class_name);
|
||||
|
||||
t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name);
|
||||
@ -111,13 +95,10 @@ namespace chaiscript
|
||||
not_equal<EnumClass>(t_module);
|
||||
assign<EnumClass>(t_module);
|
||||
|
||||
for (const auto &constant : t_constants)
|
||||
{
|
||||
for (const auto &constant : t_constants) {
|
||||
t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace chaiscript::utility
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
BSD-3-Clause License
|
||||
|
||||
Copyright 2009-2016 Jason Turner
|
||||
Copyright 2009-2012 Jonathan Turner.
|
||||
Copyright 2009-2018 Jason Turner
|
||||
|
||||
All Rights Reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@ -5,9 +5,8 @@ double f(const std::string &, double, bool) noexcept {
|
||||
return .0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
int main() {
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
chai.add(chaiscript::fun(&f), "f");
|
||||
|
||||
@ -16,5 +15,4 @@ int main()
|
||||
f("str", 1.2, false);
|
||||
}
|
||||
)");
|
||||
|
||||
}
|
||||
|
||||
@ -5,16 +5,14 @@ double f(const std::string &, double, bool) noexcept {
|
||||
return .0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
int main() {
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
chai.add(chaiscript::fun(&f), "f");
|
||||
|
||||
const auto f = chai.eval<std::function<void ()>>(R"(fun(){ f("str", 1.2, false); })");
|
||||
const auto f = chai.eval<std::function<void()>>(R"(fun(){ f("str", 1.2, false); })");
|
||||
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
f();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
15
readme.md
15
readme.md
@ -29,7 +29,7 @@ Introduction
|
||||
|
||||
ChaiScript is one of the only embedded scripting language designed from the
|
||||
ground up to directly target C++ and take advantage of modern C++ development
|
||||
techniques, working with the developer like he expects it to work. Being a
|
||||
techniques, working with the developer how they would expect it to work. Being a
|
||||
native C++ application, it has some advantages over existing embedded scripting
|
||||
languages:
|
||||
|
||||
@ -48,6 +48,19 @@ templates. It has been tested with gcc 4.9 and clang 3.6 (with libcxx).
|
||||
For more information see the build
|
||||
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
|
||||
|
||||
Installation using vcpkg
|
||||
========================
|
||||
|
||||
You can download and install ChaiScript using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
|
||||
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
vcpkg install chaiscript
|
||||
|
||||
The ChaiScript port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
Notes:
|
||||
=======
|
||||
Current Version: 6.1.0
|
||||
Current Version: 6.1.1
|
||||
|
||||
### Changes since 6.1.0
|
||||
|
||||
* Handle the returning of `&` to `*` types. This specifically comes up with `std::vector<int *>` and similar containers
|
||||
* Update CMake to use `LIBDIR` instead of `lib` #502 by @guoyunhe
|
||||
* Add documentation for installing ChaiScript with vcpkg #500 by @grdowns
|
||||
* Fix warning for implicit 'this' lambda capture in C++20 #495 by @Josh-Thompson
|
||||
|
||||
### Changes since 6.0.0
|
||||
|
||||
@ -14,7 +21,6 @@ Current Version: 6.1.0
|
||||
* Support for C++17 compilers!
|
||||
* Support for UTF8 BOM #439 @AlekMosingiewicz @MarioLiebisch
|
||||
|
||||
|
||||
### Changes since 5.8.6
|
||||
|
||||
*6.0.0 is a massive rework compared to 5.x. It now requires a C++14 enabled compiler*
|
||||
|
||||
@ -1,52 +1,45 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
class Entity
|
||||
{
|
||||
public:
|
||||
class Entity {
|
||||
public:
|
||||
int width;
|
||||
int height;
|
||||
int x;
|
||||
int y;
|
||||
std::string name;
|
||||
|
||||
std::function<void (Entity &)> updater;
|
||||
std::function<void(Entity &)> updater;
|
||||
|
||||
Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name)
|
||||
: width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name))
|
||||
{
|
||||
: width(t_width)
|
||||
, height(t_height)
|
||||
, x(t_x)
|
||||
, y(t_y)
|
||||
, name(std::move(t_name)) {
|
||||
}
|
||||
};
|
||||
|
||||
class Factory
|
||||
{
|
||||
public:
|
||||
class Factory {
|
||||
public:
|
||||
// we may as well pass the parameters for the entity to the factory method, this does the initialization
|
||||
// in one step.
|
||||
Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name)
|
||||
{
|
||||
Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name) {
|
||||
auto entity = entities.insert({name, Entity{width, height, x, y, name}});
|
||||
return &(entity.first->second);
|
||||
}
|
||||
|
||||
Entity *get_entity(const std::string &name)
|
||||
{
|
||||
return &entities.at(name);
|
||||
}
|
||||
|
||||
Entity *get_entity(const std::string &name) { return &entities.at(name); }
|
||||
|
||||
// loop over all entities and all their updater function (if it exists)
|
||||
void update_entities()
|
||||
{
|
||||
for (auto &entity : entities)
|
||||
{
|
||||
void update_entities() {
|
||||
for (auto &entity : entities) {
|
||||
if (entity.second.updater) {
|
||||
entity.second.updater(entity.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
// we cannot store the entities in a std::vector if we want to return a pointer to them,
|
||||
// because a vector automatically resizing itself can invalidate the pointer that was returned.
|
||||
// using a map guarantees that the memory assigned to the entity will never change, plus
|
||||
@ -54,8 +47,7 @@ class Factory
|
||||
std::map<std::string, Entity> entities;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int main() {
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
chai.add(chaiscript::fun(&Entity::width), "width");
|
||||
@ -71,7 +63,6 @@ int main()
|
||||
chai.add(chaiscript::fun(&Factory::update_entities), "update_entities");
|
||||
chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer
|
||||
|
||||
|
||||
Factory f;
|
||||
chai.add(chaiscript::var(&f), "f");
|
||||
|
||||
@ -92,11 +83,5 @@ int main()
|
||||
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
|
||||
)"";
|
||||
|
||||
|
||||
chai.eval(script);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <regex>
|
||||
@ -19,14 +18,15 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
#else
|
||||
|
||||
char *mystrdup(const char *s) {
|
||||
size_t len = strlen(s); // Space for length plus nul
|
||||
char *d = static_cast<char*>(malloc(len + 1));
|
||||
if (d == nullptr) return nullptr; // No memory
|
||||
char *d = static_cast<char *>(malloc(len + 1));
|
||||
if (d == nullptr)
|
||||
return nullptr; // No memory
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
strcpy_s(d, len + 1, s); // Copy the characters
|
||||
#else
|
||||
@ -36,26 +36,20 @@ char *mystrdup(const char *s) {
|
||||
return d; // Return the new string
|
||||
}
|
||||
|
||||
char* readline(const char* p)
|
||||
{
|
||||
char *readline(const char *p) {
|
||||
std::string retval;
|
||||
std::cout << p;
|
||||
std::getline(std::cin, retval);
|
||||
return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
|
||||
}
|
||||
|
||||
|
||||
void add_history(const char*){}
|
||||
void using_history(){}
|
||||
void add_history(const char *) {}
|
||||
void using_history() {}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void *cast_module_symbol(std::vector<std::string>(*t_path)())
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
std::vector<std::string>(*in_ptr)();
|
||||
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
|
||||
union cast_union {
|
||||
std::vector<std::string> (*in_ptr)();
|
||||
void *out_ptr;
|
||||
};
|
||||
|
||||
@ -64,8 +58,7 @@ void *cast_module_symbol(std::vector<std::string>(*t_path)())
|
||||
return c.out_ptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> default_search_paths()
|
||||
{
|
||||
std::vector<std::string> default_search_paths() {
|
||||
std::vector<std::string> paths;
|
||||
|
||||
#ifndef CHAISCRIPT_NO_DYNLOAD
|
||||
@ -77,14 +70,12 @@ std::vector<std::string> default_search_paths()
|
||||
|
||||
size_t lastslash = exepath.rfind('\\');
|
||||
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
|
||||
if (lastslash != std::string::npos)
|
||||
{
|
||||
if (lastslash != std::string::npos) {
|
||||
paths.push_back(exepath.substr(0, lastslash));
|
||||
}
|
||||
|
||||
if (secondtolastslash != std::string::npos)
|
||||
{
|
||||
return{ exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\" };
|
||||
if (secondtolastslash != std::string::npos) {
|
||||
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
|
||||
}
|
||||
#else
|
||||
|
||||
@ -93,29 +84,23 @@ std::vector<std::string> default_search_paths()
|
||||
std::vector<char> buf(2048);
|
||||
ssize_t size = -1;
|
||||
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0)
|
||||
{
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0) {
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0)
|
||||
{
|
||||
if (exepath.empty()) {
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0) {
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0)
|
||||
{
|
||||
if (exepath.empty()) {
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0) {
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if (exepath.empty()) {
|
||||
Dl_info rInfo;
|
||||
memset(&rInfo, 0, sizeof(rInfo));
|
||||
if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) {
|
||||
@ -128,13 +113,11 @@ std::vector<std::string> default_search_paths()
|
||||
size_t lastslash = exepath.rfind('/');
|
||||
|
||||
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
|
||||
if (lastslash != std::string::npos)
|
||||
{
|
||||
if (lastslash != std::string::npos) {
|
||||
paths.push_back(exepath.substr(0, lastslash));
|
||||
}
|
||||
|
||||
if (secondtolastslash != std::string::npos)
|
||||
{
|
||||
if (secondtolastslash != std::string::npos) {
|
||||
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
|
||||
}
|
||||
#endif
|
||||
@ -145,46 +128,40 @@ std::vector<std::string> default_search_paths()
|
||||
|
||||
void help(int n) {
|
||||
if (n >= 0) {
|
||||
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
|
||||
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
|
||||
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
|
||||
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "usage : chai [option]+" << std::endl;
|
||||
std::cout << "option:" << std::endl;
|
||||
std::cout << " -h | --help" << std::endl;
|
||||
std::cout << " -i | --interactive" << std::endl;
|
||||
std::cout << " -c | --command cmd" << std::endl;
|
||||
std::cout << " -v | --version" << std::endl;
|
||||
std::cout << " - --stdin" << std::endl;
|
||||
std::cout << " filepath" << std::endl;
|
||||
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
|
||||
std::cout << "Additionally, you can inspect the runtime system using:\n";
|
||||
std::cout << " dump_system() - outputs all functions registered to the system\n";
|
||||
std::cout << " dump_object(x) - dumps information about the given symbol\n";
|
||||
} else {
|
||||
std::cout << "usage : chai [option]+\n";
|
||||
std::cout << "option:\n";
|
||||
std::cout << " -h | --help\n";
|
||||
std::cout << " -i | --interactive\n";
|
||||
std::cout << " -c | --command cmd\n";
|
||||
std::cout << " -v | --version\n";
|
||||
std::cout << " - --stdin\n";
|
||||
std::cout << " filepath\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::string helloWorld(const std::string &t_name)
|
||||
{
|
||||
std::string helloWorld(const std::string &t_name) {
|
||||
return "Hello " + t_name + "!";
|
||||
}
|
||||
|
||||
bool throws_exception(const std::function<void()> &f)
|
||||
{
|
||||
bool throws_exception(const std::function<void()> &f) {
|
||||
try {
|
||||
f();
|
||||
}
|
||||
catch (...) {
|
||||
} catch (...) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f)
|
||||
{
|
||||
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) {
|
||||
try {
|
||||
f();
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &e) {
|
||||
} catch (const chaiscript::exception::eval_error &e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -200,13 +177,11 @@ std::string get_next_command() {
|
||||
|
||||
std::string val(input_raw);
|
||||
size_t pos = val.find_first_not_of("\t \n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
if (pos != std::string::npos) {
|
||||
val.erase(0, pos);
|
||||
}
|
||||
pos = val.find_last_not_of("\t \n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
if (pos != std::string::npos) {
|
||||
val.erase(pos + 1, std::string::npos);
|
||||
}
|
||||
|
||||
@ -215,11 +190,7 @@ std::string get_next_command() {
|
||||
::free(input_raw);
|
||||
}
|
||||
}
|
||||
if (retval == "quit"
|
||||
|| retval == "exit"
|
||||
|| retval == "help"
|
||||
|| retval == "version")
|
||||
{
|
||||
if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") {
|
||||
retval += "(0)";
|
||||
}
|
||||
return retval;
|
||||
@ -231,8 +202,7 @@ void myexit(int return_val) {
|
||||
exit(return_val);
|
||||
}
|
||||
|
||||
void interactive(chaiscript::ChaiScript& chai)
|
||||
{
|
||||
void interactive(chaiscript::ChaiScript &chai) {
|
||||
using_history();
|
||||
|
||||
for (;;) {
|
||||
@ -241,32 +211,28 @@ void interactive(chaiscript::ChaiScript& chai)
|
||||
// evaluate input
|
||||
chaiscript::Boxed_Value val = chai.eval(input);
|
||||
|
||||
//Then, we try to print the result of the evaluation to the user
|
||||
// Then, we try to print the result of the evaluation to the user
|
||||
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
|
||||
try {
|
||||
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl;
|
||||
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)>>("to_string")(val) << '\n';
|
||||
} catch (...) {
|
||||
} // If we can't, do nothing
|
||||
}
|
||||
catch (...) {} //If we can't, do nothing
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.what();
|
||||
if (ee.call_stack.size() > 0) {
|
||||
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
std::cout << '\n';
|
||||
} catch (const std::exception &e) {
|
||||
std::cout << e.what();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Disable deprecation warning for getenv call.
|
||||
int main(int argc, char *argv[]) {
|
||||
// Disable deprecation warning for getenv call.
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
@ -281,8 +247,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
std::vector<std::string> usepaths;
|
||||
usepaths.push_back("");
|
||||
if (usepath)
|
||||
{
|
||||
if (usepath) {
|
||||
usepaths.push_back(usepath);
|
||||
}
|
||||
|
||||
@ -290,12 +255,11 @@ int main(int argc, char *argv[])
|
||||
std::vector<std::string> searchpaths = default_search_paths();
|
||||
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
|
||||
modulepaths.push_back("");
|
||||
if (modulepath)
|
||||
{
|
||||
if (modulepath) {
|
||||
modulepaths.push_back(modulepath);
|
||||
}
|
||||
|
||||
//chaiscript::ChaiScript chai(modulepaths, usepaths);
|
||||
// chaiscript::ChaiScript chai(modulepaths, usepaths);
|
||||
chaiscript::ChaiScript chai(usepaths);
|
||||
|
||||
chai.add(chaiscript::fun(&myexit), "exit");
|
||||
@ -308,8 +272,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
clock_t begin = clock();
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
std::string str = helloWorld("Bob12345");
|
||||
fwrite(str.c_str(), 1, str.size(), stdout);
|
||||
}
|
||||
@ -317,17 +280,17 @@ int main(int argc, char *argv[])
|
||||
clock_t end = clock();
|
||||
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
|
||||
|
||||
//begin = clock();
|
||||
// begin = clock();
|
||||
|
||||
////for (int i = 0; i < 1000; i++)
|
||||
////{
|
||||
//// chai.eval("puts(helloWorld(\"Bob12345\"));");
|
||||
////}
|
||||
//chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai");
|
||||
// chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai");
|
||||
|
||||
//end = clock();
|
||||
//elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
|
||||
//printf("**MyProgram::time= %lf\n", elapsed_secs);
|
||||
// end = clock();
|
||||
// elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
|
||||
// printf("**MyProgram::time= %lf\n", elapsed_secs);
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (i == 0 && argc > 1) {
|
||||
@ -337,49 +300,47 @@ int main(int argc, char *argv[])
|
||||
std::string arg(i ? argv[i] : "--interactive");
|
||||
|
||||
enum {
|
||||
eInteractive
|
||||
, eCommand
|
||||
, eFile
|
||||
} mode = eCommand;
|
||||
eInteractive,
|
||||
eCommand,
|
||||
eFile
|
||||
} mode
|
||||
= eCommand;
|
||||
|
||||
if (arg == "-c" || arg == "--command") {
|
||||
if ((i + 1) >= argc) {
|
||||
std::cout << "insufficient input following " << arg << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
arg = argv[++i];
|
||||
}
|
||||
}
|
||||
else if (arg == "-" || arg == "--stdin") {
|
||||
} else if (arg == "-" || arg == "--stdin") {
|
||||
arg = "";
|
||||
std::string line;
|
||||
while (std::getline(std::cin, line)) {
|
||||
arg += line + '\n';
|
||||
}
|
||||
}
|
||||
else if (arg == "-v" || arg == "--version") {
|
||||
} else if (arg == "-v" || arg == "--version") {
|
||||
arg = "version()";
|
||||
}
|
||||
else if (arg == "-h" || arg == "--help") {
|
||||
} else if (arg == "-h" || arg == "--help") {
|
||||
arg = "help(-1)";
|
||||
}
|
||||
else if (arg == "-i" || arg == "--interactive") {
|
||||
} else if (arg == "-i" || arg == "--interactive") {
|
||||
mode = eInteractive;
|
||||
}
|
||||
else if (arg.find('-') == 0) {
|
||||
} else if (arg.find('-') == 0) {
|
||||
std::cout << "unrecognised argument " << arg << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mode = eFile;
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value val;
|
||||
try {
|
||||
switch (mode) {
|
||||
case eInteractive: interactive(chai); break;
|
||||
case eCommand: val = chai.eval(arg); break;
|
||||
case eInteractive:
|
||||
interactive(chai);
|
||||
break;
|
||||
case eCommand:
|
||||
val = chai.eval(arg);
|
||||
break;
|
||||
case eFile: {
|
||||
begin = clock();
|
||||
|
||||
@ -391,15 +352,12 @@ int main(int argc, char *argv[])
|
||||
printf("**ChaiScript::time= %.10f\n", elapsed_secs1);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.pretty_print();
|
||||
std::cout << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
} catch (std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@ -407,4 +365,3 @@ int main(int argc, char *argv[])
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -1,79 +1,66 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
class BaseClass
|
||||
{
|
||||
public:
|
||||
BaseClass()
|
||||
{
|
||||
}
|
||||
class BaseClass {
|
||||
public:
|
||||
BaseClass() = default;
|
||||
|
||||
BaseClass(const BaseClass &) = default;
|
||||
|
||||
virtual ~BaseClass() {}
|
||||
virtual ~BaseClass() = default;
|
||||
|
||||
virtual std::string doSomething(float, double) const = 0;
|
||||
|
||||
|
||||
void setValue(const std::string &t_val) {
|
||||
if (validateValue(t_val))
|
||||
{
|
||||
if (validateValue(t_val)) {
|
||||
m_value = t_val;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getValue() const {
|
||||
return m_value;
|
||||
}
|
||||
std::string getValue() const { return m_value; }
|
||||
|
||||
protected:
|
||||
protected:
|
||||
virtual bool validateValue(const std::string &t_val) = 0;
|
||||
|
||||
private:
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
class ChaiScriptDerived : public BaseClass
|
||||
{
|
||||
public:
|
||||
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs)
|
||||
{
|
||||
class ChaiScriptDerived : public BaseClass {
|
||||
public:
|
||||
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs) {
|
||||
// using the range-checked .at() methods to give us an exception
|
||||
// instead of a crash if the user passed in too-few params
|
||||
tie(t_funcs.at(0), m_doSomethingImpl);
|
||||
tie(t_funcs.at(1), m_validateValueImpl);
|
||||
}
|
||||
|
||||
std::string doSomething(float f, double d) const override
|
||||
{
|
||||
std::string doSomething(float f, double d) const override {
|
||||
assert(m_doSomethingImpl);
|
||||
return m_doSomethingImpl(*this, f, d);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool validateValue(const std::string &t_val) override
|
||||
{
|
||||
protected:
|
||||
bool validateValue(const std::string &t_val) override {
|
||||
assert(m_validateValueImpl);
|
||||
return m_validateValueImpl(*this, t_val);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
template<typename Param>
|
||||
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param)
|
||||
{
|
||||
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param) {
|
||||
t_param = chaiscript::boxed_cast<Param>(t_func);
|
||||
}
|
||||
|
||||
std::function<std::string (const ChaiScriptDerived&, float, double)> m_doSomethingImpl;
|
||||
std::function<bool (ChaiScriptDerived&, const std::string &t_val)> m_validateValueImpl;
|
||||
std::function<std::string(const ChaiScriptDerived &, float, double)> m_doSomethingImpl;
|
||||
std::function<bool(ChaiScriptDerived &, const std::string &t_val)> m_validateValueImpl;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int main() {
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
|
||||
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
|
||||
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
|
||||
chai.add(chaiscript::constructor<ChaiScriptDerived (const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
|
||||
chai.add(chaiscript::constructor<ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
|
||||
chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>());
|
||||
chai.add(chaiscript::user_type<BaseClass>(), "BaseClass");
|
||||
chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived");
|
||||
@ -106,7 +93,7 @@ int main()
|
||||
|
||||
chai.eval(script);
|
||||
|
||||
BaseClass &myderived = chai.eval<ChaiScriptDerived&>("myderived");
|
||||
BaseClass &myderived = chai.eval<ChaiScriptDerived &>("myderived");
|
||||
|
||||
// at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases
|
||||
// it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors
|
||||
@ -121,7 +108,6 @@ int main()
|
||||
myderived.setValue("12345");
|
||||
assert(myderived.getValue() == "1234");
|
||||
|
||||
|
||||
chai.eval(R"(myderived.setValue("new"))"); // set the value via chaiscript
|
||||
assert(myderived.getValue() == "new");
|
||||
|
||||
@ -131,5 +117,3 @@ int main()
|
||||
|
||||
// The whole process is fully orthogonal
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -3,12 +3,10 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
std::string get_next_command() {
|
||||
#ifdef READLINE_AVAILABLE
|
||||
char *input_raw;
|
||||
@ -23,42 +21,32 @@ std::string get_next_command() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void function(void)
|
||||
{
|
||||
void function(void) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
class test
|
||||
{
|
||||
class test {
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript::State backupState = chai.get_state();
|
||||
|
||||
public:
|
||||
void ResetState()
|
||||
{
|
||||
public:
|
||||
void ResetState() {
|
||||
chai.set_state(backupState);
|
||||
chai.add(chaiscript::fun(&function),"Whatever()");
|
||||
chai.add(chaiscript::fun(&function), "Whatever()");
|
||||
}
|
||||
|
||||
void RunFile(std::string sFile)
|
||||
{
|
||||
void RunFile(std::string sFile) {
|
||||
try {
|
||||
chaiscript::Boxed_Value val = chai.eval_file(sFile);
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
} catch (std::exception &e) {
|
||||
std::cout << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main(int /*argc*/, char * /*argv*/[]) {
|
||||
|
||||
test myChai;
|
||||
|
||||
|
||||
std::string command = "";
|
||||
|
||||
//
|
||||
@ -70,12 +58,11 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
// scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as
|
||||
// low as in case 1 scenario3 :
|
||||
|
||||
while(command != "quit")
|
||||
{
|
||||
for(int i = 1; i < 200; i++)
|
||||
while (command != "quit") {
|
||||
for (int i = 1; i < 200; i++)
|
||||
myChai.ResetState();
|
||||
|
||||
if(command == "runfile")
|
||||
if (command == "runfile")
|
||||
myChai.RunFile("Test.chai");
|
||||
|
||||
command = get_next_command();
|
||||
|
||||
@ -2,14 +2,11 @@
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <chaiscript/dispatchkit/function_call.hpp>
|
||||
|
||||
int main( int /*argc*/ , char * /*argv*/[] )
|
||||
{
|
||||
int main(int /*argc*/, char * /*argv*/[]) {
|
||||
chaiscript::ChaiScript ch;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
static const char script[ ] =
|
||||
try {
|
||||
static const char script[] =
|
||||
R""(
|
||||
|
||||
class Rectangle
|
||||
@ -21,12 +18,9 @@ int main( int /*argc*/ , char * /*argv*/[] )
|
||||
|
||||
)"";
|
||||
|
||||
|
||||
ch.eval( script );
|
||||
}
|
||||
catch ( const std::exception &e )
|
||||
{
|
||||
printf( " >>> Exception thrown: %s \n" , e.what( ) );
|
||||
ch.eval(script);
|
||||
} catch (const std::exception &e) {
|
||||
printf(" >>> Exception thrown: %s \n", e.what());
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
|
||||
// MSVC doesn't like that we are using C++ return types from our C declared module
|
||||
// but this is the best way to do it for cross platform compatibility
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
@ -14,13 +13,10 @@
|
||||
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
||||
#endif
|
||||
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib()
|
||||
{
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib() {
|
||||
return chaiscript::Std_Lib::library();
|
||||
}
|
||||
|
||||
|
||||
#ifdef __llvm__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <regex>
|
||||
@ -16,49 +15,45 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include "../static_libs/chaiscript_parser.hpp"
|
||||
#include "../static_libs/chaiscript_stdlib.hpp"
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
#include "sha3.h"
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
#else
|
||||
|
||||
char *mystrdup (const char *s) {
|
||||
char *mystrdup(const char *s) {
|
||||
size_t len = strlen(s); // Space for length plus nul
|
||||
char *d = static_cast<char*>(malloc (len+1));
|
||||
if (d == nullptr) { return nullptr; } // No memory
|
||||
char *d = static_cast<char *>(malloc(len + 1));
|
||||
if (d == nullptr) {
|
||||
return nullptr;
|
||||
} // No memory
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
strcpy_s(d, len+1, s); // Copy the characters
|
||||
strcpy_s(d, len + 1, s); // Copy the characters
|
||||
#else
|
||||
strncpy(d,s,len); // Copy the characters
|
||||
strncpy(d, s, len); // Copy the characters
|
||||
#endif
|
||||
d[len] = '\0';
|
||||
return d; // Return the new string
|
||||
}
|
||||
|
||||
char* readline(const char* p)
|
||||
{
|
||||
char *readline(const char *p) {
|
||||
std::string retval;
|
||||
std::cout << p ;
|
||||
std::cout << p;
|
||||
std::getline(std::cin, retval);
|
||||
return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
|
||||
}
|
||||
|
||||
|
||||
void add_history(const char* /*unused*/){}
|
||||
void using_history(){}
|
||||
void add_history(const char * /*unused*/) {}
|
||||
void using_history() {}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void *cast_module_symbol(std::vector<std::string> (*t_path)())
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
|
||||
union cast_union {
|
||||
std::vector<std::string> (*in_ptr)();
|
||||
void *out_ptr;
|
||||
};
|
||||
@ -68,26 +63,23 @@ void *cast_module_symbol(std::vector<std::string> (*t_path)())
|
||||
return c.out_ptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> default_search_paths()
|
||||
{
|
||||
std::vector<std::string> default_search_paths() {
|
||||
std::vector<std::string> paths;
|
||||
|
||||
#ifndef CHAISCRIPT_NO_DYNLOAD
|
||||
#ifdef CHAISCRIPT_WINDOWS // force no unicode
|
||||
CHAR path[4096];
|
||||
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
|
||||
int size = GetModuleFileNameA(nullptr, path, sizeof(path) - 1);
|
||||
|
||||
std::string exepath(path, size);
|
||||
|
||||
size_t lastslash = exepath.rfind('\\');
|
||||
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
|
||||
if (lastslash != std::string::npos)
|
||||
{
|
||||
if (lastslash != std::string::npos) {
|
||||
paths.push_back(exepath.substr(0, lastslash));
|
||||
}
|
||||
|
||||
if (secondtolastslash != std::string::npos)
|
||||
{
|
||||
if (secondtolastslash != std::string::npos) {
|
||||
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
|
||||
}
|
||||
#else
|
||||
@ -97,32 +89,26 @@ std::vector<std::string> default_search_paths()
|
||||
std::vector<char> buf(2048);
|
||||
ssize_t size = -1;
|
||||
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0)
|
||||
{
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0) {
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
|
||||
{
|
||||
if (exepath.empty()) {
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) {
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
|
||||
{
|
||||
if (exepath.empty()) {
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) {
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if (exepath.empty()) {
|
||||
Dl_info rInfo;
|
||||
memset( &rInfo, 0, sizeof(rInfo) );
|
||||
if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) {
|
||||
memset(&rInfo, 0, sizeof(rInfo));
|
||||
if (dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr) {
|
||||
return paths;
|
||||
}
|
||||
|
||||
@ -132,13 +118,11 @@ std::vector<std::string> default_search_paths()
|
||||
size_t lastslash = exepath.rfind('/');
|
||||
|
||||
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
|
||||
if (lastslash != std::string::npos)
|
||||
{
|
||||
paths.push_back(exepath.substr(0, lastslash+1));
|
||||
if (lastslash != std::string::npos) {
|
||||
paths.push_back(exepath.substr(0, lastslash + 1));
|
||||
}
|
||||
|
||||
if (secondtolastslash != std::string::npos)
|
||||
{
|
||||
if (secondtolastslash != std::string::npos) {
|
||||
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
|
||||
}
|
||||
#endif
|
||||
@ -148,7 +132,7 @@ std::vector<std::string> default_search_paths()
|
||||
}
|
||||
|
||||
void help(int n) {
|
||||
if ( n >= 0 ) {
|
||||
if (n >= 0) {
|
||||
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
|
||||
std::cout << "Additionally, you can inspect the runtime system using:\n";
|
||||
std::cout << " dump_system() - outputs all functions registered to the system\n";
|
||||
@ -165,8 +149,7 @@ void help(int n) {
|
||||
}
|
||||
}
|
||||
|
||||
bool throws_exception(const std::function<void ()> &f)
|
||||
{
|
||||
bool throws_exception(const std::function<void()> &f) {
|
||||
try {
|
||||
f();
|
||||
} catch (...) {
|
||||
@ -176,8 +159,7 @@ bool throws_exception(const std::function<void ()> &f)
|
||||
return false;
|
||||
}
|
||||
|
||||
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
|
||||
{
|
||||
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) {
|
||||
try {
|
||||
f();
|
||||
} catch (const chaiscript::exception::eval_error &e) {
|
||||
@ -189,21 +171,19 @@ chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f
|
||||
|
||||
std::string get_next_command() {
|
||||
std::string retval("quit");
|
||||
if ( ! std::cin.eof() ) {
|
||||
if (!std::cin.eof()) {
|
||||
char *input_raw = readline("eval> ");
|
||||
if ( input_raw != nullptr ) {
|
||||
if (input_raw != nullptr) {
|
||||
add_history(input_raw);
|
||||
|
||||
std::string val(input_raw);
|
||||
size_t pos = val.find_first_not_of("\t \n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
if (pos != std::string::npos) {
|
||||
val.erase(0, pos);
|
||||
}
|
||||
pos = val.find_last_not_of("\t \n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
val.erase(pos+1, std::string::npos);
|
||||
if (pos != std::string::npos) {
|
||||
val.erase(pos + 1, std::string::npos);
|
||||
}
|
||||
|
||||
retval = val;
|
||||
@ -211,11 +191,7 @@ std::string get_next_command() {
|
||||
::free(input_raw);
|
||||
}
|
||||
}
|
||||
if( retval == "quit"
|
||||
|| retval == "exit"
|
||||
|| retval == "help"
|
||||
|| retval == "version")
|
||||
{
|
||||
if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") {
|
||||
retval += "(0)";
|
||||
}
|
||||
return retval;
|
||||
@ -227,8 +203,7 @@ void myexit(int return_val) {
|
||||
exit(return_val);
|
||||
}
|
||||
|
||||
void interactive(chaiscript::ChaiScript_Basic& chai)
|
||||
{
|
||||
void interactive(chaiscript::ChaiScript_Basic &chai) {
|
||||
using_history();
|
||||
|
||||
for (;;) {
|
||||
@ -237,30 +212,27 @@ void interactive(chaiscript::ChaiScript_Basic& chai)
|
||||
// evaluate input
|
||||
chaiscript::Boxed_Value val = chai.eval(input);
|
||||
|
||||
//Then, we try to print the result of the evaluation to the user
|
||||
// Then, we try to print the result of the evaluation to the user
|
||||
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
|
||||
try {
|
||||
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
|
||||
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)>>("to_string")(val) << '\n';
|
||||
} catch (...) {
|
||||
} // If we can't, do nothing
|
||||
}
|
||||
catch (...) {} //If we can't, do nothing
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.what();
|
||||
if ( !ee.call_stack.empty() ) {
|
||||
if (!ee.call_stack.empty()) {
|
||||
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
} catch (const std::exception &e) {
|
||||
std::cout << e.what();
|
||||
std::cout << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double now()
|
||||
{
|
||||
double now() {
|
||||
using namespace std::chrono;
|
||||
auto now = high_resolution_clock::now();
|
||||
return duration_cast<duration<double>>(now.time_since_epoch()).count();
|
||||
@ -269,7 +241,7 @@ double now()
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
chai.eval( R"chaiscript(
|
||||
chai.eval(R"chaiscript(
|
||||
def assert_equal(x, y)
|
||||
{
|
||||
if (x == y)
|
||||
@ -339,7 +311,8 @@ def assert_throws(desc, x)
|
||||
std::ofstream ofs("BOXED_VALUE/" + sha);
|
||||
ofs << input;
|
||||
} catch (const chaiscript::exception::load_module_error &e) {
|
||||
std::cout << "Unhandled module load error\n" << e.what() << '\n';
|
||||
std::cout << "Unhandled module load error\n"
|
||||
<< e.what() << '\n';
|
||||
} catch (const std::exception &) {
|
||||
std::ofstream ofs("STD_EXCEPTION/" + sha);
|
||||
ofs << input;
|
||||
@ -350,5 +323,3 @@ def assert_throws(desc, x)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
213
src/main.cpp
213
src/main.cpp
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <regex>
|
||||
@ -16,48 +15,43 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
#include "../static_libs/chaiscript_parser.hpp"
|
||||
#include "../static_libs/chaiscript_stdlib.hpp"
|
||||
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
#else
|
||||
|
||||
char *mystrdup (const char *s) {
|
||||
char *mystrdup(const char *s) {
|
||||
size_t len = strlen(s); // Space for length plus nul
|
||||
char *d = static_cast<char*>(malloc (len+1));
|
||||
if (d == nullptr) { return nullptr; } // No memory
|
||||
char *d = static_cast<char *>(malloc(len + 1));
|
||||
if (d == nullptr) {
|
||||
return nullptr;
|
||||
} // No memory
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
strcpy_s(d, len+1, s); // Copy the characters
|
||||
strcpy_s(d, len + 1, s); // Copy the characters
|
||||
#else
|
||||
strncpy(d,s,len); // Copy the characters
|
||||
strncpy(d, s, len); // Copy the characters
|
||||
#endif
|
||||
d[len] = '\0';
|
||||
return d; // Return the new string
|
||||
}
|
||||
|
||||
char* readline(const char* p)
|
||||
{
|
||||
char *readline(const char *p) {
|
||||
std::string retval;
|
||||
std::cout << p ;
|
||||
std::cout << p;
|
||||
std::getline(std::cin, retval);
|
||||
return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
|
||||
}
|
||||
|
||||
|
||||
void add_history(const char* /*unused*/){}
|
||||
void using_history(){}
|
||||
void add_history(const char * /*unused*/) {}
|
||||
void using_history() {}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void *cast_module_symbol(std::vector<std::string> (*t_path)())
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
|
||||
union cast_union {
|
||||
std::vector<std::string> (*in_ptr)();
|
||||
void *out_ptr;
|
||||
};
|
||||
@ -67,26 +61,23 @@ void *cast_module_symbol(std::vector<std::string> (*t_path)())
|
||||
return c.out_ptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> default_search_paths()
|
||||
{
|
||||
std::vector<std::string> default_search_paths() {
|
||||
std::vector<std::string> paths;
|
||||
|
||||
#ifndef CHAISCRIPT_NO_DYNLOAD
|
||||
#ifdef CHAISCRIPT_WINDOWS // force no unicode
|
||||
CHAR path[4096];
|
||||
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
|
||||
int size = GetModuleFileNameA(nullptr, path, sizeof(path) - 1);
|
||||
|
||||
std::string exepath(path, size);
|
||||
|
||||
size_t lastslash = exepath.rfind('\\');
|
||||
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
|
||||
if (lastslash != std::string::npos)
|
||||
{
|
||||
if (lastslash != std::string::npos) {
|
||||
paths.push_back(exepath.substr(0, lastslash));
|
||||
}
|
||||
|
||||
if (secondtolastslash != std::string::npos)
|
||||
{
|
||||
if (secondtolastslash != std::string::npos) {
|
||||
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
|
||||
}
|
||||
#else
|
||||
@ -96,32 +87,26 @@ std::vector<std::string> default_search_paths()
|
||||
std::vector<char> buf(2048);
|
||||
ssize_t size = -1;
|
||||
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0)
|
||||
{
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0) {
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
|
||||
{
|
||||
if (exepath.empty()) {
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) {
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
|
||||
{
|
||||
if (exepath.empty()) {
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) {
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if (exepath.empty()) {
|
||||
Dl_info rInfo;
|
||||
memset( &rInfo, 0, sizeof(rInfo) );
|
||||
if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) {
|
||||
memset(&rInfo, 0, sizeof(rInfo));
|
||||
if (dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr) {
|
||||
return paths;
|
||||
}
|
||||
|
||||
@ -131,13 +116,11 @@ std::vector<std::string> default_search_paths()
|
||||
size_t lastslash = exepath.rfind('/');
|
||||
|
||||
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
|
||||
if (lastslash != std::string::npos)
|
||||
{
|
||||
paths.push_back(exepath.substr(0, lastslash+1));
|
||||
if (lastslash != std::string::npos) {
|
||||
paths.push_back(exepath.substr(0, lastslash + 1));
|
||||
}
|
||||
|
||||
if (secondtolastslash != std::string::npos)
|
||||
{
|
||||
if (secondtolastslash != std::string::npos) {
|
||||
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
|
||||
}
|
||||
#endif
|
||||
@ -147,7 +130,7 @@ std::vector<std::string> default_search_paths()
|
||||
}
|
||||
|
||||
void help(int n) {
|
||||
if ( n >= 0 ) {
|
||||
if (n >= 0) {
|
||||
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
|
||||
std::cout << "Additionally, you can inspect the runtime system using:\n";
|
||||
std::cout << " dump_system() - outputs all functions registered to the system\n";
|
||||
@ -164,8 +147,7 @@ void help(int n) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string throws_exception(const std::function<void ()> &f)
|
||||
{
|
||||
std::string throws_exception(const std::function<void()> &f) {
|
||||
try {
|
||||
f();
|
||||
} catch (const std::exception &e) {
|
||||
@ -175,8 +157,7 @@ std::string throws_exception(const std::function<void ()> &f)
|
||||
return "";
|
||||
}
|
||||
|
||||
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
|
||||
{
|
||||
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) {
|
||||
try {
|
||||
f();
|
||||
} catch (const chaiscript::exception::eval_error &e) {
|
||||
@ -188,21 +169,19 @@ chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f
|
||||
|
||||
std::string get_next_command() {
|
||||
std::string retval("quit");
|
||||
if ( ! std::cin.eof() ) {
|
||||
if (!std::cin.eof()) {
|
||||
char *input_raw = readline("eval> ");
|
||||
if ( input_raw != nullptr ) {
|
||||
if (input_raw != nullptr) {
|
||||
add_history(input_raw);
|
||||
|
||||
std::string val(input_raw);
|
||||
size_t pos = val.find_first_not_of("\t \n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
if (pos != std::string::npos) {
|
||||
val.erase(0, pos);
|
||||
}
|
||||
pos = val.find_last_not_of("\t \n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
val.erase(pos+1, std::string::npos);
|
||||
if (pos != std::string::npos) {
|
||||
val.erase(pos + 1, std::string::npos);
|
||||
}
|
||||
|
||||
retval = val;
|
||||
@ -210,11 +189,7 @@ std::string get_next_command() {
|
||||
::free(input_raw);
|
||||
}
|
||||
}
|
||||
if( retval == "quit"
|
||||
|| retval == "exit"
|
||||
|| retval == "help"
|
||||
|| retval == "version")
|
||||
{
|
||||
if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") {
|
||||
retval += "(0)";
|
||||
}
|
||||
return retval;
|
||||
@ -226,8 +201,7 @@ void myexit(int return_val) {
|
||||
exit(return_val);
|
||||
}
|
||||
|
||||
void interactive(chaiscript::ChaiScript_Basic& chai)
|
||||
{
|
||||
void interactive(chaiscript::ChaiScript_Basic &chai) {
|
||||
using_history();
|
||||
|
||||
for (;;) {
|
||||
@ -236,39 +210,34 @@ void interactive(chaiscript::ChaiScript_Basic& chai)
|
||||
// evaluate input
|
||||
chaiscript::Boxed_Value val = chai.eval(input);
|
||||
|
||||
//Then, we try to print the result of the evaluation to the user
|
||||
// Then, we try to print the result of the evaluation to the user
|
||||
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
|
||||
try {
|
||||
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
|
||||
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)>>("to_string")(val) << '\n';
|
||||
} catch (...) {
|
||||
} // If we can't, do nothing
|
||||
}
|
||||
catch (...) {} //If we can't, do nothing
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.what();
|
||||
if ( !ee.call_stack.empty() ) {
|
||||
if (!ee.call_stack.empty()) {
|
||||
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
} catch (const std::exception &e) {
|
||||
std::cout << e.what();
|
||||
std::cout << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double now()
|
||||
{
|
||||
double now() {
|
||||
using namespace std::chrono;
|
||||
auto now = high_resolution_clock::now();
|
||||
return duration_cast<duration<double>>(now.time_since_epoch()).count();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Disable deprecation warning for getenv call.
|
||||
int main(int argc, char *argv[]) {
|
||||
// Disable deprecation warning for getenv call.
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
@ -282,22 +251,20 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
std::vector<std::string> usepaths;
|
||||
usepaths.push_back("");
|
||||
if (usepath != nullptr)
|
||||
{
|
||||
usepaths.push_back(usepath);
|
||||
usepaths.emplace_back("");
|
||||
if (usepath != nullptr) {
|
||||
usepaths.emplace_back(usepath);
|
||||
}
|
||||
|
||||
std::vector<std::string> modulepaths;
|
||||
std::vector<std::string> searchpaths = default_search_paths();
|
||||
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
|
||||
modulepaths.push_back("");
|
||||
if (modulepath != nullptr)
|
||||
{
|
||||
modulepaths.push_back(modulepath);
|
||||
modulepaths.emplace_back("");
|
||||
if (modulepath != nullptr) {
|
||||
modulepaths.emplace_back(modulepath);
|
||||
}
|
||||
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(),modulepaths,usepaths);
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser(), modulepaths, usepaths);
|
||||
|
||||
chai.add(chaiscript::fun(&myexit), "exit");
|
||||
chai.add(chaiscript::fun(&myexit), "quit");
|
||||
@ -311,46 +278,48 @@ int main(int argc, char *argv[])
|
||||
bool any_exception_ok = false;
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if ( i == 0 && argc > 1 ) {
|
||||
if (i == 0 && argc > 1) {
|
||||
++i;
|
||||
}
|
||||
|
||||
std::string arg( i != 0 ? argv[i] : "--interactive" );
|
||||
std::string arg(i != 0 ? argv[i] : "--interactive");
|
||||
|
||||
enum { eInteractive
|
||||
, eCommand
|
||||
, eFile
|
||||
} mode = eCommand ;
|
||||
enum {
|
||||
eInteractive,
|
||||
eCommand,
|
||||
eFile
|
||||
} mode
|
||||
= eCommand;
|
||||
|
||||
if ( arg == "-c" || arg == "--command" ) {
|
||||
if ( (i+1) >= argc ) {
|
||||
if (arg == "-c" || arg == "--command") {
|
||||
if ((i + 1) >= argc) {
|
||||
std::cout << "insufficient input following " << arg << '\n';
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
arg = argv[++i];
|
||||
|
||||
} else if ( arg == "-" || arg == "--stdin" ) {
|
||||
arg = "" ;
|
||||
} else if (arg == "-" || arg == "--stdin") {
|
||||
arg = "";
|
||||
std::string line;
|
||||
while ( std::getline(std::cin, line) ) {
|
||||
arg += line + '\n' ;
|
||||
while (std::getline(std::cin, line)) {
|
||||
arg += line + '\n';
|
||||
}
|
||||
} else if ( arg == "-v" || arg == "--version" ) {
|
||||
arg = "print(version())" ;
|
||||
} else if ( arg == "-h" || arg == "--help" ) {
|
||||
} else if (arg == "-v" || arg == "--version") {
|
||||
arg = "print(version())";
|
||||
} else if (arg == "-h" || arg == "--help") {
|
||||
arg = "help(-1)";
|
||||
} else if ( arg == "-e" || arg == "--evalerrorok" ) {
|
||||
} else if (arg == "-e" || arg == "--evalerrorok") {
|
||||
eval_error_ok = true;
|
||||
continue;
|
||||
} else if ( arg == "--exception" ) {
|
||||
} else if (arg == "--exception") {
|
||||
boxed_exception_ok = true;
|
||||
continue;
|
||||
} else if ( arg == "--any-exception" ) {
|
||||
} else if (arg == "--any-exception") {
|
||||
any_exception_ok = true;
|
||||
continue;
|
||||
} else if ( arg == "-i" || arg == "--interactive" ) {
|
||||
mode = eInteractive ;
|
||||
} else if ( arg.find('-') == 0 ) {
|
||||
} else if (arg == "-i" || arg == "--interactive") {
|
||||
mode = eInteractive;
|
||||
} else if (arg.find('-') == 0) {
|
||||
std::cout << "unrecognised argument " << arg << '\n';
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
@ -358,7 +327,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
try {
|
||||
switch ( mode ) {
|
||||
switch (mode) {
|
||||
case eInteractive:
|
||||
interactive(chai);
|
||||
break;
|
||||
@ -368,32 +337,28 @@ int main(int argc, char *argv[])
|
||||
case eFile:
|
||||
chai.eval_file(arg);
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.pretty_print();
|
||||
std::cout << '\n';
|
||||
|
||||
if (!eval_error_ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::Boxed_Value &e) {
|
||||
} catch (const chaiscript::Boxed_Value &e) {
|
||||
std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n';
|
||||
|
||||
if (!boxed_exception_ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::exception::load_module_error &e) {
|
||||
std::cout << "Unhandled module load error\n" << e.what() << '\n';
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
} catch (const chaiscript::exception::load_module_error &e) {
|
||||
std::cout << "Unhandled module load error\n"
|
||||
<< e.what() << '\n';
|
||||
} catch (std::exception &e) {
|
||||
std::cout << "Unhandled standard exception: " << e.what() << '\n';
|
||||
if (!any_exception_ok) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
} catch (...) {
|
||||
std::cout << "Unhandled unknown exception" << '\n';
|
||||
if (!any_exception_ok) {
|
||||
throw;
|
||||
|
||||
@ -4,62 +4,52 @@
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
// NOT TO BE USED AS A SOURCE OF BEST PRACTICES
|
||||
// FOR CHAISCRIPT
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <chaiscript/dispatchkit/function_call.hpp>
|
||||
|
||||
void log(const std::string &msg)
|
||||
{
|
||||
void log(const std::string &msg) {
|
||||
std::cout << "[" << time(nullptr) << "] " << msg << '\n';
|
||||
}
|
||||
|
||||
void log(const std::string &module, const std::string &msg)
|
||||
{
|
||||
void log(const std::string &module, const std::string &msg) {
|
||||
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n';
|
||||
}
|
||||
|
||||
void bound_log(const std::string &msg)
|
||||
{
|
||||
void bound_log(const std::string &msg) {
|
||||
log(msg);
|
||||
}
|
||||
|
||||
void hello_world(const chaiscript::Boxed_Value & /*o*/)
|
||||
{
|
||||
void hello_world(const chaiscript::Boxed_Value & /*o*/) {
|
||||
std::cout << "Hello World\n";
|
||||
}
|
||||
|
||||
void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
|
||||
{
|
||||
void hello_constructor(const chaiscript::Boxed_Value & /*o*/) {
|
||||
std::cout << "Hello Constructor\n";
|
||||
}
|
||||
|
||||
struct System {
|
||||
std::map<std::string, std::function<std::string(const std::string &)>> m_callbacks;
|
||||
|
||||
struct System
|
||||
{
|
||||
std::map<std::string, std::function<std::string (const std::string &) > > m_callbacks;
|
||||
|
||||
void add_callback(const std::string &t_name,
|
||||
const std::function<std::string (const std::string &)> &t_func)
|
||||
{
|
||||
void add_callback(const std::string &t_name, const std::function<std::string(const std::string &)> &t_func) {
|
||||
m_callbacks[t_name] = t_func;
|
||||
}
|
||||
|
||||
|
||||
void do_callbacks(const std::string &inp)
|
||||
{
|
||||
void do_callbacks(const std::string &inp) {
|
||||
log("Running Callbacks: " + inp);
|
||||
for (auto & m_callback : m_callbacks)
|
||||
{
|
||||
for (auto &m_callback : m_callbacks) {
|
||||
log("Callback: " + m_callback.first, m_callback.second(inp));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void take_shared_ptr(const std::shared_ptr<const std::string> &p)
|
||||
{
|
||||
void take_shared_ptr(const std::shared_ptr<const std::string> &p) {
|
||||
std::cout << *p << '\n';
|
||||
}
|
||||
|
||||
@ -68,15 +58,14 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
|
||||
ChaiScript chai;
|
||||
|
||||
|
||||
//Create a new system object and share it with the chaiscript engine
|
||||
// Create a new system object and share it with the chaiscript engine
|
||||
System system;
|
||||
chai.add_global(var(&system), "system");
|
||||
|
||||
//Add a bound callback method
|
||||
// Add a bound callback method
|
||||
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
|
||||
|
||||
//Register the two methods of the System structure.
|
||||
// Register the two methods of the System structure.
|
||||
chai.add(fun(&System::add_callback), "add_callback");
|
||||
chai.add(fun(&System::do_callbacks), "do_callbacks");
|
||||
|
||||
@ -106,29 +95,26 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
// A shortcut to using eval is just to use the chai operator()
|
||||
chai(R"(log("Test Module", "Test Message");)");
|
||||
|
||||
//Finally, it is possible to register a lambda as a system function, in this
|
||||
//way, we can, for instance add a bound member function to the system
|
||||
chai.add(fun([&system](){ return system.do_callbacks("Bound Test"); }), "do_callbacks");
|
||||
// Finally, it is possible to register a lambda as a system function, in this
|
||||
// way, we can, for instance add a bound member function to the system
|
||||
chai.add(fun([&system]() { return system.do_callbacks("Bound Test"); }), "do_callbacks");
|
||||
|
||||
//Call bound version of do_callbacks
|
||||
// Call bound version of do_callbacks
|
||||
chai("do_callbacks()");
|
||||
|
||||
std::function<void ()> caller = chai.eval<std::function<void ()> >(
|
||||
R"(fun() { system.do_callbacks("From Functor"); })"
|
||||
);
|
||||
std::function<void()> caller = chai.eval<std::function<void()>>(R"(fun() { system.do_callbacks("From Functor"); })");
|
||||
caller();
|
||||
|
||||
|
||||
//If we would like a type-safe return value from all call, we can use
|
||||
//the templated version of eval:
|
||||
// If we would like a type-safe return value from all call, we can use
|
||||
// the templated version of eval:
|
||||
int i = chai.eval<int>("5+5");
|
||||
|
||||
std::cout << "5+5: " << i << '\n';
|
||||
|
||||
//Add a new variable
|
||||
// Add a new variable
|
||||
chai("var scripti = 15");
|
||||
|
||||
//We can even get a handle to the variables in the system
|
||||
// We can even get a handle to the variables in the system
|
||||
int &scripti = chai.eval<int &>("scripti");
|
||||
|
||||
std::cout << "scripti: " << scripti << '\n';
|
||||
@ -136,10 +122,10 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
std::cout << "scripti (updated): " << scripti << '\n';
|
||||
chai(R"(print("Scripti from chai: " + to_string(scripti)))");
|
||||
|
||||
//To do: Add examples of handling Boxed_Values directly when needed
|
||||
// To do: Add examples of handling Boxed_Values directly when needed
|
||||
|
||||
//Creating a functor on the stack and using it immediately
|
||||
int x = chai.eval<std::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
|
||||
// Creating a functor on the stack and using it immediately
|
||||
int x = chai.eval<std::function<int(int, int)>>("fun (x, y) { return x + y; }")(5, 6);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << x;
|
||||
@ -153,25 +139,23 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
chai("def getvar() { return constvar; }");
|
||||
chai("print( getvar() )");
|
||||
|
||||
|
||||
//Ability to create our own container types when needed. std::vector and std::map are
|
||||
//mostly supported currently
|
||||
chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
|
||||
|
||||
// Ability to create our own container types when needed. std::vector and std::map are
|
||||
// mostly supported currently
|
||||
// chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
|
||||
|
||||
// Test ability to register a function that excepts a shared_ptr version of a type
|
||||
chai(R"(take_shared_ptr("Hello World as a shared_ptr");)");
|
||||
|
||||
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
|
||||
|
||||
//Dynamic objects test
|
||||
// Dynamic objects test
|
||||
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
|
||||
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
|
||||
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr");
|
||||
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func,
|
||||
// "TestType", "attr", std::placeholders::_1))), "attr");
|
||||
|
||||
chai.eval("var x = TestType()");
|
||||
// chai.eval("x.attr = \"hi\"");
|
||||
// chai.eval("print(x.attr)");
|
||||
// chai.eval("x.attr = \"hi\"");
|
||||
// chai.eval("print(x.attr)");
|
||||
chai.eval("x.hello_world()");
|
||||
}
|
||||
|
||||
206
src/sha3.cpp
206
src/sha3.cpp
@ -11,19 +11,15 @@
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// same as reset()
|
||||
SHA3::SHA3(Bits bits)
|
||||
: m_blockSize(200 - 2 * (bits / 8)),
|
||||
m_bits(bits)
|
||||
{
|
||||
: m_blockSize(200 - 2 * (bits / 8))
|
||||
, m_bits(bits) {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
/// restart
|
||||
void SHA3::reset()
|
||||
{
|
||||
void SHA3::reset() {
|
||||
for (size_t i = 0; i < StateSize; i++)
|
||||
m_hash[i] = 0;
|
||||
|
||||
@ -31,32 +27,19 @@ void SHA3::reset()
|
||||
m_bufferSize = 0;
|
||||
}
|
||||
|
||||
|
||||
/// constants and local helper functions
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
const unsigned int Rounds = 24;
|
||||
const uint64_t XorMasks[Rounds] =
|
||||
{
|
||||
0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
|
||||
0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
|
||||
0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
|
||||
0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
|
||||
0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
|
||||
0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
|
||||
0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
|
||||
0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
|
||||
};
|
||||
const uint64_t XorMasks[Rounds]
|
||||
= {0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL};
|
||||
|
||||
/// rotate left and wrap around to the right
|
||||
inline uint64_t rotateLeft(uint64_t x, uint8_t numBits)
|
||||
{
|
||||
inline uint64_t rotateLeft(uint64_t x, uint8_t numBits) {
|
||||
return (x << numBits) | (x >> (64 - numBits));
|
||||
}
|
||||
|
||||
/// convert litte vs big endian
|
||||
inline uint64_t swap(uint64_t x)
|
||||
{
|
||||
inline uint64_t swap(uint64_t x) {
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_bswap64(x);
|
||||
#endif
|
||||
@ -64,54 +47,42 @@ namespace
|
||||
return _byteswap_uint64(x);
|
||||
#endif
|
||||
|
||||
return (x >> 56) |
|
||||
((x >> 40) & 0x000000000000FF00ULL) |
|
||||
((x >> 24) & 0x0000000000FF0000ULL) |
|
||||
((x >> 8) & 0x00000000FF000000ULL) |
|
||||
((x << 8) & 0x000000FF00000000ULL) |
|
||||
((x << 24) & 0x0000FF0000000000ULL) |
|
||||
((x << 40) & 0x00FF000000000000ULL) |
|
||||
(x << 56);
|
||||
return (x >> 56) | ((x >> 40) & 0x000000000000FF00ULL) | ((x >> 24) & 0x0000000000FF0000ULL) | ((x >> 8) & 0x00000000FF000000ULL)
|
||||
| ((x << 8) & 0x000000FF00000000ULL) | ((x << 24) & 0x0000FF0000000000ULL) | ((x << 40) & 0x00FF000000000000ULL) | (x << 56);
|
||||
}
|
||||
|
||||
|
||||
/// return x % 5 for 0 <= x <= 9
|
||||
unsigned int mod5(unsigned int x)
|
||||
{
|
||||
unsigned int mod5(unsigned int x) {
|
||||
if (x < 5)
|
||||
return x;
|
||||
|
||||
return x - 5;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/// process a full block
|
||||
void SHA3::processBlock(const void* data)
|
||||
{
|
||||
void SHA3::processBlock(const void *data) {
|
||||
#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
#define LITTLEENDIAN(x) swap(x)
|
||||
#else
|
||||
#define LITTLEENDIAN(x) (x)
|
||||
#endif
|
||||
|
||||
const uint64_t* data64 = (const uint64_t*) data;
|
||||
const uint64_t *data64 = (const uint64_t *)data;
|
||||
// mix data into state
|
||||
for (unsigned int i = 0; i < m_blockSize / 8; i++)
|
||||
m_hash[i] ^= LITTLEENDIAN(data64[i]);
|
||||
|
||||
// re-compute state
|
||||
for (unsigned int round = 0; round < Rounds; round++)
|
||||
{
|
||||
for (unsigned int round = 0; round < Rounds; round++) {
|
||||
// Theta
|
||||
uint64_t coefficients[5];
|
||||
for (unsigned int i = 0; i < 5; i++)
|
||||
coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20];
|
||||
|
||||
for (unsigned int i = 0; i < 5; i++)
|
||||
{
|
||||
for (unsigned int i = 0; i < 5; i++) {
|
||||
uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1);
|
||||
m_hash[i ] ^= one;
|
||||
m_hash[i] ^= one;
|
||||
m_hash[i + 5] ^= one;
|
||||
m_hash[i + 10] ^= one;
|
||||
m_hash[i + 15] ^= one;
|
||||
@ -123,34 +94,79 @@ void SHA3::processBlock(const void* data)
|
||||
|
||||
// Rho Pi
|
||||
uint64_t last = m_hash[1];
|
||||
one = m_hash[10]; m_hash[10] = rotateLeft(last, 1); last = one;
|
||||
one = m_hash[ 7]; m_hash[ 7] = rotateLeft(last, 3); last = one;
|
||||
one = m_hash[11]; m_hash[11] = rotateLeft(last, 6); last = one;
|
||||
one = m_hash[17]; m_hash[17] = rotateLeft(last, 10); last = one;
|
||||
one = m_hash[18]; m_hash[18] = rotateLeft(last, 15); last = one;
|
||||
one = m_hash[ 3]; m_hash[ 3] = rotateLeft(last, 21); last = one;
|
||||
one = m_hash[ 5]; m_hash[ 5] = rotateLeft(last, 28); last = one;
|
||||
one = m_hash[16]; m_hash[16] = rotateLeft(last, 36); last = one;
|
||||
one = m_hash[ 8]; m_hash[ 8] = rotateLeft(last, 45); last = one;
|
||||
one = m_hash[21]; m_hash[21] = rotateLeft(last, 55); last = one;
|
||||
one = m_hash[24]; m_hash[24] = rotateLeft(last, 2); last = one;
|
||||
one = m_hash[ 4]; m_hash[ 4] = rotateLeft(last, 14); last = one;
|
||||
one = m_hash[15]; m_hash[15] = rotateLeft(last, 27); last = one;
|
||||
one = m_hash[23]; m_hash[23] = rotateLeft(last, 41); last = one;
|
||||
one = m_hash[19]; m_hash[19] = rotateLeft(last, 56); last = one;
|
||||
one = m_hash[13]; m_hash[13] = rotateLeft(last, 8); last = one;
|
||||
one = m_hash[12]; m_hash[12] = rotateLeft(last, 25); last = one;
|
||||
one = m_hash[ 2]; m_hash[ 2] = rotateLeft(last, 43); last = one;
|
||||
one = m_hash[20]; m_hash[20] = rotateLeft(last, 62); last = one;
|
||||
one = m_hash[14]; m_hash[14] = rotateLeft(last, 18); last = one;
|
||||
one = m_hash[22]; m_hash[22] = rotateLeft(last, 39); last = one;
|
||||
one = m_hash[ 9]; m_hash[ 9] = rotateLeft(last, 61); last = one;
|
||||
one = m_hash[ 6]; m_hash[ 6] = rotateLeft(last, 20); last = one;
|
||||
m_hash[ 1] = rotateLeft(last, 44);
|
||||
one = m_hash[10];
|
||||
m_hash[10] = rotateLeft(last, 1);
|
||||
last = one;
|
||||
one = m_hash[7];
|
||||
m_hash[7] = rotateLeft(last, 3);
|
||||
last = one;
|
||||
one = m_hash[11];
|
||||
m_hash[11] = rotateLeft(last, 6);
|
||||
last = one;
|
||||
one = m_hash[17];
|
||||
m_hash[17] = rotateLeft(last, 10);
|
||||
last = one;
|
||||
one = m_hash[18];
|
||||
m_hash[18] = rotateLeft(last, 15);
|
||||
last = one;
|
||||
one = m_hash[3];
|
||||
m_hash[3] = rotateLeft(last, 21);
|
||||
last = one;
|
||||
one = m_hash[5];
|
||||
m_hash[5] = rotateLeft(last, 28);
|
||||
last = one;
|
||||
one = m_hash[16];
|
||||
m_hash[16] = rotateLeft(last, 36);
|
||||
last = one;
|
||||
one = m_hash[8];
|
||||
m_hash[8] = rotateLeft(last, 45);
|
||||
last = one;
|
||||
one = m_hash[21];
|
||||
m_hash[21] = rotateLeft(last, 55);
|
||||
last = one;
|
||||
one = m_hash[24];
|
||||
m_hash[24] = rotateLeft(last, 2);
|
||||
last = one;
|
||||
one = m_hash[4];
|
||||
m_hash[4] = rotateLeft(last, 14);
|
||||
last = one;
|
||||
one = m_hash[15];
|
||||
m_hash[15] = rotateLeft(last, 27);
|
||||
last = one;
|
||||
one = m_hash[23];
|
||||
m_hash[23] = rotateLeft(last, 41);
|
||||
last = one;
|
||||
one = m_hash[19];
|
||||
m_hash[19] = rotateLeft(last, 56);
|
||||
last = one;
|
||||
one = m_hash[13];
|
||||
m_hash[13] = rotateLeft(last, 8);
|
||||
last = one;
|
||||
one = m_hash[12];
|
||||
m_hash[12] = rotateLeft(last, 25);
|
||||
last = one;
|
||||
one = m_hash[2];
|
||||
m_hash[2] = rotateLeft(last, 43);
|
||||
last = one;
|
||||
one = m_hash[20];
|
||||
m_hash[20] = rotateLeft(last, 62);
|
||||
last = one;
|
||||
one = m_hash[14];
|
||||
m_hash[14] = rotateLeft(last, 18);
|
||||
last = one;
|
||||
one = m_hash[22];
|
||||
m_hash[22] = rotateLeft(last, 39);
|
||||
last = one;
|
||||
one = m_hash[9];
|
||||
m_hash[9] = rotateLeft(last, 61);
|
||||
last = one;
|
||||
one = m_hash[6];
|
||||
m_hash[6] = rotateLeft(last, 20);
|
||||
last = one;
|
||||
m_hash[1] = rotateLeft(last, 44);
|
||||
|
||||
// Chi
|
||||
for (unsigned int j = 0; j < 25; j += 5)
|
||||
{
|
||||
for (unsigned int j = 0; j < 25; j += 5) {
|
||||
// temporaries
|
||||
uint64_t one = m_hash[j];
|
||||
uint64_t two = m_hash[j + 1];
|
||||
@ -167,26 +183,21 @@ void SHA3::processBlock(const void* data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void SHA3::add(const void* data, size_t numBytes)
|
||||
{
|
||||
const uint8_t* current = (const uint8_t*) data;
|
||||
void SHA3::add(const void *data, size_t numBytes) {
|
||||
const uint8_t *current = (const uint8_t *)data;
|
||||
|
||||
// copy data to buffer
|
||||
if (m_bufferSize > 0)
|
||||
{
|
||||
while (numBytes > 0 && m_bufferSize < m_blockSize)
|
||||
{
|
||||
if (m_bufferSize > 0) {
|
||||
while (numBytes > 0 && m_bufferSize < m_blockSize) {
|
||||
m_buffer[m_bufferSize++] = *current++;
|
||||
numBytes--;
|
||||
}
|
||||
}
|
||||
|
||||
// full buffer
|
||||
if (m_bufferSize == m_blockSize)
|
||||
{
|
||||
processBlock((void*)m_buffer);
|
||||
if (m_bufferSize == m_blockSize) {
|
||||
processBlock((void *)m_buffer);
|
||||
m_numBytes += m_blockSize;
|
||||
m_bufferSize = 0;
|
||||
}
|
||||
@ -196,8 +207,7 @@ void SHA3::add(const void* data, size_t numBytes)
|
||||
return;
|
||||
|
||||
// process full blocks
|
||||
while (numBytes >= m_blockSize)
|
||||
{
|
||||
while (numBytes >= m_blockSize) {
|
||||
processBlock(current);
|
||||
current += m_blockSize;
|
||||
m_numBytes += m_blockSize;
|
||||
@ -205,17 +215,14 @@ void SHA3::add(const void* data, size_t numBytes)
|
||||
}
|
||||
|
||||
// keep remaining bytes in buffer
|
||||
while (numBytes > 0)
|
||||
{
|
||||
while (numBytes > 0) {
|
||||
m_buffer[m_bufferSize++] = *current++;
|
||||
numBytes--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// process everything left in the internal buffer
|
||||
void SHA3::processBuffer()
|
||||
{
|
||||
void SHA3::processBuffer() {
|
||||
// add padding
|
||||
size_t offset = m_bufferSize;
|
||||
// add a "1" byte
|
||||
@ -230,10 +237,8 @@ void SHA3::processBuffer()
|
||||
processBlock(m_buffer);
|
||||
}
|
||||
|
||||
|
||||
/// return latest hash as 16 hex characters
|
||||
std::string SHA3::getHash()
|
||||
{
|
||||
std::string SHA3::getHash() {
|
||||
// process remaining bytes
|
||||
processBuffer();
|
||||
|
||||
@ -249,7 +254,7 @@ std::string SHA3::getHash()
|
||||
for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes
|
||||
{
|
||||
// convert a byte to hex
|
||||
unsigned char oneByte = (unsigned char) (m_hash[i] >> (8 * j));
|
||||
unsigned char oneByte = (unsigned char)(m_hash[i] >> (8 * j));
|
||||
result += dec2hex[oneByte >> 4];
|
||||
result += dec2hex[oneByte & 15];
|
||||
}
|
||||
@ -257,10 +262,9 @@ std::string SHA3::getHash()
|
||||
// SHA3-224's last entry in m_hash provides only 32 bits instead of 64 bits
|
||||
unsigned int remainder = m_bits - hashLength * 64;
|
||||
unsigned int processed = 0;
|
||||
while (processed < remainder)
|
||||
{
|
||||
while (processed < remainder) {
|
||||
// convert a byte to hex
|
||||
unsigned char oneByte = (unsigned char) (m_hash[hashLength] >> processed);
|
||||
unsigned char oneByte = (unsigned char)(m_hash[hashLength] >> processed);
|
||||
result += dec2hex[oneByte >> 4];
|
||||
result += dec2hex[oneByte & 15];
|
||||
|
||||
@ -270,19 +274,15 @@ std::string SHA3::getHash()
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// compute SHA3 of a memory block
|
||||
std::string SHA3::operator()(const void* data, size_t numBytes)
|
||||
{
|
||||
std::string SHA3::operator()(const void *data, size_t numBytes) {
|
||||
reset();
|
||||
add(data, numBytes);
|
||||
return getHash();
|
||||
}
|
||||
|
||||
|
||||
/// compute SHA3 of a string, excluding final zero
|
||||
std::string SHA3::operator()(const std::string& text)
|
||||
{
|
||||
std::string SHA3::operator()(const std::string &text) {
|
||||
reset();
|
||||
add(text.c_str(), text.size());
|
||||
return getHash();
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// 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)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <list>
|
||||
@ -25,11 +24,10 @@
|
||||
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
||||
#endif
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
|
||||
{
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra() {
|
||||
auto module = std::make_shared<chaiscript::Module>();
|
||||
chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List", *module);
|
||||
chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t> >("u16vector", *module);
|
||||
chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value>>("List", *module);
|
||||
chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t>>("u16vector", *module);
|
||||
module->add(chaiscript::vector_conversion<std::vector<uint16_t>>());
|
||||
return module;
|
||||
}
|
||||
|
||||
@ -3,17 +3,42 @@
|
||||
#include <chaiscript/dispatchkit/bootstrap.hpp>
|
||||
#include <string>
|
||||
|
||||
class TestBaseType {
|
||||
public:
|
||||
TestBaseType()
|
||||
: val(10)
|
||||
, const_val(15)
|
||||
, mdarray{} {
|
||||
}
|
||||
TestBaseType(int)
|
||||
: val(10)
|
||||
, const_val(15)
|
||||
, mdarray{} {
|
||||
}
|
||||
TestBaseType(int *)
|
||||
: val(10)
|
||||
, const_val(15)
|
||||
, mdarray{} {
|
||||
}
|
||||
|
||||
TestBaseType(const TestBaseType &other)
|
||||
: val(other.val)
|
||||
, const_val(other.const_val)
|
||||
, const_val_ptr(&const_val)
|
||||
, func_member(other.func_member) {
|
||||
}
|
||||
|
||||
class TestBaseType
|
||||
{
|
||||
public:
|
||||
TestBaseType() : val(10), const_val(15), mdarray{} { }
|
||||
TestBaseType(int) : val(10), const_val(15), mdarray{} { }
|
||||
TestBaseType(int *) : val(10), const_val(15), mdarray{} { }
|
||||
TestBaseType(TestBaseType &&other)
|
||||
: val(other.val)
|
||||
, const_val(other.const_val)
|
||||
, const_val_ptr(&const_val)
|
||||
, func_member(std::move(other.func_member)) {
|
||||
}
|
||||
|
||||
TestBaseType(const TestBaseType &) = default;
|
||||
virtual ~TestBaseType() {}
|
||||
TestBaseType &operator=(TestBaseType &&) = delete;
|
||||
TestBaseType &operator=(const TestBaseType &) = delete;
|
||||
|
||||
virtual ~TestBaseType() = default;
|
||||
virtual int func() { return 0; }
|
||||
|
||||
int base_only_func() { return -9; }
|
||||
@ -24,112 +49,75 @@ class TestBaseType
|
||||
const int const_val;
|
||||
const int *const_val_ptr = &const_val;
|
||||
|
||||
const int *get_const_val_ptr() {
|
||||
return const_val_ptr;
|
||||
}
|
||||
const int *get_const_val_ptr() { return const_val_ptr; }
|
||||
|
||||
int mdarray[2][3][5];
|
||||
std::function<int (int)> func_member;
|
||||
std::function<int(int)> func_member;
|
||||
|
||||
void set_string_val(std::string &t_str)
|
||||
{
|
||||
t_str = "42";
|
||||
}
|
||||
|
||||
private:
|
||||
TestBaseType &operator=(const TestBaseType &) = delete;
|
||||
void set_string_val(std::string &t_str) { t_str = "42"; }
|
||||
};
|
||||
|
||||
class Type2
|
||||
{
|
||||
public:
|
||||
class Type2 {
|
||||
public:
|
||||
Type2(TestBaseType t_bt)
|
||||
: m_bt(std::move(t_bt)),
|
||||
m_str("Hello World")
|
||||
{
|
||||
: m_bt(std::move(t_bt))
|
||||
, m_str("Hello World") {
|
||||
}
|
||||
|
||||
int get_val() const
|
||||
{
|
||||
return m_bt.val;
|
||||
}
|
||||
int get_val() const { return m_bt.val; }
|
||||
|
||||
const char *get_str() const { return m_str.c_str(); }
|
||||
|
||||
const char *get_str() const
|
||||
{
|
||||
return m_str.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
TestBaseType m_bt;
|
||||
std::string m_str;
|
||||
};
|
||||
|
||||
enum TestEnum
|
||||
{
|
||||
enum TestEnum {
|
||||
TestValue1 = 1
|
||||
};
|
||||
|
||||
int to_int(TestEnum t)
|
||||
{
|
||||
int to_int(TestEnum t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
class TestDerivedType : public TestBaseType
|
||||
{
|
||||
public:
|
||||
~TestDerivedType() override {}
|
||||
TestDerivedType(const TestDerivedType &) = default;
|
||||
TestDerivedType() = default;
|
||||
virtual int func() override { return 1; }
|
||||
class TestDerivedType : public TestBaseType {
|
||||
public:
|
||||
int func() override { return 1; }
|
||||
int derived_only_func() { return 19; }
|
||||
|
||||
private:
|
||||
TestDerivedType &operator=(const TestDerivedType &) = delete;
|
||||
};
|
||||
|
||||
class TestMoreDerivedType : public TestDerivedType
|
||||
{
|
||||
public:
|
||||
TestMoreDerivedType(const TestMoreDerivedType &) = default;
|
||||
TestMoreDerivedType() = default;
|
||||
virtual ~TestMoreDerivedType() {}
|
||||
class TestMoreDerivedType : public TestDerivedType {
|
||||
public:
|
||||
};
|
||||
|
||||
std::shared_ptr<TestBaseType> derived_type_factory()
|
||||
{
|
||||
std::shared_ptr<TestBaseType> derived_type_factory() {
|
||||
return std::make_shared<TestDerivedType>();
|
||||
}
|
||||
|
||||
std::shared_ptr<TestBaseType> more_derived_type_factory()
|
||||
{
|
||||
std::shared_ptr<TestBaseType> more_derived_type_factory() {
|
||||
return std::make_shared<TestMoreDerivedType>();
|
||||
}
|
||||
|
||||
std::shared_ptr<TestBaseType> null_factory()
|
||||
{
|
||||
std::shared_ptr<TestBaseType> null_factory() {
|
||||
return std::shared_ptr<TestBaseType>();
|
||||
}
|
||||
|
||||
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
|
||||
{
|
||||
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr) {
|
||||
ptr = std::make_shared<TestDerivedType>();
|
||||
}
|
||||
|
||||
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
|
||||
{
|
||||
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr) {
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
std::string hello_world()
|
||||
{
|
||||
std::string hello_world() {
|
||||
return "Hello World";
|
||||
}
|
||||
|
||||
static int global_i = 1;
|
||||
|
||||
int *get_new_int()
|
||||
{
|
||||
int *get_new_int() {
|
||||
return &global_i;
|
||||
}
|
||||
|
||||
@ -145,8 +133,7 @@ int *get_new_int()
|
||||
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
||||
#endif
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module()
|
||||
{
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module() {
|
||||
chaiscript::ModulePtr m(new chaiscript::Module());
|
||||
|
||||
m->add(chaiscript::fun(hello_world), "hello_world");
|
||||
@ -156,16 +143,16 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
|
||||
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
|
||||
m->add(chaiscript::user_type<Type2>(), "Type2");
|
||||
|
||||
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
|
||||
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
|
||||
m->add(chaiscript::constructor<TestBaseType (const TestBaseType &)>(), "TestBaseType");
|
||||
m->add(chaiscript::constructor<TestBaseType (int *)>(), "TestBaseType");
|
||||
m->add(chaiscript::constructor<TestBaseType()>(), "TestBaseType");
|
||||
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
|
||||
m->add(chaiscript::constructor<TestBaseType(const TestBaseType &)>(), "TestBaseType");
|
||||
m->add(chaiscript::constructor<TestBaseType(int *)>(), "TestBaseType");
|
||||
|
||||
m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType");
|
||||
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
|
||||
m->add(chaiscript::constructor<TestDerivedType()>(), "TestDerivedType");
|
||||
m->add(chaiscript::constructor<TestDerivedType(const TestDerivedType &)>(), "TestDerivedType");
|
||||
|
||||
m->add(chaiscript::constructor<TestMoreDerivedType ()>(), "TestMoreDerivedType");
|
||||
m->add(chaiscript::constructor<TestMoreDerivedType (const TestMoreDerivedType &)>(), "TestMoreDerivedType");
|
||||
m->add(chaiscript::constructor<TestMoreDerivedType()>(), "TestMoreDerivedType");
|
||||
m->add(chaiscript::constructor<TestMoreDerivedType(const TestMoreDerivedType &)>(), "TestMoreDerivedType");
|
||||
|
||||
/// \todo automatic chaining of base classes?
|
||||
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
|
||||
@ -197,7 +184,6 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
|
||||
m->add(chaiscript::fun(&TestBaseType::func_member), "func_member");
|
||||
m->add(chaiscript::fun(&get_new_int), "get_new_int");
|
||||
|
||||
|
||||
m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1");
|
||||
|
||||
m->add(chaiscript::user_type<TestEnum>(), "TestEnum");
|
||||
@ -210,16 +196,14 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
|
||||
m->add(chaiscript::fun(&Type2::get_val), "get_val");
|
||||
m->add(chaiscript::fun(&Type2::get_str), "get_str");
|
||||
m->add(chaiscript::type_conversion<const char *, std::string>());
|
||||
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
|
||||
m->add(chaiscript::constructor<Type2(const TestBaseType &)>(), "Type2");
|
||||
|
||||
m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr");
|
||||
m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr");
|
||||
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __llvm__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
#include "../include/chaiscript/language/chaiscript_parser.hpp"
|
||||
#include "chaiscript_parser.hpp"
|
||||
|
||||
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser()
|
||||
{
|
||||
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser() {
|
||||
return std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>();
|
||||
}
|
||||
|
||||
|
||||
@ -2,11 +2,13 @@
|
||||
#ifndef CHAISCRIPT_PARSER_LIB
|
||||
#define CHAISCRIPT_PARSER_LIB
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace chaiscript {
|
||||
namespace parser {
|
||||
class ChaiScript_Parser_Base;
|
||||
}
|
||||
}
|
||||
} // namespace chaiscript
|
||||
|
||||
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser();
|
||||
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
#include "../include/chaiscript/chaiscript_stdlib.hpp"
|
||||
#include "chaiscript_stdlib.hpp"
|
||||
|
||||
std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib()
|
||||
{
|
||||
std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib() {
|
||||
return chaiscript::Std_Lib::library();
|
||||
}
|
||||
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 = 2 } );
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 + 2 = 2 } );
|
||||
@ -1,2 +0,0 @@
|
||||
var prod = bind(foldl, _, `*`, 1.0)
|
||||
assert_equal(60, prod([3, 4, 5]))
|
||||
@ -1,34 +0,0 @@
|
||||
|
||||
def add(x, y)
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
|
||||
assert_equal(2, add.get_arity());
|
||||
|
||||
var b = bind(add, 2, _);
|
||||
|
||||
assert_equal(1, b.get_arity());
|
||||
|
||||
var c = bind(b, 3);
|
||||
|
||||
assert_equal(0, c.get_arity());
|
||||
|
||||
assert_equal(6, b(4));
|
||||
assert_equal(5, c());
|
||||
|
||||
def concat2(a,b,c,d)
|
||||
{
|
||||
return to_string(a) + to_string(b) + to_string(c) + to_string(d);
|
||||
}
|
||||
|
||||
var d = bind(concat2, _, " Hello ", _, " World");
|
||||
assert_equal(2, d.get_arity());
|
||||
|
||||
assert_equal("1 Hello 3 World", d(1,3));
|
||||
|
||||
var e = bind(`<`, _, 5);
|
||||
var types = e.get_param_types();
|
||||
assert_equal(2, types.size());
|
||||
assert_equal(true, types[0].bare_equal(bool_type));
|
||||
|
||||
@ -1 +0,0 @@
|
||||
{print("hello")}
|
||||
@ -1 +0,0 @@
|
||||
assert_equal(false, !true)
|
||||
@ -1,7 +0,0 @@
|
||||
var i = 0
|
||||
while (i < 10) {
|
||||
if (++i == 5) {
|
||||
break
|
||||
}
|
||||
}
|
||||
assert_equal(5, i);
|
||||
@ -1 +0,0 @@
|
||||
assert_equal("b", to_string('b'))
|
||||
@ -1,7 +0,0 @@
|
||||
assert_equal(true, 1.is_var_const());
|
||||
assert_equal(false, 1.is_var_reference());
|
||||
assert_equal(true, 1.is_var_pointer());
|
||||
assert_equal(false, 1.is_var_null());
|
||||
assert_equal(false, 1.is_var_undef());
|
||||
var i;
|
||||
assert_equal(true, i.is_var_undef());
|
||||
@ -1,3 +0,0 @@
|
||||
var v = collate(1, 2)
|
||||
assert_equal(1, v[0])
|
||||
assert_equal(2, v[1])
|
||||
@ -1 +0,0 @@
|
||||
assert_equal(false, 1 > 2);
|
||||
@ -1 +0,0 @@
|
||||
assert_equal(true, 1 < 2)
|
||||
@ -1,5 +0,0 @@
|
||||
var v = concat([1, 2], [3, 4]);
|
||||
|
||||
assert_equal(4, v.size());
|
||||
assert_equal(1, v[0]);
|
||||
assert_equal(4, v[3]);
|
||||
@ -1,4 +0,0 @@
|
||||
//If the following succeeds, the test passes
|
||||
|
||||
|
||||
"Hello World".for_each(fun(x) { print(x) } )
|
||||
@ -1 +0,0 @@
|
||||
assert_equal("3.5bob", 3.5.to_string() + "bob");
|
||||
@ -1 +0,0 @@
|
||||
assert_equal("3bob", 3.to_string + "bob")
|
||||
@ -1 +0,0 @@
|
||||
assert_equal(6.8, "3.5".to_double() + 3.3)
|
||||
@ -1 +0,0 @@
|
||||
assert_equal(8, "4".to_int() + 4)
|
||||
@ -1,11 +0,0 @@
|
||||
var a = [1,2,3, [4,5,6] ]
|
||||
|
||||
assert_equal(a[3][0], 4)
|
||||
|
||||
|
||||
def Test::Test() { this.a = [1,2,3]; }
|
||||
attr Test::a;
|
||||
|
||||
var t = Test();
|
||||
|
||||
assert_equal(t.a[0], 1)
|
||||
@ -1,10 +0,0 @@
|
||||
assert_equal(`==`, `==`);
|
||||
assert_not_equal(`==`, `<`);
|
||||
assert_equal(`<`.get_arity(), 2);
|
||||
assert_equal(get_arity.get_contained_functions().size(), 0);
|
||||
assert_equal(get_arity.get_arity(), 1);
|
||||
assert_equal(get_arity.get_param_types().size(), 2);
|
||||
|
||||
var paramtypes = get_arity.get_param_types();
|
||||
|
||||
assert_equal(true, paramtypes[1].bare_equal(Function_type));
|
||||
@ -1 +0,0 @@
|
||||
assert_equal([3,4], drop([1, 2, 3, 4], 2))
|
||||
@ -1 +0,0 @@
|
||||
assert_equal([2, 3], drop_while([1, 2, 3], odd))
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user