mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2025-12-06 16:57:04 +08:00
Merge remote-tracking branch 'origin/develop' into apply_unicode_patches
This commit is contained in:
commit
2818ec67df
0
.buckconfig
Normal file
0
.buckconfig
Normal file
98
.clang-format
Normal file
98
.clang-format
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
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
|
||||||
|
ColumnLimit: 0
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 2
|
||||||
|
ContinuationIndentWidth: 2
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: true
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: 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
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: true
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
Language: Cpp
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 2
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
ObjCBlockIndentWidth: 7
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
ObjCSpaceBeforeProtocolList: false
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 0
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/buck-out/
|
||||||
|
/.buckd/
|
||||||
|
/buckaroo/
|
||||||
|
.buckconfig.local
|
||||||
|
BUCKAROO_DEPS
|
||||||
23
.travis.yml
23
.travis.yml
@ -8,6 +8,7 @@ addons:
|
|||||||
packages:
|
packages:
|
||||||
- g++-4.9
|
- g++-4.9
|
||||||
- g++-5
|
- g++-5
|
||||||
|
- g++-6
|
||||||
coverity_scan:
|
coverity_scan:
|
||||||
project:
|
project:
|
||||||
name: "ChaiScript/ChaiScript"
|
name: "ChaiScript/ChaiScript"
|
||||||
@ -23,14 +24,25 @@ matrix:
|
|||||||
sudo: false
|
sudo: false
|
||||||
env: GCC_VER="4.9"
|
env: GCC_VER="4.9"
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
|
# - os: linux
|
||||||
|
#sudo: false
|
||||||
|
#env: GCC_VER="6" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
|
||||||
|
#compiler: gcc
|
||||||
- os: linux
|
- os: linux
|
||||||
sudo: false
|
sudo: false
|
||||||
env: GCC_VER="5"
|
env: GCC_VER="5" 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"
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
- os: osx
|
- os: osx
|
||||||
compiler: clang
|
compiler: clang
|
||||||
osx_image: xcode8
|
osx_image: xcode8
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
osx_image: xcode8
|
||||||
|
env: CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
@ -40,14 +52,13 @@ env:
|
|||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
|
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
|
||||||
- if [ "${GCC_VER}" == "5" ]; then export CPPCHECK=1 COVERAGE=1 FUZZY_CMD="-D RUN_FUZZY_TESTS:BOOL=TRUE" ; fi
|
|
||||||
- pip install --user cpp-coveralls
|
- pip install --user cpp-coveralls
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $FUZZY_CMD .
|
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS .
|
||||||
- cmake --build . -- -j2
|
- cmake --build . -- -j2
|
||||||
- ctest
|
- if [ "${BUILD_ONLY}" != "1" ]; then ctest; fi
|
||||||
- if [ ${COVERAGE} = 1 ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
|
- if [ "${COVERAGE}" = "1" ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
|
||||||
|
|
||||||
#after_script:
|
#after_script:
|
||||||
# - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
|
# - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
|
||||||
|
|||||||
11
BUCK
Normal file
11
BUCK
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
prebuilt_cxx_library(
|
||||||
|
name = 'chaiscript',
|
||||||
|
header_only = True,
|
||||||
|
header_namespace = 'chaiscript',
|
||||||
|
exported_headers = subdir_glob([
|
||||||
|
('include/chaiscript', '**/*.hpp'),
|
||||||
|
]),
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC',
|
||||||
|
],
|
||||||
|
)
|
||||||
@ -14,6 +14,7 @@ ELSE()
|
|||||||
project(chaiscript)
|
project(chaiscript)
|
||||||
|
|
||||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||||
|
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
|
||||||
|
|
||||||
|
|
||||||
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
|
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
|
||||||
@ -21,6 +22,7 @@ option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
|||||||
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
|
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
|
||||||
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
|
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
|
||||||
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
|
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)
|
mark_as_advanced(USE_STD_MAKE_SHARED)
|
||||||
|
|
||||||
@ -149,17 +151,31 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
|||||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||||
|
|
||||||
if(GCC_VERSION VERSION_LESS 4.9)
|
if(GCC_VERSION VERSION_LESS 4.9)
|
||||||
set(CPP11_FLAG "-std=c++1y")
|
set(CPP14_FLAG "-std=c++1y")
|
||||||
else()
|
else()
|
||||||
set(CPP11_FLAG "-std=c++14")
|
if (BUILD_IN_CPP17_MODE)
|
||||||
|
set(CPP14_FLAG "-std=c++1z")
|
||||||
|
else()
|
||||||
|
set(CPP14_FLAG "-std=c++14")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
set(CPP11_FLAG "-std=c++14")
|
if (BUILD_IN_CPP17_MODE)
|
||||||
|
set(CPP14_FLAG "-std=c++1z")
|
||||||
|
else()
|
||||||
|
set(CPP14_FLAG "-std=c++14")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
|
add_definitions(/W4 /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
|
# VS2013 doesn't have magic statics
|
||||||
add_definitions(/w44640)
|
add_definitions(/w44640)
|
||||||
@ -168,7 +184,7 @@ if(MSVC)
|
|||||||
add_definitions(/w34062)
|
add_definitions(/w34062)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(/bigobj)
|
add_definitions(/bigobj /permissive-)
|
||||||
# Note on MSVC compiler flags.
|
# Note on MSVC compiler flags.
|
||||||
# The code base selective disables warnings as necessary when the compiler is complaining too much
|
# The code base selective disables warnings as necessary when the compiler is complaining too much
|
||||||
# about something that is perfectly valid, or there is simply no technical way around it
|
# about something that is perfectly valid, or there is simply no technical way around it
|
||||||
@ -178,10 +194,10 @@ if(MSVC)
|
|||||||
# how to workaround or fix the error. So I'm disabling it globally.
|
# how to workaround or fix the error. So I'm disabling it globally.
|
||||||
add_definitions(/wd4503)
|
add_definitions(/wd4503)
|
||||||
else()
|
else()
|
||||||
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
|
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP14_FLAG})
|
||||||
|
|
||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command)
|
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template)
|
||||||
else()
|
else()
|
||||||
add_definitions(-Wnoexcept)
|
add_definitions(-Wnoexcept)
|
||||||
endif()
|
endif()
|
||||||
@ -196,12 +212,12 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
|||||||
|
|
||||||
if(USE_LIBCXX)
|
if(USE_LIBCXX)
|
||||||
add_definitions(-stdlib=libc++)
|
add_definitions(-stdlib=libc++)
|
||||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++")
|
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG} -stdlib=libc++")
|
||||||
else()
|
else()
|
||||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
|
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}")
|
||||||
endif()
|
endif()
|
||||||
elseif(CMAKE_COMPILER_IS_GNUCC)
|
elseif(CMAKE_COMPILER_IS_GNUCC)
|
||||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
|
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# limitations in MinGW require us to make an optimized build
|
# limitations in MinGW require us to make an optimized build
|
||||||
@ -221,9 +237,15 @@ if(NOT MULTITHREAD_SUPPORT_ENABLED)
|
|||||||
add_definitions(-DCHAISCRIPT_NO_THREADS)
|
add_definitions(-DCHAISCRIPT_NO_THREADS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT DYNLOAD_ENABLED)
|
||||||
|
add_definitions(-DCHAISCRIPT_NO_DYNLOAD)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(CMAKE_HOST_UNIX)
|
if(CMAKE_HOST_UNIX)
|
||||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
|
if(DYNLOAD_ENABLED)
|
||||||
list(APPEND LIBS "dl")
|
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
|
||||||
|
list(APPEND LIBS "dl")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MULTITHREAD_SUPPORT_ENABLED)
|
if(MULTITHREAD_SUPPORT_ENABLED)
|
||||||
@ -298,32 +320,17 @@ if (RUN_FUZZY_TESTS)
|
|||||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
|
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
|
||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2016-06-29.tar.bz2
|
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2017-07-20.tar.bz2
|
||||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
file(GLOB FUZZY_CRASH_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/id*)
|
file(GLOB FUZZY_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/MINIMIZED/*)
|
||||||
list(SORT FUZZY_CRASH_TESTS)
|
list(SORT FUZZY_TESTS)
|
||||||
|
|
||||||
file(GLOB FUZZY_EXCEPTION_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/id*)
|
foreach(filename ${FUZZY_TESTS})
|
||||||
list(SORT FUZZY_EXCEPTION_TESTS)
|
|
||||||
|
|
||||||
|
|
||||||
foreach(filename ${FUZZY_CRASH_TESTS})
|
|
||||||
message(STATUS "Adding test ${filename}")
|
message(STATUS "Adding test ${filename}")
|
||||||
add_test(${filename} chai "-e" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
add_test(fuzz.${filename} chai "-e" "--exception" "--any-exception" ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzz_unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
||||||
endforeach()
|
|
||||||
|
|
||||||
set_property(TEST ${FUZZY_CRASH_TESTS}
|
|
||||||
PROPERTY ENVIRONMENT
|
|
||||||
"CHAI_USE_PATH=${CMAKE_BINARY_DIR}/unittests/"
|
|
||||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
|
||||||
)
|
|
||||||
|
|
||||||
foreach(filename ${FUZZY_EXCEPTION_TESTS})
|
|
||||||
message(STATUS "Adding test ${filename}")
|
|
||||||
add_test(${filename} chai "--exception" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
|
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
|
||||||
@ -427,6 +434,9 @@ if(BUILD_TESTING)
|
|||||||
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS})
|
||||||
ADD_CATCH_TESTS(compiled_tests)
|
ADD_CATCH_TESTS(compiled_tests)
|
||||||
|
|
||||||
|
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp)
|
||||||
|
target_link_libraries(static_chaiscript_test ${LIBS})
|
||||||
|
add_test(NAME Static_ChaiScript_Test COMMAND static_chaiscript_test)
|
||||||
|
|
||||||
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
|
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
|
||||||
target_link_libraries(boxed_cast_test ${LIBS})
|
target_link_libraries(boxed_cast_test ${LIBS})
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
version: 5.8.x.{build}
|
version: 5.8.x.{build}
|
||||||
os: Visual Studio 2015
|
image:
|
||||||
|
- Visual Studio 2017
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- {}
|
- VS_VERSION: "Visual Studio 14"
|
||||||
|
- VS_VERSION: "Visual Studio 15"
|
||||||
build_script:
|
build_script:
|
||||||
- cmd: >-
|
- cmd: >-
|
||||||
mkdir build
|
mkdir build
|
||||||
|
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
cmake c:\Projects\chaiscript -G "Visual Studio 14"
|
cmake c:\Projects\chaiscript -G "%VS_VERSION%"
|
||||||
|
|
||||||
cmake --build . --config Debug
|
cmake --build . --config Debug
|
||||||
test_script:
|
test_script:
|
||||||
|
|||||||
3
buckaroo.json
Normal file
3
buckaroo.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"name": "ChaiScript"
|
||||||
|
}
|
||||||
@ -5,7 +5,7 @@ ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme.
|
|||||||
* Major Version Number: API changes / breaking changes
|
* Major Version Number: API changes / breaking changes
|
||||||
* Minor Version Number: New Features
|
* Minor Version Number: New Features
|
||||||
* Patch Version Number: Minor changes / enhancements
|
* Patch Version Number: Minor changes / enhancements
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Initializing ChaiScript
|
# Initializing ChaiScript
|
||||||
@ -15,6 +15,9 @@ chaiscript::ChaiScript chai; // loads stdlib from loadable module on file system
|
|||||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
|
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that ChaiScript cannot be used as a global / static object unless it is being compiled with `CHAISCRIPT_NO_THREADS`.
|
||||||
|
|
||||||
|
|
||||||
# Adding Things To The Engine
|
# Adding Things To The Engine
|
||||||
|
|
||||||
## Adding a Function / Method / Member
|
## Adding a Function / Method / Member
|
||||||
@ -34,7 +37,7 @@ chai.add(chaiscript::fun(&Class::method_name, Class_instance_ptr), "method_name"
|
|||||||
chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name");
|
chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name");
|
||||||
```
|
```
|
||||||
|
|
||||||
### With Overloads
|
### With Overloads
|
||||||
|
|
||||||
#### Preferred
|
#### Preferred
|
||||||
|
|
||||||
@ -66,9 +69,9 @@ chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
|
|||||||
```
|
```
|
||||||
chai.add(
|
chai.add(
|
||||||
chaiscript::fun<std::string (bool)>(
|
chaiscript::fun<std::string (bool)>(
|
||||||
[](bool type) {
|
[](bool type) {
|
||||||
if (type) { return "x"; }
|
if (type) { return "x"; }
|
||||||
else { return "y"; }
|
else { return "y"; }
|
||||||
}), "function_name");
|
}), "function_name");
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -163,6 +166,23 @@ chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throw
|
|||||||
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
|
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Adding Namespaces
|
||||||
|
|
||||||
|
Namespaces will not be populated until `import` is called.
|
||||||
|
This saves memory and computing costs if a namespace is not imported into every ChaiScript instance.
|
||||||
|
```
|
||||||
|
chai.register_namespace([](chaiscript::Namespace& math) {
|
||||||
|
math["pi"] = chaiscript::const_var(3.14159);
|
||||||
|
math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); },
|
||||||
|
"math");
|
||||||
|
```
|
||||||
|
|
||||||
|
Import namespace in ChaiScript
|
||||||
|
```
|
||||||
|
import("math")
|
||||||
|
print(math.pi) // prints 3.14159
|
||||||
|
```
|
||||||
|
|
||||||
# Using STL
|
# Using STL
|
||||||
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
|
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
|
||||||
|
|
||||||
@ -476,6 +496,20 @@ o.f = fun(y) { print(this.x + y); }
|
|||||||
o.f(10); // prints 13
|
o.f(10); // prints 13
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Namespaces
|
||||||
|
|
||||||
|
Namespaces in ChaiScript are Dynamic Objects with global scope
|
||||||
|
|
||||||
|
```
|
||||||
|
namespace("math") // create a new namespace
|
||||||
|
|
||||||
|
math.square = fun(x) { x * x } // add a function to the "math" namespace
|
||||||
|
math.sum_squares = fun(x, y) { math.square(x) + math.square(y) }
|
||||||
|
|
||||||
|
print(math.square(4)) // prints 16
|
||||||
|
print(math.sum_squares(2, 5)) // prints 29
|
||||||
|
```
|
||||||
|
|
||||||
### Option Explicit
|
### Option Explicit
|
||||||
|
|
||||||
If you want to disable dynamic parameter definitions, you can `set_explicit`.
|
If you want to disable dynamic parameter definitions, you can `set_explicit`.
|
||||||
|
|||||||
1
contrib/vim
Normal file
1
contrib/vim
Normal file
@ -0,0 +1 @@
|
|||||||
|
vim support can be found at https://github.com/ChaiScript/vim-chaiscript
|
||||||
@ -1,7 +0,0 @@
|
|||||||
Install ftdetect, indent and syntax subdirectories to:
|
|
||||||
|
|
||||||
~/.vim/
|
|
||||||
|
|
||||||
See the vim documentation on this:
|
|
||||||
|
|
||||||
http://vimdoc.sourceforge.net/htmldoc/syntax.html#mysyntaxfile
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
au BufRead,BufNewFile *.chai set filetype=chaiscript
|
|
||||||
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
" Vim indent file
|
|
||||||
" Language: ChaiScript
|
|
||||||
" Maintainer: Jason Turner <lefticus 'at' gmail com>
|
|
||||||
|
|
||||||
" Only load this indent file when no other was loaded.
|
|
||||||
if exists("b:did_indent")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let b:did_indent = 1
|
|
||||||
|
|
||||||
setlocal indentexpr=GetChaiScriptIndent()
|
|
||||||
setlocal autoindent
|
|
||||||
|
|
||||||
" Only define the function once.
|
|
||||||
if exists("*GetChaiScriptIndent")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
function! GetChaiScriptIndent()
|
|
||||||
" Find a non-blank line above the current line.
|
|
||||||
let lnum = prevnonblank(v:lnum - 1)
|
|
||||||
|
|
||||||
" Hit the start of the file, use zero indent.
|
|
||||||
if lnum == 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Add a 'shiftwidth' after lines that start a block:
|
|
||||||
" lines containing a {
|
|
||||||
let ind = indent(lnum)
|
|
||||||
let flag = 0
|
|
||||||
let prevline = getline(lnum)
|
|
||||||
if prevline =~ '^.*{.*'
|
|
||||||
let ind = ind + &shiftwidth
|
|
||||||
let flag = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Subtract a 'shiftwidth' after lines containing a { followed by a }
|
|
||||||
" to keep it balanced
|
|
||||||
if flag == 1 && prevline =~ '.*{.*}.*'
|
|
||||||
let ind = ind - &shiftwidth
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Subtract a 'shiftwidth' on lines ending with }
|
|
||||||
if getline(v:lnum) =~ '^\s*\%(}\)'
|
|
||||||
let ind = ind - &shiftwidth
|
|
||||||
endif
|
|
||||||
|
|
||||||
return ind
|
|
||||||
endfunction
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
" Vim syntax file
|
|
||||||
" Language: ChaiScript
|
|
||||||
" Maintainer: Jason Turner <lefticus 'at' gmail com>
|
|
||||||
|
|
||||||
" Quit when a (custom) syntax file was already loaded
|
|
||||||
if exists("b:current_syntax")
|
|
||||||
finish
|
|
||||||
end
|
|
||||||
|
|
||||||
let s:cpo_save = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
syn case match
|
|
||||||
|
|
||||||
" syncing method
|
|
||||||
syn sync fromstart
|
|
||||||
|
|
||||||
" Strings
|
|
||||||
syn region chaiscriptString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=chaiscriptSpecial,chaiscriptEval,@Spell
|
|
||||||
|
|
||||||
" Escape characters
|
|
||||||
syn match chaiscriptSpecial contained "\\[\\abfnrtv\'\"]\|\\\d\{,3}"
|
|
||||||
|
|
||||||
" String evals
|
|
||||||
syn region chaiscriptEval contained start="${" end="}"
|
|
||||||
|
|
||||||
" integer number
|
|
||||||
syn match chaiscriptNumber "\<\d\+\>"
|
|
||||||
|
|
||||||
" floating point number, with dot, optional exponent
|
|
||||||
syn match chaiscriptFloat "\<\d\+\.\d*\%(e[-+]\=\d\+\)\=\>"
|
|
||||||
|
|
||||||
" floating point number, starting with a dot, optional exponent
|
|
||||||
syn match chaiscriptFloat "\.\d\+\%(e[-+]\=\d\+\)\=\>"
|
|
||||||
|
|
||||||
" floating point number, without dot, with exponent
|
|
||||||
syn match chaiscriptFloat "\<\d\+e[-+]\=\d\+\>"
|
|
||||||
|
|
||||||
" Hex strings
|
|
||||||
syn match chaiscriptNumber "\<0x\x\+\>"
|
|
||||||
|
|
||||||
" Binary strings
|
|
||||||
syn match chaiscriptNumber "\<0b[01]\+\>"
|
|
||||||
|
|
||||||
" Various language features
|
|
||||||
syn keyword chaiscriptCond if else
|
|
||||||
syn keyword chaiscriptRepeat while for do
|
|
||||||
syn keyword chaiscriptStatement break continue return switch case default
|
|
||||||
syn keyword chaiscriptExceptions try catch throw
|
|
||||||
|
|
||||||
"Keyword
|
|
||||||
syn keyword chaiscriptKeyword def true false attr
|
|
||||||
|
|
||||||
"Built in types
|
|
||||||
syn keyword chaiscriptType fun var auto
|
|
||||||
|
|
||||||
"Built in funcs, keep it simple
|
|
||||||
syn keyword chaiscriptFunc eval throw
|
|
||||||
|
|
||||||
"Let's treat all backtick operator function lookups as built in too
|
|
||||||
syn region chaiscriptFunc matchgroup=chaiscriptFunc start="`" end="`"
|
|
||||||
|
|
||||||
" Account for the "[1..10]" syntax, treating it as an operator
|
|
||||||
" Intentionally leaving out all of the normal, well known operators
|
|
||||||
syn match chaiscriptOperator "\.\."
|
|
||||||
|
|
||||||
" Guard seperator as an operator
|
|
||||||
syn match chaiscriptOperator ":"
|
|
||||||
|
|
||||||
" Comments
|
|
||||||
syn match chaiscriptComment "//.*$" contains=@Spell
|
|
||||||
syn region chaiscriptComment matchgroup=chaiscriptComment start="/\*" end="\*/" contains=@Spell
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
hi def link chaiscriptExceptions Exception
|
|
||||||
hi def link chaiscriptKeyword Keyword
|
|
||||||
hi def link chaiscriptStatement Statement
|
|
||||||
hi def link chaiscriptRepeat Repeat
|
|
||||||
hi def link chaiscriptString String
|
|
||||||
hi def link chaiscriptNumber Number
|
|
||||||
hi def link chaiscriptFloat Float
|
|
||||||
hi def link chaiscriptOperator Operator
|
|
||||||
hi def link chaiscriptConstant Constant
|
|
||||||
hi def link chaiscriptCond Conditional
|
|
||||||
hi def link chaiscriptFunction Function
|
|
||||||
hi def link chaiscriptComment Comment
|
|
||||||
hi def link chaiscriptTodo Todo
|
|
||||||
hi def link chaiscriptError Error
|
|
||||||
hi def link chaiscriptSpecial SpecialChar
|
|
||||||
hi def link chaiscriptFunc Identifier
|
|
||||||
hi def link chaiscriptType Type
|
|
||||||
hi def link chaiscriptEval Special
|
|
||||||
|
|
||||||
let b:current_syntax = "chaiscript"
|
|
||||||
|
|
||||||
let &cpo = s:cpo_save
|
|
||||||
unlet s:cpo_save
|
|
||||||
" vim: nowrap sw=2 sts=2 ts=8 noet
|
|
||||||
@ -832,7 +832,7 @@ namespace chaiscript
|
|||||||
public:
|
public:
|
||||||
ChaiScript(std::vector<std::string> t_modulepaths = {},
|
ChaiScript(std::vector<std::string> t_modulepaths = {},
|
||||||
std::vector<std::string> t_usepaths = {},
|
std::vector<std::string> t_usepaths = {},
|
||||||
const std::vector<Options> &t_opts = {})
|
const std::vector<Options> &t_opts = chaiscript::default_options())
|
||||||
: ChaiScript_Basic(
|
: ChaiScript_Basic(
|
||||||
chaiscript::Std_Lib::library(),
|
chaiscript::Std_Lib::library(),
|
||||||
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
|
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
|
||||||
|
|||||||
@ -93,6 +93,16 @@ namespace chaiscript {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename B, typename D, typename ...Arg>
|
||||||
|
inline std::unique_ptr<B> make_unique(Arg && ... arg)
|
||||||
|
{
|
||||||
|
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
|
||||||
|
return std::make_unique<D>(std::forward<Arg>(arg)...);
|
||||||
|
#else
|
||||||
|
return std::unique_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
struct Build_Info {
|
struct Build_Info {
|
||||||
static int version_major()
|
static int version_major()
|
||||||
{
|
{
|
||||||
@ -156,48 +166,56 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
||||||
{
|
{
|
||||||
T t = 0;
|
T t = 0;
|
||||||
T base = 0;
|
T base{};
|
||||||
T decimal_place = 0;
|
T decimal_place = 0;
|
||||||
bool exponent = false;
|
int exponent = 0;
|
||||||
bool neg_exponent = false;
|
|
||||||
|
|
||||||
const auto final_value = [](const T val, const T baseval, const bool hasexp, const bool negexp) -> T {
|
for (char c;; ++t_str) {
|
||||||
if (!hasexp) {
|
c = *t_str;
|
||||||
return val;
|
switch (c)
|
||||||
} else {
|
{
|
||||||
return baseval * std::pow(T(10), val*T(negexp?-1:1));
|
case '.':
|
||||||
}
|
decimal_place = 10;
|
||||||
};
|
break;
|
||||||
|
case 'e':
|
||||||
for(; *t_str != '\0'; ++t_str) {
|
case 'E':
|
||||||
char c = *t_str;
|
exponent = 1;
|
||||||
if (c == '.') {
|
decimal_place = 0;
|
||||||
decimal_place = 10;
|
base = t;
|
||||||
} else if (c == 'e' || c == 'E') {
|
t = 0;
|
||||||
exponent = true;
|
break;
|
||||||
decimal_place = 0;
|
case '-':
|
||||||
base = t;
|
exponent = -1;
|
||||||
t = 0;
|
break;
|
||||||
} else if (c == '-' && exponent) {
|
case '+':
|
||||||
neg_exponent = true;
|
break;
|
||||||
} else if (c == '+' && exponent) {
|
case '0':
|
||||||
neg_exponent = false;
|
case '1':
|
||||||
} else if (c < '0' || c > '9') {
|
case '2':
|
||||||
return final_value(t, base, exponent, neg_exponent);
|
case '3':
|
||||||
} else if (decimal_place < T(10)) {
|
case '4':
|
||||||
t *= T(10);
|
case '5':
|
||||||
t += T(c - '0');
|
case '6':
|
||||||
} else {
|
case '7':
|
||||||
t += (T(c - '0') / (T(decimal_place)));
|
case '8':
|
||||||
decimal_place *= 10;
|
case '9':
|
||||||
}
|
if (decimal_place < 10) {
|
||||||
}
|
t *= 10;
|
||||||
|
t += static_cast<T>(c - '0');
|
||||||
return final_value(t, base, exponent, neg_exponent);
|
}
|
||||||
|
else {
|
||||||
|
t += static_cast<T>(c - '0') / decimal_place;
|
||||||
|
decimal_place *= 10;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -216,7 +234,11 @@ namespace chaiscript {
|
|||||||
|
|
||||||
static inline std::vector<Options> default_options()
|
static inline std::vector<Options> default_options()
|
||||||
{
|
{
|
||||||
|
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||||
|
return {Options::No_Load_Modules, Options::External_Scripts};
|
||||||
|
#else
|
||||||
return {Options::Load_Modules, Options::External_Scripts};
|
return {Options::Load_Modules, Options::External_Scripts};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -67,44 +67,44 @@ namespace chaiscript
|
|||||||
class Thread_Storage
|
class Thread_Storage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Thread_Storage() = default;
|
||||||
explicit Thread_Storage(void *t_key)
|
Thread_Storage(const Thread_Storage &) = delete;
|
||||||
: m_key(t_key)
|
Thread_Storage(Thread_Storage &&) = delete;
|
||||||
{
|
Thread_Storage &operator=(const Thread_Storage &) = delete;
|
||||||
}
|
Thread_Storage &operator=(Thread_Storage &&) = delete;
|
||||||
|
|
||||||
~Thread_Storage()
|
~Thread_Storage()
|
||||||
{
|
{
|
||||||
t().erase(m_key);
|
t().erase(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const T *operator->() const
|
inline const T *operator->() const
|
||||||
{
|
{
|
||||||
return &(t()[m_key]);
|
return &(t()[this]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const T &operator*() const
|
inline const T &operator*() const
|
||||||
{
|
{
|
||||||
return t()[m_key];
|
return t()[this];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline T *operator->()
|
inline T *operator->()
|
||||||
{
|
{
|
||||||
return &(t()[m_key]);
|
return &(t()[this]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline T &operator*()
|
inline T &operator*()
|
||||||
{
|
{
|
||||||
return t()[m_key];
|
return t()[this];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *m_key;
|
void *m_key;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::unordered_map<void*, T> &t()
|
static std::unordered_map<const void*, T> &t()
|
||||||
{
|
{
|
||||||
thread_local static std::unordered_map<void *, T> my_t;
|
thread_local std::unordered_map<const void *, T> my_t;
|
||||||
return my_t;
|
return my_t;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -144,7 +144,7 @@ namespace chaiscript
|
|||||||
class Thread_Storage
|
class Thread_Storage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Thread_Storage(void *)
|
explicit Thread_Storage()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -144,6 +144,7 @@ namespace chaiscript
|
|||||||
construct_pod<T>(name, m);
|
construct_pod<T>(name, m);
|
||||||
|
|
||||||
m.add(fun(&parse_string<T>), "to_" + name);
|
m.add(fun(&parse_string<T>), "to_" + name);
|
||||||
|
m.add(fun([](const T t){ return t; }), "to_" + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -305,13 +306,13 @@ namespace chaiscript
|
|||||||
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||||
{
|
{
|
||||||
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||||
return pf && pf->get_parse_tree();
|
return bool(pf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static chaiscript::AST_NodePtr 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);
|
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||||
if (pf && pf->get_parse_tree())
|
if (pf)
|
||||||
{
|
{
|
||||||
return pf->get_parse_tree();
|
return pf->get_parse_tree();
|
||||||
} else {
|
} else {
|
||||||
@ -545,7 +546,7 @@ namespace chaiscript
|
|||||||
std::vector<Boxed_Value> retval;
|
std::vector<Boxed_Value> retval;
|
||||||
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
||||||
std::back_inserter(retval),
|
std::back_inserter(retval),
|
||||||
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
|
&chaiscript::var<const chaiscript::AST_Node_Trace &>);
|
||||||
return retval;
|
return retval;
|
||||||
}), "call_stack"} }
|
}), "call_stack"} }
|
||||||
);
|
);
|
||||||
@ -574,7 +575,7 @@ namespace chaiscript
|
|||||||
const auto children = t_node.get_children();
|
const auto children = t_node.get_children();
|
||||||
std::transform(children.begin(), children.end(),
|
std::transform(children.begin(), children.end(),
|
||||||
std::back_inserter(retval),
|
std::back_inserter(retval),
|
||||||
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
|
&chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>);
|
||||||
return retval;
|
return retval;
|
||||||
}), "children"}
|
}), "children"}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -335,9 +335,24 @@ namespace chaiscript
|
|||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void back_insertion_sequence_type(const std::string &type, Module& m)
|
void back_insertion_sequence_type(const std::string &type, Module& m)
|
||||||
{
|
{
|
||||||
typedef typename ContainerType::reference (ContainerType::*backptr)();
|
m.add(fun([](ContainerType &container)->decltype(auto){
|
||||||
|
if (container.empty()) {
|
||||||
m.add(fun(static_cast<backptr>(&ContainerType::back)), "back");
|
throw std::range_error("Container empty");
|
||||||
|
} else {
|
||||||
|
return (container.back());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, "back");
|
||||||
|
m.add(fun([](const ContainerType &container)->decltype(auto){
|
||||||
|
if (container.empty()) {
|
||||||
|
throw std::range_error("Container empty");
|
||||||
|
} else {
|
||||||
|
return (container.back());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, "back");
|
||||||
|
|
||||||
|
|
||||||
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
||||||
@ -380,13 +395,29 @@ namespace chaiscript
|
|||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void front_insertion_sequence_type(const std::string &type, Module& m)
|
void front_insertion_sequence_type(const std::string &type, Module& m)
|
||||||
{
|
{
|
||||||
typedef typename ContainerType::reference (ContainerType::*front_ptr)();
|
|
||||||
typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const;
|
|
||||||
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference);
|
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference);
|
||||||
typedef void (ContainerType::*pop_ptr)();
|
typedef void (ContainerType::*pop_ptr)();
|
||||||
|
|
||||||
m.add(fun(static_cast<front_ptr>(&ContainerType::front)), "front");
|
m.add(fun([](ContainerType &container)->decltype(auto){
|
||||||
m.add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front");
|
if (container.empty()) {
|
||||||
|
throw std::range_error("Container empty");
|
||||||
|
} else {
|
||||||
|
return (container.front());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, "front");
|
||||||
|
|
||||||
|
m.add(fun([](const ContainerType &container)->decltype(auto){
|
||||||
|
if (container.empty()) {
|
||||||
|
throw std::range_error("Container empty");
|
||||||
|
} else {
|
||||||
|
return (container.front());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, "front");
|
||||||
|
|
||||||
|
|
||||||
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
|
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
|
||||||
[&]()->std::string{
|
[&]()->std::string{
|
||||||
@ -577,11 +608,27 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
m.add(user_type<VectorType>(), type);
|
m.add(user_type<VectorType>(), type);
|
||||||
|
|
||||||
typedef typename VectorType::reference (VectorType::*frontptr)();
|
m.add(fun([](VectorType &container)->decltype(auto){
|
||||||
typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const;
|
if (container.empty()) {
|
||||||
|
throw std::range_error("Container empty");
|
||||||
|
} else {
|
||||||
|
return (container.front());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, "front");
|
||||||
|
|
||||||
|
m.add(fun([](const VectorType &container)->decltype(auto){
|
||||||
|
if (container.empty()) {
|
||||||
|
throw std::range_error("Container empty");
|
||||||
|
} else {
|
||||||
|
return (container.front());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, "front");
|
||||||
|
|
||||||
|
|
||||||
m.add(fun(static_cast<frontptr>(&VectorType::front)), "front");
|
|
||||||
m.add(fun(static_cast<constfrontptr>(&VectorType::front)), "front");
|
|
||||||
|
|
||||||
|
|
||||||
back_insertion_sequence_type<VectorType>(type, m);
|
back_insertion_sequence_type<VectorType>(type, m);
|
||||||
@ -659,6 +706,8 @@ namespace chaiscript
|
|||||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of");
|
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of");
|
||||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of");
|
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of");
|
||||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of");
|
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of");
|
||||||
|
|
||||||
|
m.add(fun([](String *s, typename String::value_type c) -> decltype(auto) { return (*s += c); } ), "+=");
|
||||||
|
|
||||||
m.add(fun([](String *s) { s->clear(); } ), "clear");
|
m.add(fun([](String *s) { s->clear(); } ), "clear");
|
||||||
m.add(fun([](const String *s) { return s->empty(); } ), "empty");
|
m.add(fun([](const String *s) { return s->empty(); } ), "empty");
|
||||||
@ -686,7 +735,7 @@ namespace chaiscript
|
|||||||
m.add(user_type<FutureType>(), type);
|
m.add(user_type<FutureType>(), type);
|
||||||
|
|
||||||
m.add(fun([](const FutureType &t) { return t.valid(); }), "valid");
|
m.add(fun([](const FutureType &t) { return t.valid(); }), "valid");
|
||||||
m.add(fun(&FutureType::get), "get");
|
m.add(fun([](FutureType &t) { return t.get(); }), "get");
|
||||||
m.add(fun(&FutureType::wait), "wait");
|
m.add(fun(&FutureType::wait), "wait");
|
||||||
}
|
}
|
||||||
template<typename FutureType>
|
template<typename FutureType>
|
||||||
|
|||||||
@ -521,6 +521,10 @@ namespace chaiscript
|
|||||||
validate_boxed_number(bv);
|
validate_boxed_number(bv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Boxed_Value clone(const Boxed_Value &t_bv) {
|
||||||
|
return Boxed_Number(t_bv).get_as(t_bv.get_type_info()).bv;
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_floating_point(const Boxed_Value &t_bv)
|
static bool is_floating_point(const Boxed_Value &t_bv)
|
||||||
{
|
{
|
||||||
const Type_Info &inp_ = t_bv.get_type_info();
|
const Type_Info &inp_ = t_bv.get_type_info();
|
||||||
|
|||||||
@ -452,7 +452,7 @@ namespace chaiscript
|
|||||||
};
|
};
|
||||||
|
|
||||||
explicit Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser)
|
explicit Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser)
|
||||||
: m_stack_holder(this),
|
: m_stack_holder(),
|
||||||
m_parser(parser)
|
m_parser(parser)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -1142,25 +1142,17 @@ namespace chaiscript
|
|||||||
void dump_system() const
|
void dump_system() const
|
||||||
{
|
{
|
||||||
std::cout << "Registered Types: \n";
|
std::cout << "Registered Types: \n";
|
||||||
std::vector<std::pair<std::string, Type_Info> > types = get_types();
|
for (auto const &type: get_types())
|
||||||
for (std::vector<std::pair<std::string, Type_Info> >::const_iterator itr = types.begin();
|
|
||||||
itr != types.end();
|
|
||||||
++itr)
|
|
||||||
{
|
{
|
||||||
std::cout << itr->first << ": ";
|
std::cout << type.first << ": " << type.second.bare_name() << '\n';
|
||||||
std::cout << itr->second.bare_name();
|
|
||||||
std::cout << '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << '\n';
|
std::cout << '\n';
|
||||||
std::vector<std::pair<std::string, Proxy_Function > > funcs = get_functions();
|
|
||||||
|
|
||||||
std::cout << "Functions: \n";
|
std::cout << "Functions: \n";
|
||||||
for (std::vector<std::pair<std::string, Proxy_Function > >::const_iterator itr = funcs.begin();
|
for (auto const &func: get_functions())
|
||||||
itr != funcs.end();
|
|
||||||
++itr)
|
|
||||||
{
|
{
|
||||||
dump_function(*itr);
|
dump_function(func);
|
||||||
}
|
}
|
||||||
std::cout << '\n';
|
std::cout << '\n';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -181,9 +181,9 @@ namespace chaiscript
|
|||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<const Ret>
|
struct Handle_Return<const Ret>
|
||||||
{
|
{
|
||||||
static Boxed_Value handle(const Ret &r)
|
static Boxed_Value handle(Ret r)
|
||||||
{
|
{
|
||||||
return Boxed_Value(std::cref(r));
|
return Boxed_Value(std::move(r));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ namespace chaiscript
|
|||||||
class Boxed_Number;
|
class Boxed_Number;
|
||||||
struct AST_Node;
|
struct AST_Node;
|
||||||
|
|
||||||
typedef std::shared_ptr<AST_Node> AST_NodePtr;
|
typedef std::unique_ptr<AST_Node> AST_NodePtr;
|
||||||
|
|
||||||
namespace dispatch
|
namespace dispatch
|
||||||
{
|
{
|
||||||
@ -346,14 +346,15 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Dynamic_Proxy_Function(
|
Dynamic_Proxy_Function(
|
||||||
int t_arity=-1,
|
const int t_arity,
|
||||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
std::shared_ptr<AST_Node> t_parsenode,
|
||||||
Param_Types t_param_types = Param_Types(),
|
Param_Types t_param_types = Param_Types(),
|
||||||
Proxy_Function t_guard = Proxy_Function())
|
Proxy_Function t_guard = Proxy_Function())
|
||||||
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
|
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
|
||||||
m_param_types(std::move(t_param_types)),
|
m_param_types(std::move(t_param_types)),
|
||||||
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
|
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
|
||||||
{
|
{
|
||||||
|
// assert(t_parsenode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -379,9 +380,17 @@ namespace chaiscript
|
|||||||
return m_guard;
|
return m_guard;
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_NodePtr get_parse_tree() const
|
bool has_parse_tree() const {
|
||||||
|
return static_cast<bool>(m_parsenode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AST_Node &get_parse_tree() const
|
||||||
{
|
{
|
||||||
return m_parsenode;
|
if (m_parsenode) {
|
||||||
|
return *m_parsenode;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Dynamic_Proxy_Function does not have parse_tree");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -445,7 +454,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Proxy_Function m_guard;
|
Proxy_Function m_guard;
|
||||||
AST_NodePtr m_parsenode;
|
std::shared_ptr<AST_Node> m_parsenode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -457,7 +466,7 @@ namespace chaiscript
|
|||||||
Dynamic_Proxy_Function_Impl(
|
Dynamic_Proxy_Function_Impl(
|
||||||
Callable t_f,
|
Callable t_f,
|
||||||
int t_arity=-1,
|
int t_arity=-1,
|
||||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
std::shared_ptr<AST_Node> t_parsenode = AST_NodePtr(),
|
||||||
Param_Types t_param_types = Param_Types(),
|
Param_Types t_param_types = Param_Types(),
|
||||||
Proxy_Function t_guard = Proxy_Function())
|
Proxy_Function t_guard = Proxy_Function())
|
||||||
: Dynamic_Proxy_Function(
|
: Dynamic_Proxy_Function(
|
||||||
|
|||||||
@ -48,6 +48,7 @@ namespace chaiscript
|
|||||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Ret, typename ... Param>
|
template<typename Ret, typename ... Param>
|
||||||
Proxy_Function fun(Ret (*func)(Param...))
|
Proxy_Function fun(Ret (*func)(Param...))
|
||||||
{
|
{
|
||||||
@ -77,13 +78,45 @@ namespace chaiscript
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T, typename Class /*, typename = typename std::enable_if<std::is_member_object_pointer<T>::value>::type*/>
|
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*/ )
|
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));
|
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 __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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -338,9 +338,7 @@ namespace chaiscript
|
|||||||
: m_mutex(),
|
: m_mutex(),
|
||||||
m_conversions(),
|
m_conversions(),
|
||||||
m_convertableTypes(),
|
m_convertableTypes(),
|
||||||
m_num_types(0),
|
m_num_types(0)
|
||||||
m_thread_cache(this),
|
|
||||||
m_conversion_saves(this)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -62,7 +62,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
|
|
||||||
/// Types of AST nodes available to the parser and eval
|
/// Types of AST nodes available to the parser and eval
|
||||||
enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_Decl,
|
enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_Decl, Assign_Decl,
|
||||||
Array_Call, Dot_Access,
|
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,
|
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,
|
Inline_Range, Try, Catch, Finally, Method, Attr_Decl,
|
||||||
@ -77,7 +77,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
/// Helper lookup to get the name of each node type
|
/// Helper lookup to get the name of each node type
|
||||||
inline const char *ast_node_type_to_string(AST_Node_Type ast_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",
|
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",
|
"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",
|
"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",
|
"Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
|
||||||
@ -124,8 +124,10 @@ namespace chaiscript
|
|||||||
|
|
||||||
|
|
||||||
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
|
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
|
||||||
typedef std::shared_ptr<AST_Node> AST_NodePtr;
|
typedef std::unique_ptr<AST_Node> AST_NodePtr;
|
||||||
typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const;
|
typedef std::unique_ptr<const AST_Node> AST_NodePtr_Const;
|
||||||
|
|
||||||
|
struct AST_Node_Trace;
|
||||||
|
|
||||||
|
|
||||||
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
|
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
|
||||||
@ -168,7 +170,7 @@ namespace chaiscript
|
|||||||
File_Position start_position;
|
File_Position start_position;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string detail;
|
std::string detail;
|
||||||
std::vector<AST_NodePtr_Const> call_stack;
|
std::vector<AST_Node_Trace> call_stack;
|
||||||
|
|
||||||
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
|
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
|
||||||
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
||||||
@ -228,26 +230,26 @@ namespace chaiscript
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static AST_Node_Type id(const T& t)
|
static AST_Node_Type id(const T& t)
|
||||||
{
|
{
|
||||||
return t->identifier;
|
return t.identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static std::string pretty(const T& t)
|
static std::string pretty(const T& t)
|
||||||
{
|
{
|
||||||
return t->pretty_print();
|
return t.pretty_print();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static const std::string &fname(const T& t)
|
static const std::string &fname(const T& t)
|
||||||
{
|
{
|
||||||
return t->filename();
|
return t.filename();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static std::string startpos(const T& t)
|
static std::string startpos(const T& t)
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << t->start().line << ", " << t->start().column;
|
oss << t.start().line << ", " << t.start().column;
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +262,7 @@ namespace chaiscript
|
|||||||
bool t_dot_notation,
|
bool t_dot_notation,
|
||||||
const chaiscript::detail::Dispatch_Engine &t_ss)
|
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||||
{
|
{
|
||||||
|
assert(t_func);
|
||||||
int arity = t_func->get_arity();
|
int arity = t_func->get_arity();
|
||||||
std::vector<Type_Info> types = t_func->get_param_types();
|
std::vector<Type_Info> types = t_func->get_param_types();
|
||||||
|
|
||||||
@ -308,20 +311,20 @@ namespace chaiscript
|
|||||||
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
|
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
|
||||||
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
|
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
|
||||||
|
|
||||||
if (dynfun)
|
if (dynfun && dynfun->has_parse_tree())
|
||||||
{
|
{
|
||||||
Proxy_Function f = dynfun->get_guard();
|
Proxy_Function f = dynfun->get_guard();
|
||||||
|
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
|
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
|
||||||
if (dynfunguard)
|
if (dynfunguard && dynfunguard->has_parse_tree())
|
||||||
{
|
{
|
||||||
retval += " : " + format_guard(dynfunguard->get_parse_tree());
|
retval += " : " + format_guard(dynfunguard->get_parse_tree());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
retval += "\n Defined at " + format_location(dynfun->get_parse_tree());
|
retval += "\n Defined at " + format_location(dynfun->get_parse_tree());
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@ -330,20 +333,15 @@ namespace chaiscript
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static std::string format_guard(const T &t)
|
static std::string format_guard(const T &t)
|
||||||
{
|
{
|
||||||
return t->pretty_print();
|
return t.pretty_print();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static std::string format_location(const T &t)
|
static std::string format_location(const T &t)
|
||||||
{
|
{
|
||||||
if (t) {
|
std::ostringstream oss;
|
||||||
std::ostringstream oss;
|
oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")";
|
||||||
oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")";
|
return oss.str();
|
||||||
return oss.str();
|
|
||||||
} else {
|
|
||||||
return "(internal)";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
||||||
@ -353,6 +351,7 @@ namespace chaiscript
|
|||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
if (t_functions.size() == 1)
|
if (t_functions.size() == 1)
|
||||||
{
|
{
|
||||||
|
assert(t_functions[0]);
|
||||||
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
|
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
|
||||||
} else {
|
} else {
|
||||||
ss << " " << t_functions.size() << " overloads available:\n";
|
ss << " " << t_functions.size() << " overloads available:\n";
|
||||||
@ -492,7 +491,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
|
|
||||||
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
||||||
struct AST_Node : std::enable_shared_from_this<AST_Node> {
|
struct AST_Node {
|
||||||
public:
|
public:
|
||||||
const AST_Node_Type identifier;
|
const AST_Node_Type identifier;
|
||||||
const std::string text;
|
const std::string text;
|
||||||
@ -516,14 +515,14 @@ namespace chaiscript
|
|||||||
|
|
||||||
oss << text;
|
oss << text;
|
||||||
|
|
||||||
for (auto & elem : this->get_children()) {
|
for (auto & elem : get_children()) {
|
||||||
oss << elem->pretty_print() << ' ';
|
oss << elem.get().pretty_print() << ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<AST_NodePtr> get_children() const = 0;
|
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;
|
virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
|
||||||
|
|
||||||
|
|
||||||
@ -534,8 +533,8 @@ namespace chaiscript
|
|||||||
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
|
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
|
||||||
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
|
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
|
||||||
|
|
||||||
for (auto & elem : this->get_children()) {
|
for (auto & elem : get_children()) {
|
||||||
oss << elem->to_string(t_prepend + " ");
|
oss << elem.get().to_string(t_prepend + " ");
|
||||||
}
|
}
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
@ -568,12 +567,60 @@ namespace chaiscript
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 File_Position &start() const {
|
||||||
|
return location.start;
|
||||||
|
}
|
||||||
|
|
||||||
|
const File_Position &end() const {
|
||||||
|
return location.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string pretty_print() const
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
|
||||||
|
oss << text;
|
||||||
|
|
||||||
|
for (const auto & elem : children) {
|
||||||
|
oss << elem.pretty_print() << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AST_Node_Trace> get_children(const AST_Node &node)
|
||||||
|
{
|
||||||
|
const auto node_children = node.get_children();
|
||||||
|
return std::vector<AST_Node_Trace>(node_children.begin(), node_children.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_Node_Trace(const AST_Node &node)
|
||||||
|
: identifier(node.identifier), text(node.text),
|
||||||
|
location(node.location), children(get_children(node))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<AST_Node_Trace> children;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
namespace parser {
|
namespace parser {
|
||||||
class ChaiScript_Parser_Base
|
class ChaiScript_Parser_Base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
|
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
|
||||||
virtual void debug_print(AST_NodePtr t, std::string prepend = "") const = 0;
|
virtual void debug_print(const AST_Node &t, std::string prepend = "") const = 0;
|
||||||
virtual void *get_tracer_ptr() = 0;
|
virtual void *get_tracer_ptr() = 0;
|
||||||
virtual ~ChaiScript_Parser_Base() = default;
|
virtual ~ChaiScript_Parser_Base() = default;
|
||||||
ChaiScript_Parser_Base() = default;
|
ChaiScript_Parser_Base() = default;
|
||||||
|
|||||||
@ -36,12 +36,13 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CHAISCRIPT_NO_DYNLOAD)
|
||||||
#ifdef CHAISCRIPT_WINDOWS
|
#include "chaiscript_unknown.hpp"
|
||||||
|
#elif defined(CHAISCRIPT_WINDOWS)
|
||||||
#include "chaiscript_windows.hpp"
|
#include "chaiscript_windows.hpp"
|
||||||
#elif _POSIX_VERSION
|
#elif _POSIX_VERSION
|
||||||
#include "chaiscript_posix.hpp"
|
#include "chaiscript_posix.hpp"
|
||||||
@ -54,6 +55,8 @@
|
|||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript
|
||||||
{
|
{
|
||||||
|
/// Namespace alias to provide cleaner and more explicit syntax to users.
|
||||||
|
using Namespace = dispatch::Dynamic_Object;
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
@ -78,6 +81,8 @@ namespace chaiscript
|
|||||||
|
|
||||||
chaiscript::detail::Dispatch_Engine m_engine;
|
chaiscript::detail::Dispatch_Engine m_engine;
|
||||||
|
|
||||||
|
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
|
/// 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)
|
||||||
{
|
{
|
||||||
@ -185,7 +190,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
|
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
|
||||||
m_engine.add(fun([this](const AST_NodePtr &t_ast){ return eval(t_ast); }), "eval");
|
m_engine.add(fun([this](const AST_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, 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){ return parse(t_str); }), "parse");
|
||||||
@ -194,6 +199,9 @@ namespace chaiscript
|
|||||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
|
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
|
||||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
|
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
|
||||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -242,7 +250,7 @@ namespace chaiscript
|
|||||||
m_parser(std::move(parser)),
|
m_parser(std::move(parser)),
|
||||||
m_engine(*m_parser)
|
m_engine(*m_parser)
|
||||||
{
|
{
|
||||||
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
#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
|
// If on Unix, add the path of the current executable to the module search path
|
||||||
// as windows would do
|
// as windows would do
|
||||||
|
|
||||||
@ -278,6 +286,7 @@ namespace chaiscript
|
|||||||
build_eval_system(t_lib, t_opts);
|
build_eval_system(t_lib, t_opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_NO_DYNLOAD
|
||||||
/// \brief Constructor for ChaiScript.
|
/// \brief Constructor for ChaiScript.
|
||||||
///
|
///
|
||||||
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
|
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
|
||||||
@ -307,16 +316,22 @@ namespace chaiscript
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else // CHAISCRIPT_NO_DYNLOAD
|
||||||
|
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
|
||||||
|
std::vector<std::string> t_module_paths = {},
|
||||||
|
std::vector<std::string> t_use_paths = {},
|
||||||
|
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) = delete;
|
||||||
|
#endif
|
||||||
|
|
||||||
parser::ChaiScript_Parser_Base &get_parser()
|
parser::ChaiScript_Parser_Base &get_parser()
|
||||||
{
|
{
|
||||||
return *m_parser;
|
return *m_parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Boxed_Value eval(const AST_NodePtr &t_ast)
|
const Boxed_Value eval(const AST_Node &t_ast)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return t_ast->eval(chaiscript::detail::Dispatch_State(m_engine));
|
return t_ast.eval(chaiscript::detail::Dispatch_State(m_engine));
|
||||||
} catch (const exception::eval_error &t_ee) {
|
} catch (const exception::eval_error &t_ee) {
|
||||||
throw Boxed_Value(t_ee);
|
throw Boxed_Value(t_ee);
|
||||||
}
|
}
|
||||||
@ -324,9 +339,9 @@ namespace chaiscript
|
|||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
const auto ast = m_parser->parse(t_input, "PARSE");
|
auto ast = m_parser->parse(t_input, "PARSE");
|
||||||
if (t_debug_print) {
|
if (t_debug_print) {
|
||||||
m_parser->debug_print(ast);
|
m_parser->debug_print(*ast);
|
||||||
}
|
}
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
@ -548,6 +563,10 @@ namespace chaiscript
|
|||||||
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
|
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
|
||||||
std::string load_module(const std::string &t_module_name)
|
std::string load_module(const std::string &t_module_name)
|
||||||
{
|
{
|
||||||
|
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||||
|
(void)t_module_name; // -Wunused-parameter
|
||||||
|
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
|
||||||
|
#else
|
||||||
std::vector<exception::load_module_error> errors;
|
std::vector<exception::load_module_error> errors;
|
||||||
std::string version_stripped_name = t_module_name;
|
std::string version_stripped_name = t_module_name;
|
||||||
size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
|
size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
|
||||||
@ -581,6 +600,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw chaiscript::exception::load_module_error(t_module_name, errors);
|
throw chaiscript::exception::load_module_error(t_module_name, errors);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Load a binary module from a dynamic library. Works on platforms that support
|
/// \brief Load a binary module from a dynamic library. Works on platforms that support
|
||||||
@ -690,6 +710,41 @@ namespace chaiscript
|
|||||||
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
|
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
|
||||||
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler));
|
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \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)
|
||||||
|
{
|
||||||
|
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)) {
|
||||||
|
m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name);
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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 {
|
||||||
|
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,13 +47,13 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
template<typename T> struct AST_Node_Impl;
|
template<typename T> struct AST_Node_Impl;
|
||||||
|
|
||||||
template<typename T> using AST_Node_Impl_Ptr = typename std::shared_ptr<AST_Node_Impl<T>>;
|
template<typename T> using AST_Node_Impl_Ptr = typename std::unique_ptr<AST_Node_Impl<T>>;
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
/// Helper function that will set up the scope around a function call, including handling the named function parameters
|
/// Helper function that will set up the scope around a function call, including handling the named function parameters
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl_Ptr<T> &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr, bool has_this_capture = false) {
|
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl<T> &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr, bool has_this_capture = false) {
|
||||||
chaiscript::detail::Dispatch_State state(t_ss);
|
chaiscript::detail::Dispatch_State state(t_ss);
|
||||||
|
|
||||||
const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
|
const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
|
||||||
@ -83,11 +83,28 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return t_node->eval(state);
|
return t_node.eval(state);
|
||||||
} catch (detail::Return_Value &rv) {
|
} catch (detail::Return_Value &rv) {
|
||||||
return std::move(rv.retval);
|
return std::move(rv.retval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Boxed_Value clone_if_necessary(Boxed_Value incoming, std::atomic_uint_fast32_t &t_loc, const chaiscript::detail::Dispatch_State &t_ss)
|
||||||
|
{
|
||||||
|
if (!incoming.is_return_value())
|
||||||
|
{
|
||||||
|
if (incoming.get_type_info().is_arithmetic()) {
|
||||||
|
return Boxed_Number::clone(incoming);
|
||||||
|
} else if (incoming.get_type_info().bare_equal_type_info(typeid(bool))) {
|
||||||
|
return Boxed_Value(*static_cast<const bool*>(incoming.get_const_ptr()));
|
||||||
|
} else {
|
||||||
|
return t_ss->call_function("clone", t_loc, {incoming}, t_ss.conversions());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
incoming.reset_return_value();
|
||||||
|
return incoming;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -106,8 +123,14 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<AST_NodePtr> get_children() const final {
|
std::vector<std::reference_wrapper<AST_Node>> get_children() const final {
|
||||||
return {children.begin(), children.end()};
|
std::vector<std::reference_wrapper<AST_Node>> retval;
|
||||||
|
retval.reserve(children.size());
|
||||||
|
for (auto &&child : children) {
|
||||||
|
retval.emplace_back(*child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const final
|
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const final
|
||||||
@ -116,7 +139,7 @@ namespace chaiscript
|
|||||||
T::trace(t_e, this);
|
T::trace(t_e, this);
|
||||||
return eval_internal(t_e);
|
return eval_internal(t_e);
|
||||||
} catch (exception::eval_error &ee) {
|
} catch (exception::eval_error &ee) {
|
||||||
ee.call_stack.push_back(shared_from_this());
|
ee.call_stack.push_back(*this);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,7 +305,9 @@ namespace chaiscript
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct Fun_Call_AST_Node : AST_Node_Impl<T> {
|
struct Fun_Call_AST_Node : AST_Node_Impl<T> {
|
||||||
Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
||||||
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { }
|
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) {
|
||||||
|
assert(!this->children.empty());
|
||||||
|
}
|
||||||
|
|
||||||
template<bool Save_Params>
|
template<bool Save_Params>
|
||||||
Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const
|
Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const
|
||||||
@ -302,15 +327,17 @@ namespace chaiscript
|
|||||||
|
|
||||||
Boxed_Value fn(this->children[0]->eval(t_ss));
|
Boxed_Value fn(this->children[0]->eval(t_ss));
|
||||||
|
|
||||||
|
using ConstFunctionTypePtr = const dispatch::Proxy_Function_Base *;
|
||||||
try {
|
try {
|
||||||
return (*t_ss->boxed_cast<const dispatch::Proxy_Function_Base *>(fn))(params, t_ss.conversions());
|
return (*t_ss->boxed_cast<ConstFunctionTypePtr>(fn))(params, t_ss.conversions());
|
||||||
}
|
}
|
||||||
catch(const exception::dispatch_error &e){
|
catch(const exception::dispatch_error &e){
|
||||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
|
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
|
||||||
}
|
}
|
||||||
catch(const exception::bad_boxed_cast &){
|
catch(const exception::bad_boxed_cast &){
|
||||||
try {
|
try {
|
||||||
Const_Proxy_Function f = t_ss->boxed_cast<const Const_Proxy_Function &>(fn);
|
using ConstFunctionTypeRef = const Const_Proxy_Function &;
|
||||||
|
Const_Proxy_Function f = t_ss->boxed_cast<ConstFunctionTypeRef>(fn);
|
||||||
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
||||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss);
|
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss);
|
||||||
} catch (const exception::bad_boxed_cast &) {
|
} catch (const exception::bad_boxed_cast &) {
|
||||||
@ -364,44 +391,44 @@ namespace chaiscript
|
|||||||
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
|
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
|
||||||
|
|
||||||
|
|
||||||
static std::string get_arg_name(const AST_Node_Impl_Ptr<T> &t_node) {
|
static std::string get_arg_name(const AST_Node_Impl<T> &t_node) {
|
||||||
if (t_node->children.empty())
|
if (t_node.children.empty())
|
||||||
{
|
{
|
||||||
return t_node->text;
|
return t_node.text;
|
||||||
} else if (t_node->children.size() == 1) {
|
} else if (t_node.children.size() == 1) {
|
||||||
return t_node->children[0]->text;
|
return t_node.children[0]->text;
|
||||||
} else {
|
} else {
|
||||||
return t_node->children[1]->text;
|
return t_node.children[1]->text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::string> get_arg_names(const AST_Node_Impl_Ptr<T> &t_node) {
|
static std::vector<std::string> get_arg_names(const AST_Node_Impl<T> &t_node) {
|
||||||
std::vector<std::string> retval;
|
std::vector<std::string> retval;
|
||||||
|
|
||||||
for (const auto &node : t_node->children)
|
for (const auto &node : t_node.children)
|
||||||
{
|
{
|
||||||
retval.push_back(get_arg_name(node));
|
retval.push_back(get_arg_name(*node));
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<std::string, Type_Info> get_arg_type(const AST_Node_Impl_Ptr<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss)
|
static std::pair<std::string, Type_Info> get_arg_type(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss)
|
||||||
{
|
{
|
||||||
if (t_node->children.size() < 2)
|
if (t_node.children.size() < 2)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
} else {
|
} else {
|
||||||
return {t_node->children[0]->text, t_ss->get_type(t_node->children[0]->text, false)};
|
return {t_node.children[0]->text, t_ss->get_type(t_node.children[0]->text, false)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static dispatch::Param_Types get_arg_types(const AST_Node_Impl_Ptr<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss) {
|
static dispatch::Param_Types get_arg_types(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss) {
|
||||||
std::vector<std::pair<std::string, Type_Info>> retval;
|
std::vector<std::pair<std::string, Type_Info>> retval;
|
||||||
|
|
||||||
for (const auto &child : t_node->children)
|
for (const auto &child : t_node.children)
|
||||||
{
|
{
|
||||||
retval.push_back(get_arg_type(child, t_ss));
|
retval.push_back(get_arg_type(*child, t_ss));
|
||||||
}
|
}
|
||||||
|
|
||||||
return dispatch::Param_Types(std::move(retval));
|
return dispatch::Param_Types(std::move(retval));
|
||||||
@ -451,11 +478,7 @@ namespace chaiscript
|
|||||||
lhs.reset_return_value();
|
lhs.reset_return_value();
|
||||||
return rhs;
|
return rhs;
|
||||||
} else {
|
} else {
|
||||||
if (!rhs.is_return_value())
|
rhs = detail::clone_if_necessary(std::move(rhs), m_clone_loc, t_ss);
|
||||||
{
|
|
||||||
rhs = t_ss->call_function("clone", m_clone_loc, {rhs}, t_ss.conversions());
|
|
||||||
}
|
|
||||||
rhs.reset_return_value();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,6 +557,27 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Assign_Decl_AST_Node final : AST_Node_Impl<T> {
|
||||||
|
Assign_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
||||||
|
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Assign_Decl, std::move(t_loc), std::move(t_children)) { }
|
||||||
|
|
||||||
|
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||||
|
const std::string &idname = this->children[0]->text;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Boxed_Value bv(detail::clone_if_necessary(this->children[1]->eval(t_ss), m_loc, t_ss));
|
||||||
|
bv.reset_return_value();
|
||||||
|
t_ss.add_object(idname, bv);
|
||||||
|
return bv;
|
||||||
|
} catch (const exception::name_conflict_error &e) {
|
||||||
|
throw exception::eval_error("Variable redefined '" + e.name() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Array_Call_AST_Node final : AST_Node_Impl<T> {
|
struct Array_Call_AST_Node final : AST_Node_Impl<T> {
|
||||||
@ -621,9 +665,15 @@ namespace chaiscript
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct Lambda_AST_Node final : AST_Node_Impl<T> {
|
struct Lambda_AST_Node final : AST_Node_Impl<T> {
|
||||||
Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
||||||
AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Lambda, std::move(t_loc), std::move(t_children)),
|
AST_Node_Impl<T>(t_ast_node_text,
|
||||||
m_param_names(Arg_List_AST_Node<T>::get_arg_names(this->children[1])),
|
AST_Node_Type::Lambda,
|
||||||
m_this_capture(has_this_capture(this->children[0]->children))
|
std::move(t_loc),
|
||||||
|
std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
|
||||||
|
std::make_move_iterator(std::prev(t_children.end())))
|
||||||
|
),
|
||||||
|
m_param_names(Arg_List_AST_Node<T>::get_arg_names(*this->children[1])),
|
||||||
|
m_this_capture(has_this_capture(this->children[0]->children)),
|
||||||
|
m_lambda_node(std::move(t_children.back()))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||||
@ -637,18 +687,18 @@ namespace chaiscript
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
const auto numparams = this->children[1]->children.size();
|
const auto numparams = this->children[1]->children.size();
|
||||||
const auto param_types = Arg_List_AST_Node<T>::get_arg_types(this->children[1], t_ss);
|
const auto param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss);
|
||||||
|
|
||||||
const auto &lambda_node = this->children.back();
|
|
||||||
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
||||||
|
|
||||||
return Boxed_Value(
|
return Boxed_Value(
|
||||||
dispatch::make_dynamic_proxy_function(
|
dispatch::make_dynamic_proxy_function(
|
||||||
[engine, lambda_node, param_names = this->m_param_names, captures, this_capture = this->m_this_capture](const std::vector<Boxed_Value> &t_params)
|
[engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures,
|
||||||
|
this_capture = this->m_this_capture] (const std::vector<Boxed_Value> &t_params)
|
||||||
{
|
{
|
||||||
return detail::eval_function(engine, lambda_node, param_names, t_params, &captures, this_capture);
|
return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), lambda_node, param_types
|
static_cast<int>(numparams), m_lambda_node, param_types
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -664,7 +714,7 @@ namespace chaiscript
|
|||||||
private:
|
private:
|
||||||
const std::vector<std::string> m_param_names;
|
const std::vector<std::string> m_param_names;
|
||||||
const bool m_this_capture = false;
|
const bool m_this_capture = false;
|
||||||
|
const std::shared_ptr<AST_Node_Impl<T>> m_lambda_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -699,55 +749,83 @@ namespace chaiscript
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Def_AST_Node final : AST_Node_Impl<T> {
|
struct Def_AST_Node final : AST_Node_Impl<T> {
|
||||||
|
|
||||||
|
std::shared_ptr<AST_Node_Impl<T>> m_body_node;
|
||||||
|
std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
|
||||||
|
|
||||||
Def_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
Def_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
||||||
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc), std::move(t_children)) { }
|
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc),
|
||||||
|
std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
|
||||||
|
std::make_move_iterator(std::prev(t_children.end(), has_guard(t_children, 1)?2:1)))
|
||||||
|
),
|
||||||
|
// This apparent use after move is safe because we are only moving out the specific elements we need
|
||||||
|
// on each operation.
|
||||||
|
m_body_node(get_body_node(std::move(t_children))),
|
||||||
|
m_guard_node(get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2))
|
||||||
|
|
||||||
|
{ }
|
||||||
|
|
||||||
|
static std::shared_ptr<AST_Node_Impl<T>> get_guard_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec, bool has_guard)
|
||||||
|
{
|
||||||
|
if (has_guard) {
|
||||||
|
return std::move(*std::prev(vec.end(), 2));
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<AST_Node_Impl<T>> get_body_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec)
|
||||||
|
{
|
||||||
|
return std::move(vec.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool has_guard(const std::vector<AST_Node_Impl_Ptr<T>> &t_children, const std::size_t offset)
|
||||||
|
{
|
||||||
|
if ((t_children.size() > 2 + offset) && (t_children[1+offset]->identifier == AST_Node_Type::Arg_List)) {
|
||||||
|
if (t_children.size() > 3 + offset) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (t_children.size() > 2 + offset) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
|
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
|
||||||
std::vector<std::string> t_param_names;
|
std::vector<std::string> t_param_names;
|
||||||
size_t numparams = 0;
|
size_t numparams = 0;
|
||||||
AST_Node_Impl_Ptr<T> guardnode;
|
|
||||||
|
|
||||||
dispatch::Param_Types param_types;
|
dispatch::Param_Types param_types;
|
||||||
|
|
||||||
if ((this->children.size() > 2) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
|
if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
|
||||||
numparams = this->children[1]->children.size();
|
numparams = this->children[1]->children.size();
|
||||||
t_param_names = Arg_List_AST_Node<T>::get_arg_names(this->children[1]);
|
t_param_names = Arg_List_AST_Node<T>::get_arg_names(*this->children[1]);
|
||||||
param_types = Arg_List_AST_Node<T>::get_arg_types(this->children[1], t_ss);
|
param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss);
|
||||||
|
|
||||||
if (this->children.size() > 3) {
|
|
||||||
guardnode = this->children[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//no parameters
|
|
||||||
numparams = 0;
|
|
||||||
|
|
||||||
if (this->children.size() > 2) {
|
|
||||||
guardnode = this->children[1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
||||||
std::shared_ptr<dispatch::Proxy_Function_Base> guard;
|
std::shared_ptr<dispatch::Proxy_Function_Base> guard;
|
||||||
if (guardnode) {
|
if (m_guard_node) {
|
||||||
guard = dispatch::make_dynamic_proxy_function(
|
guard = dispatch::make_dynamic_proxy_function(
|
||||||
[engine, guardnode, t_param_names](const std::vector<Boxed_Value> &t_params)
|
[engine, guardnode = m_guard_node, t_param_names](const std::vector<Boxed_Value> &t_params)
|
||||||
{
|
{
|
||||||
return detail::eval_function(engine, guardnode, t_param_names, t_params);
|
return detail::eval_function(engine, *guardnode, t_param_names, t_params);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), guardnode);
|
static_cast<int>(numparams), m_guard_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const std::string & l_function_name = this->children[0]->text;
|
const std::string & l_function_name = this->children[0]->text;
|
||||||
const auto & func_node = this->children.back();
|
|
||||||
t_ss->add(
|
t_ss->add(
|
||||||
dispatch::make_dynamic_proxy_function(
|
dispatch::make_dynamic_proxy_function(
|
||||||
[engine, guardnode, func_node, t_param_names](const std::vector<Boxed_Value> &t_params)
|
[engine, func_node = m_body_node, t_param_names](const std::vector<Boxed_Value> &t_params)
|
||||||
{
|
{
|
||||||
return detail::eval_function(engine, func_node, t_param_names, t_params);
|
return detail::eval_function(engine, *func_node, t_param_names, t_params);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), this->children.back(),
|
static_cast<int>(numparams), m_body_node,
|
||||||
param_types, guard), l_function_name);
|
param_types, guard), l_function_name);
|
||||||
} catch (const exception::name_conflict_error &e) {
|
} catch (const exception::name_conflict_error &e) {
|
||||||
throw exception::eval_error("Function redefined '" + e.name() + "'");
|
throw exception::eval_error("Function redefined '" + e.name() + "'");
|
||||||
@ -1016,12 +1094,7 @@ namespace chaiscript
|
|||||||
if (!this->children.empty()) {
|
if (!this->children.empty()) {
|
||||||
vec.reserve(this->children[0]->children.size());
|
vec.reserve(this->children[0]->children.size());
|
||||||
for (const auto &child : this->children[0]->children) {
|
for (const auto &child : this->children[0]->children) {
|
||||||
auto obj = child->eval(t_ss);
|
vec.push_back(detail::clone_if_necessary(child->eval(t_ss), m_loc, t_ss));
|
||||||
if (!obj.is_return_value()) {
|
|
||||||
vec.push_back(t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions()));
|
|
||||||
} else {
|
|
||||||
vec.push_back(std::move(obj));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return const_var(std::move(vec));
|
return const_var(std::move(vec));
|
||||||
@ -1046,12 +1119,8 @@ namespace chaiscript
|
|||||||
std::map<std::string, Boxed_Value> retval;
|
std::map<std::string, Boxed_Value> retval;
|
||||||
|
|
||||||
for (const auto &child : this->children[0]->children) {
|
for (const auto &child : this->children[0]->children) {
|
||||||
auto obj = child->children[1]->eval(t_ss);
|
retval.insert(std::make_pair(t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss)),
|
||||||
if (!obj.is_return_value()) {
|
detail::clone_if_necessary(child->children[1]->eval(t_ss), m_loc, t_ss)));
|
||||||
obj = t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions());
|
|
||||||
}
|
|
||||||
|
|
||||||
retval[t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return const_var(std::move(retval));
|
return const_var(std::move(retval));
|
||||||
@ -1230,32 +1299,32 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
for (size_t i = 1; i < end_point; ++i) {
|
for (size_t i = 1; i < end_point; ++i) {
|
||||||
chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss);
|
chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss);
|
||||||
AST_Node_Impl_Ptr<T> catch_block = this->children[i];
|
auto &catch_block = *this->children[i];
|
||||||
|
|
||||||
if (catch_block->children.size() == 1) {
|
if (catch_block.children.size() == 1) {
|
||||||
//No variable capture, no guards
|
//No variable capture, no guards
|
||||||
retval = catch_block->children[0]->eval(t_ss);
|
retval = catch_block.children[0]->eval(t_ss);
|
||||||
break;
|
break;
|
||||||
} else if (catch_block->children.size() == 2 || catch_block->children.size() == 3) {
|
} else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) {
|
||||||
const auto name = Arg_List_AST_Node<T>::get_arg_name(catch_block->children[0]);
|
const auto name = Arg_List_AST_Node<T>::get_arg_name(*catch_block.children[0]);
|
||||||
|
|
||||||
if (dispatch::Param_Types(
|
if (dispatch::Param_Types(
|
||||||
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(catch_block->children[0], t_ss)}
|
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(*catch_block.children[0], t_ss)}
|
||||||
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()).first)
|
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()).first)
|
||||||
{
|
{
|
||||||
t_ss.add_object(name, t_except);
|
t_ss.add_object(name, t_except);
|
||||||
|
|
||||||
if (catch_block->children.size() == 2) {
|
if (catch_block.children.size() == 2) {
|
||||||
//Variable capture, no guards
|
//Variable capture, no guards
|
||||||
retval = catch_block->children[1]->eval(t_ss);
|
retval = catch_block.children[1]->eval(t_ss);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (catch_block->children.size() == 3) {
|
else if (catch_block.children.size() == 3) {
|
||||||
//Variable capture, guards
|
//Variable capture, guards
|
||||||
|
|
||||||
bool guard = false;
|
bool guard = false;
|
||||||
try {
|
try {
|
||||||
guard = boxed_cast<bool>(catch_block->children[1]->eval(t_ss));
|
guard = boxed_cast<bool>(catch_block.children[1]->eval(t_ss));
|
||||||
} catch (const exception::bad_boxed_cast &) {
|
} catch (const exception::bad_boxed_cast &) {
|
||||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||||
this->children.back()->children[0]->eval(t_ss);
|
this->children.back()->children[0]->eval(t_ss);
|
||||||
@ -1263,7 +1332,7 @@ namespace chaiscript
|
|||||||
throw exception::eval_error("Guard condition not boolean");
|
throw exception::eval_error("Guard condition not boolean");
|
||||||
}
|
}
|
||||||
if (guard) {
|
if (guard) {
|
||||||
retval = catch_block->children[2]->eval(t_ss);
|
retval = catch_block.children[2]->eval(t_ss);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1335,8 +1404,18 @@ namespace chaiscript
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Method_AST_Node final : AST_Node_Impl<T> {
|
struct Method_AST_Node final : AST_Node_Impl<T> {
|
||||||
|
std::shared_ptr<AST_Node_Impl<T>> m_body_node;
|
||||||
|
std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
|
||||||
|
|
||||||
Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
||||||
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc), std::move(t_children)) { }
|
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc),
|
||||||
|
std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
|
||||||
|
std::make_move_iterator(std::prev(t_children.end(), Def_AST_Node<T>::has_guard(t_children, 1)?2:1)))
|
||||||
|
),
|
||||||
|
m_body_node(Def_AST_Node<T>::get_body_node(std::move(t_children))),
|
||||||
|
m_guard_node(Def_AST_Node<T>::get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
|
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
|
||||||
|
|
||||||
@ -1348,39 +1427,27 @@ namespace chaiscript
|
|||||||
std::vector<std::string> t_param_names{"this"};
|
std::vector<std::string> t_param_names{"this"};
|
||||||
dispatch::Param_Types param_types;
|
dispatch::Param_Types param_types;
|
||||||
|
|
||||||
if ((this->children.size() > 3)
|
if ((this->children.size() > 2)
|
||||||
&& (this->children[2]->identifier == AST_Node_Type::Arg_List)) {
|
&& (this->children[2]->identifier == AST_Node_Type::Arg_List)) {
|
||||||
auto args = Arg_List_AST_Node<T>::get_arg_names(this->children[2]);
|
auto args = Arg_List_AST_Node<T>::get_arg_names(*this->children[2]);
|
||||||
t_param_names.insert(t_param_names.end(), args.begin(), args.end());
|
t_param_names.insert(t_param_names.end(), args.begin(), args.end());
|
||||||
param_types = Arg_List_AST_Node<T>::get_arg_types(this->children[2], t_ss);
|
param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[2], t_ss);
|
||||||
|
|
||||||
if (this->children.size() > 4) {
|
|
||||||
guardnode = this->children[3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//no parameters
|
|
||||||
|
|
||||||
if (this->children.size() > 3) {
|
|
||||||
guardnode = this->children[2];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t numparams = t_param_names.size();
|
const size_t numparams = t_param_names.size();
|
||||||
|
|
||||||
std::shared_ptr<dispatch::Proxy_Function_Base> guard;
|
std::shared_ptr<dispatch::Proxy_Function_Base> guard;
|
||||||
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
||||||
if (guardnode) {
|
if (m_guard_node) {
|
||||||
guard = dispatch::make_dynamic_proxy_function(
|
guard = dispatch::make_dynamic_proxy_function(
|
||||||
[engine, t_param_names, guardnode](const std::vector<Boxed_Value> &t_params) {
|
[engine, t_param_names, guardnode = m_guard_node](const std::vector<Boxed_Value> &t_params) {
|
||||||
return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params);
|
return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), guardnode);
|
static_cast<int>(numparams), m_guard_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const std::string & function_name = this->children[1]->text;
|
const std::string & function_name = this->children[1]->text;
|
||||||
auto node = this->children.back();
|
|
||||||
|
|
||||||
if (function_name == class_name) {
|
if (function_name == class_name) {
|
||||||
param_types.push_front(class_name, Type_Info());
|
param_types.push_front(class_name, Type_Info());
|
||||||
@ -1388,10 +1455,10 @@ namespace chaiscript
|
|||||||
t_ss->add(
|
t_ss->add(
|
||||||
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
|
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
|
||||||
dispatch::make_dynamic_proxy_function(
|
dispatch::make_dynamic_proxy_function(
|
||||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
[engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) {
|
||||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
|
return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), node, param_types, guard
|
static_cast<int>(numparams), m_body_node, param_types, guard
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
function_name);
|
function_name);
|
||||||
@ -1402,12 +1469,13 @@ namespace chaiscript
|
|||||||
auto type = t_ss->get_type(class_name, false);
|
auto type = t_ss->get_type(class_name, false);
|
||||||
param_types.push_front(class_name, type);
|
param_types.push_front(class_name, type);
|
||||||
|
|
||||||
t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
t_ss->add(
|
||||||
|
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
||||||
dispatch::make_dynamic_proxy_function(
|
dispatch::make_dynamic_proxy_function(
|
||||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
[engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) {
|
||||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
|
return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), node, param_types, guard), type),
|
static_cast<int>(numparams), m_body_node, param_types, guard), type),
|
||||||
function_name);
|
function_name);
|
||||||
}
|
}
|
||||||
} catch (const exception::name_conflict_error &e) {
|
} catch (const exception::name_conflict_error &e) {
|
||||||
|
|||||||
@ -24,17 +24,26 @@ namespace chaiscript {
|
|||||||
|
|
||||||
template<typename Tracer>
|
template<typename Tracer>
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
|
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
|
||||||
(void)std::initializer_list<int>{ (p = static_cast<T&>(*this).optimize(p), 0)... };
|
(void)std::initializer_list<int>{ (p = static_cast<T&>(*this).optimize(std::move(p)), 0)... };
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto child_at(const eval::AST_Node_Impl_Ptr<T> &node, const size_t offset) {
|
eval::AST_Node_Impl<T> &child_at(eval::AST_Node_Impl<T> &node, const size_t offset) {
|
||||||
if (node->children[offset]->identifier == AST_Node_Type::Compiled) {
|
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
|
||||||
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node->children[offset]).m_original_node;
|
return *(dynamic_cast<eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
|
||||||
} else {
|
} else {
|
||||||
return node->children[offset];
|
return *node.children[offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) {
|
||||||
|
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -48,24 +57,24 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto child_count(const eval::AST_Node_Impl_Ptr<T> &node) {
|
auto child_count(const eval::AST_Node_Impl<T> &node) {
|
||||||
if (node->identifier == AST_Node_Type::Compiled) {
|
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 {
|
} else {
|
||||||
return node->children.size();
|
return node.children.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename Callable>
|
template<typename T, typename Callable>
|
||||||
auto make_compiled_node(const eval::AST_Node_Impl_Ptr<T> &original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable)
|
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_shared<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(original_node, std::move(children), std::move(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 {
|
struct Return {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &p)
|
auto optimize(eval::AST_Node_Impl_Ptr<T> p)
|
||||||
{
|
{
|
||||||
if ( (p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda)
|
if ( (p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda)
|
||||||
&& !p->children.empty())
|
&& !p->children.empty())
|
||||||
@ -75,7 +84,7 @@ namespace chaiscript {
|
|||||||
auto &block_last_child = last_child->children.back();
|
auto &block_last_child = last_child->children.back();
|
||||||
if (block_last_child->identifier == AST_Node_Type::Return) {
|
if (block_last_child->identifier == AST_Node_Type::Return) {
|
||||||
if (block_last_child->children.size() == 1) {
|
if (block_last_child->children.size() == 1) {
|
||||||
last_child->children.back() = block_last_child->children[0];
|
last_child->children.back() = std::move(block_last_child->children[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,9 +95,9 @@ namespace chaiscript {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool contains_var_decl_in_scope(const T &node)
|
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node)
|
||||||
{
|
{
|
||||||
if (node->identifier == AST_Node_Type::Var_Decl) {
|
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl || node.identifier == AST_Node_Type::Reference) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,8 +105,9 @@ namespace chaiscript {
|
|||||||
|
|
||||||
for (size_t i = 0; i < num; ++i) {
|
for (size_t i = 0; i < num; ++i) {
|
||||||
const auto &child = child_at(node, i);
|
const auto &child = child_at(node, i);
|
||||||
if (child->identifier != AST_Node_Type::Block
|
if (child.identifier != AST_Node_Type::Block
|
||||||
&& child->identifier != AST_Node_Type::For
|
&& child.identifier != AST_Node_Type::For
|
||||||
|
&& child.identifier != AST_Node_Type::Ranged_For
|
||||||
&& contains_var_decl_in_scope(child)) {
|
&& contains_var_decl_in_scope(child)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -108,15 +118,16 @@ namespace chaiscript {
|
|||||||
|
|
||||||
struct Block {
|
struct Block {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
||||||
if (node->identifier == AST_Node_Type::Block)
|
if (node->identifier == AST_Node_Type::Block)
|
||||||
{
|
{
|
||||||
if (!contains_var_decl_in_scope(node))
|
if (!contains_var_decl_in_scope(*node))
|
||||||
{
|
{
|
||||||
if (node->children.size() == 1) {
|
if (node->children.size() == 1) {
|
||||||
return node->children[0];
|
return std::move(node->children[0]);
|
||||||
} else {
|
} else {
|
||||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text, node->location, node->children);
|
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text, node->location,
|
||||||
|
std::move(node->children));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,7 +138,7 @@ namespace chaiscript {
|
|||||||
|
|
||||||
struct Dead_Code {
|
struct Dead_Code {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
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;
|
std::vector<size_t> keepers;
|
||||||
@ -135,10 +146,10 @@ namespace chaiscript {
|
|||||||
keepers.reserve(num_children);
|
keepers.reserve(num_children);
|
||||||
|
|
||||||
for (size_t i = 0; i < num_children; ++i) {
|
for (size_t i = 0; i < num_children; ++i) {
|
||||||
auto child = node->children[i];
|
const auto &child = *node->children[i];
|
||||||
if ( (child->identifier != AST_Node_Type::Id
|
if ( (child.identifier != AST_Node_Type::Id
|
||||||
&& child->identifier != AST_Node_Type::Constant
|
&& child.identifier != AST_Node_Type::Constant
|
||||||
&& child->identifier != AST_Node_Type::Noop)
|
&& child.identifier != AST_Node_Type::Noop)
|
||||||
|| i == num_children - 1) {
|
|| i == num_children - 1) {
|
||||||
keepers.push_back(i);
|
keepers.push_back(i);
|
||||||
}
|
}
|
||||||
@ -147,12 +158,16 @@ namespace chaiscript {
|
|||||||
if (keepers.size() == num_children) {
|
if (keepers.size() == num_children) {
|
||||||
return node;
|
return node;
|
||||||
} else {
|
} else {
|
||||||
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
|
const auto new_children = [&](){
|
||||||
for (const auto x : keepers)
|
std::vector<eval::AST_Node_Impl_Ptr<T>> retval;
|
||||||
{
|
for (const auto x : keepers)
|
||||||
new_children.push_back(node->children[x]);
|
{
|
||||||
}
|
retval.push_back(std::move(node->children[x]));
|
||||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Block_AST_Node<T>>(node->text, node->location, new_children);
|
}
|
||||||
|
return retval;
|
||||||
|
};
|
||||||
|
|
||||||
|
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Block_AST_Node<T>>(node->text, node->location, new_children());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return node;
|
return node;
|
||||||
@ -162,29 +177,30 @@ namespace chaiscript {
|
|||||||
|
|
||||||
struct Unused_Return {
|
struct Unused_Return {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
||||||
if ((node->identifier == AST_Node_Type::Block
|
if ((node->identifier == AST_Node_Type::Block
|
||||||
|| node->identifier == AST_Node_Type::Scopeless_Block)
|
|| node->identifier == AST_Node_Type::Scopeless_Block)
|
||||||
&& !node->children.empty())
|
&& !node->children.empty())
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < node->children.size()-1; ++i) {
|
for (size_t i = 0; i < node->children.size()-1; ++i) {
|
||||||
auto child = node->children[i];
|
auto child = node->children[i].get();
|
||||||
if (child->identifier == AST_Node_Type::Fun_Call) {
|
if (child->identifier == AST_Node_Type::Fun_Call) {
|
||||||
node->children[i] = chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(child->text, child->location, std::move(child->children));
|
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
|
} else if ((node->identifier == AST_Node_Type::For
|
||||||
|| node->identifier == AST_Node_Type::While)
|
|| node->identifier == AST_Node_Type::While)
|
||||||
&& child_count(node) > 0) {
|
&& child_count(*node) > 0) {
|
||||||
auto child = child_at(node, child_count(node) - 1);
|
auto &child = child_at(*node, child_count(*node) - 1);
|
||||||
if (child->identifier == AST_Node_Type::Block
|
if (child.identifier == AST_Node_Type::Block
|
||||||
|| child->identifier == AST_Node_Type::Scopeless_Block)
|
|| child.identifier == AST_Node_Type::Scopeless_Block)
|
||||||
{
|
{
|
||||||
auto num_sub_children = child_count(child);
|
auto num_sub_children = child_count(child);
|
||||||
for (size_t i = 0; i < num_sub_children; ++i) {
|
for (size_t i = 0; i < num_sub_children; ++i) {
|
||||||
auto sub_child = child_at(child, i);
|
auto &sub_child = child_at(child, i);
|
||||||
if (sub_child->identifier == AST_Node_Type::Fun_Call) {
|
if (sub_child.identifier == AST_Node_Type::Fun_Call) {
|
||||||
child->children[i] = chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(sub_child->text, sub_child->location, std::move(sub_child->children));
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,19 +209,40 @@ 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
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
|
||||||
|
new_children.push_back(std::move(node->children[0]->children[0]));
|
||||||
|
new_children.push_back(std::move(node->children[1]));
|
||||||
|
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Assign_Decl_AST_Node<T>>(node->text,
|
||||||
|
node->location, std::move(new_children) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct If {
|
struct If {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
||||||
if ((node->identifier == AST_Node_Type::If)
|
if ((node->identifier == AST_Node_Type::If)
|
||||||
&& node->children.size() >= 2
|
&& node->children.size() >= 2
|
||||||
&& node->children[0]->identifier == AST_Node_Type::Constant)
|
&& node->children[0]->identifier == AST_Node_Type::Constant)
|
||||||
{
|
{
|
||||||
const auto condition = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
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 (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
|
||||||
if (boxed_cast<bool>(condition)) {
|
if (boxed_cast<bool>(condition)) {
|
||||||
return node->children[1];
|
return std::move(node->children[1]);
|
||||||
} else if (node->children.size() == 3) {
|
} else if (node->children.size() == 3) {
|
||||||
return node->children[2];
|
return std::move(node->children[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,7 +253,7 @@ namespace chaiscript {
|
|||||||
|
|
||||||
struct Partial_Fold {
|
struct Partial_Fold {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
||||||
|
|
||||||
// Fold right side
|
// Fold right side
|
||||||
if (node->identifier == AST_Node_Type::Binary
|
if (node->identifier == AST_Node_Type::Binary
|
||||||
@ -228,9 +265,10 @@ namespace chaiscript {
|
|||||||
const auto &oper = node->text;
|
const auto &oper = node->text;
|
||||||
const auto parsed = Operators::to_operator(oper);
|
const auto parsed = Operators::to_operator(oper);
|
||||||
if (parsed != Operators::Opers::invalid) {
|
if (parsed != Operators::Opers::invalid) {
|
||||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
|
const auto rhs = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[1].get())->m_value;
|
||||||
if (rhs.get_type_info().is_arithmetic()) {
|
if (rhs.get_type_info().is_arithmetic()) {
|
||||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(node->text, node->location, node->children, rhs);
|
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 &) {
|
} catch (const std::exception &) {
|
||||||
@ -244,7 +282,7 @@ namespace chaiscript {
|
|||||||
|
|
||||||
struct Constant_Fold {
|
struct Constant_Fold {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
||||||
|
|
||||||
if (node->identifier == AST_Node_Type::Prefix
|
if (node->identifier == AST_Node_Type::Prefix
|
||||||
&& node->children.size() == 1
|
&& node->children.size() == 1
|
||||||
@ -253,14 +291,14 @@ namespace chaiscript {
|
|||||||
try {
|
try {
|
||||||
const auto &oper = node->text;
|
const auto &oper = node->text;
|
||||||
const auto parsed = Operators::to_operator(oper, true);
|
const auto parsed = Operators::to_operator(oper, true);
|
||||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> *>(node->children[0].get())->m_value;
|
||||||
const auto match = oper + node->children[0]->text;
|
const auto match = oper + node->children[0]->text;
|
||||||
|
|
||||||
if (parsed != Operators::Opers::invalid && parsed != Operators::Opers::bitwise_and && lhs.get_type_info().is_arithmetic()) {
|
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);
|
const auto val = Boxed_Number::do_oper(parsed, lhs);
|
||||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
|
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 == "!") {
|
} else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") {
|
||||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(!boxed_cast<bool>(lhs)));
|
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 &) {
|
} catch (const std::exception &) {
|
||||||
//failure to fold, that's OK
|
//failure to fold, that's OK
|
||||||
@ -271,8 +309,8 @@ namespace chaiscript {
|
|||||||
&& node->children[1]->identifier == AST_Node_Type::Constant)
|
&& node->children[1]->identifier == AST_Node_Type::Constant)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
|
||||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
|
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))) {
|
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 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] {
|
const auto val = [lhs_val = boxed_cast<bool>(lhs), rhs_val = boxed_cast<bool>(rhs), id = node->identifier] {
|
||||||
@ -280,7 +318,7 @@ namespace chaiscript {
|
|||||||
else { return Boxed_Value(lhs_val || rhs_val); }
|
else { return Boxed_Value(lhs_val || rhs_val); }
|
||||||
}();
|
}();
|
||||||
|
|
||||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
|
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 &) {
|
} catch (const std::exception &) {
|
||||||
//failure to fold, that's OK
|
//failure to fold, that's OK
|
||||||
@ -294,12 +332,12 @@ namespace chaiscript {
|
|||||||
const auto &oper = node->text;
|
const auto &oper = node->text;
|
||||||
const auto parsed = Operators::to_operator(oper);
|
const auto parsed = Operators::to_operator(oper);
|
||||||
if (parsed != Operators::Opers::invalid) {
|
if (parsed != Operators::Opers::invalid) {
|
||||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
|
||||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
|
const auto rhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]).m_value;
|
||||||
if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) {
|
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 val = Boxed_Number::do_oper(parsed, lhs, rhs);
|
||||||
const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
|
const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
|
||||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
|
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 &) {
|
} catch (const std::exception &) {
|
||||||
@ -312,13 +350,13 @@ namespace chaiscript {
|
|||||||
&& node->children[1]->children.size() == 1
|
&& node->children[1]->children.size() == 1
|
||||||
&& node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
|
&& node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
|
||||||
|
|
||||||
const auto arg = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1]->children[0])->m_value;
|
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()) {
|
if (arg.get_type_info().is_arithmetic()) {
|
||||||
const auto &fun_name = node->children[0]->text;
|
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 + ")";
|
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")";
|
||||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(val));
|
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(val));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fun_name == "double") {
|
if (fun_name == "double") {
|
||||||
@ -344,35 +382,36 @@ namespace chaiscript {
|
|||||||
|
|
||||||
struct For_Loop {
|
struct For_Loop {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &for_node) {
|
auto optimize(eval::AST_Node_Impl_Ptr<T> for_node) {
|
||||||
|
|
||||||
if (for_node->identifier != AST_Node_Type::For) {
|
if (for_node->identifier != AST_Node_Type::For) {
|
||||||
return for_node;
|
return for_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto eq_node = child_at(for_node, 0);
|
const auto &eq_node = child_at(*for_node, 0);
|
||||||
const auto binary_node = child_at(for_node, 1);
|
const auto &binary_node = child_at(*for_node, 1);
|
||||||
const auto prefix_node = child_at(for_node, 2);
|
const auto &prefix_node = child_at(*for_node, 2);
|
||||||
|
|
||||||
if (eq_node->identifier == AST_Node_Type::Equation
|
if (child_count(*for_node) == 4
|
||||||
|
&& eq_node.identifier == AST_Node_Type::Assign_Decl
|
||||||
&& child_count(eq_node) == 2
|
&& child_count(eq_node) == 2
|
||||||
&& child_at(eq_node, 0)->identifier == AST_Node_Type::Var_Decl
|
&& child_at(eq_node, 0).identifier == AST_Node_Type::Id
|
||||||
&& child_at(eq_node, 1)->identifier == AST_Node_Type::Constant
|
&& child_at(eq_node, 1).identifier == AST_Node_Type::Constant
|
||||||
&& binary_node->identifier == AST_Node_Type::Binary
|
&& binary_node.identifier == AST_Node_Type::Binary
|
||||||
&& binary_node->text == "<"
|
&& binary_node.text == "<"
|
||||||
&& child_count(binary_node) == 2
|
&& child_count(binary_node) == 2
|
||||||
&& child_at(binary_node, 0)->identifier == AST_Node_Type::Id
|
&& child_at(binary_node, 0).identifier == AST_Node_Type::Id
|
||||||
&& child_at(binary_node, 0)->text == child_at(child_at(eq_node,0), 0)->text
|
&& child_at(binary_node, 0).text == child_at(eq_node,0).text
|
||||||
&& child_at(binary_node, 1)->identifier == AST_Node_Type::Constant
|
&& child_at(binary_node, 1).identifier == AST_Node_Type::Constant
|
||||||
&& prefix_node->identifier == AST_Node_Type::Prefix
|
&& prefix_node.identifier == AST_Node_Type::Prefix
|
||||||
&& prefix_node->text == "++"
|
&& prefix_node.text == "++"
|
||||||
&& child_count(prefix_node) == 1
|
&& child_count(prefix_node) == 1
|
||||||
&& child_at(prefix_node, 0)->identifier == AST_Node_Type::Id
|
&& child_at(prefix_node, 0).identifier == AST_Node_Type::Id
|
||||||
&& child_at(prefix_node, 0)->text == child_at(child_at(eq_node,0), 0)->text)
|
&& child_at(prefix_node, 0).text == child_at(eq_node,0).text)
|
||||||
{
|
{
|
||||||
const Boxed_Value &begin = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(eq_node, 1))->m_value;
|
const Boxed_Value &begin = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(eq_node, 1)).m_value;
|
||||||
const Boxed_Value &end = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(binary_node, 1))->m_value;
|
const 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;
|
const std::string &id = child_at(prefix_node, 0).text;
|
||||||
|
|
||||||
if (begin.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>())) {
|
&& end.get_type_info().bare_equal(user_type<int>())) {
|
||||||
@ -380,9 +419,14 @@ namespace chaiscript {
|
|||||||
const auto start_int = boxed_cast<int>(begin);
|
const auto start_int = boxed_cast<int>(begin);
|
||||||
const auto end_int = boxed_cast<int>(end);
|
const auto end_int = boxed_cast<int>(end);
|
||||||
|
|
||||||
const auto body = child_at(for_node, 3);
|
// note that we are moving the last element out, then popping the empty shared_ptr
|
||||||
|
// from the vector
|
||||||
return make_compiled_node(for_node, {body},
|
std::vector<eval::AST_Node_Impl_Ptr<T>> body_vector;
|
||||||
|
auto body_child = std::move(for_node->children[3]);
|
||||||
|
for_node->children.pop_back();
|
||||||
|
body_vector.emplace_back(std::move(body_child));
|
||||||
|
|
||||||
|
return make_compiled_node(std::move(for_node), std::move(body_vector),
|
||||||
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children, const chaiscript::detail::Dispatch_State &t_ss) {
|
[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);
|
assert(children.size() == 1);
|
||||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||||
@ -418,7 +462,7 @@ namespace chaiscript {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef Optimizer<optimizer::Partial_Fold, optimizer::Unused_Return, optimizer::Constant_Fold,
|
typedef Optimizer<optimizer::Partial_Fold, optimizer::Unused_Return, optimizer::Constant_Fold,
|
||||||
optimizer::If, optimizer::Return, optimizer::Dead_Code, optimizer::Block, optimizer::For_Loop> Optimizer_Default;
|
optimizer::If, optimizer::Return, optimizer::Dead_Code, optimizer::Block, optimizer::For_Loop, optimizer::Assign_Decl> Optimizer_Default;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -397,7 +397,7 @@ namespace chaiscript
|
|||||||
return m_optimizer;
|
return m_optimizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChaiScript_Parser(const ChaiScript_Parser &) = default;
|
ChaiScript_Parser(const ChaiScript_Parser &) = delete;
|
||||||
ChaiScript_Parser &operator=(const ChaiScript_Parser &) = delete;
|
ChaiScript_Parser &operator=(const ChaiScript_Parser &) = delete;
|
||||||
ChaiScript_Parser(ChaiScript_Parser &&) = default;
|
ChaiScript_Parser(ChaiScript_Parser &&) = default;
|
||||||
ChaiScript_Parser &operator=(ChaiScript_Parser &&) = delete;
|
ChaiScript_Parser &operator=(ChaiScript_Parser &&) = delete;
|
||||||
@ -406,10 +406,10 @@ namespace chaiscript
|
|||||||
bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast<uint8_t>(c)]; }
|
bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast<uint8_t>(c)]; }
|
||||||
|
|
||||||
/// Prints the parsed ast_nodes as a tree
|
/// Prints the parsed ast_nodes as a tree
|
||||||
void debug_print(AST_NodePtr t, std::string prepend = "") const override {
|
void debug_print(const AST_Node &t, std::string prepend = "") const override {
|
||||||
std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start().line << ", " << t->start().column << '\n';
|
std::cout << prepend << "(" << ast_node_type_to_string(t.identifier) << ") " << t.text << " : " << t.start().line << ", " << t.start().column << '\n';
|
||||||
for (const auto &node : t->get_children()) {
|
for (const auto &node : t.get_children()) {
|
||||||
debug_print(node, prepend + " ");
|
debug_print(node.get(), prepend + " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,7 +452,7 @@ namespace chaiscript
|
|||||||
/// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position
|
/// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position
|
||||||
m_match_stack.push_back(
|
m_match_stack.push_back(
|
||||||
m_optimizer.optimize(
|
m_optimizer.optimize(
|
||||||
chaiscript::make_shared<chaiscript::eval::AST_Node_Impl<Tracer>, NodeType>(
|
chaiscript::make_unique<chaiscript::eval::AST_Node_Impl<Tracer>, NodeType>(
|
||||||
std::move(t_text),
|
std::move(t_text),
|
||||||
std::move(filepos),
|
std::move(filepos),
|
||||||
std::move(new_children)))
|
std::move(new_children)))
|
||||||
@ -748,7 +748,9 @@ namespace chaiscript
|
|||||||
return const_var(static_cast<unsigned int>(u));
|
return const_var(static_cast<unsigned int>(u));
|
||||||
} else if (!unsigned_ && !longlong_ && u >= std::numeric_limits<long>::min() && u <= std::numeric_limits<long>::max()) {
|
} else if (!unsigned_ && !longlong_ && u >= std::numeric_limits<long>::min() && u <= std::numeric_limits<long>::max()) {
|
||||||
return const_var(static_cast<long>(u));
|
return const_var(static_cast<long>(u));
|
||||||
} else if ((unsigned_ || base != 10) && !longlong_ && u >= std::numeric_limits<unsigned long>::min() && u <= std::numeric_limits<unsigned long>::max()) {
|
} else if ((unsigned_ || base != 10) && !longlong_
|
||||||
|
&& u >= std::numeric_limits<unsigned long>::min()
|
||||||
|
&& u <= std::numeric_limits<unsigned long>::max()) {
|
||||||
return const_var(static_cast<unsigned long>(u));
|
return const_var(static_cast<unsigned long>(u));
|
||||||
} else if (!unsigned_ && u >= std::numeric_limits<long long>::min() && u <= std::numeric_limits<long long>::max()) {
|
} else if (!unsigned_ && u >= std::numeric_limits<long long>::min() && u <= std::numeric_limits<long long>::max()) {
|
||||||
return const_var(static_cast<long long>(u));
|
return const_var(static_cast<long long>(u));
|
||||||
@ -779,9 +781,9 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ... Param>
|
template<typename T, typename ... Param>
|
||||||
std::shared_ptr<eval::AST_Node_Impl<Tracer>> make_node(std::string t_match, const int t_prev_line, const int t_prev_col, Param && ...param)
|
std::unique_ptr<eval::AST_Node_Impl<Tracer>> make_node(std::string t_match, const int t_prev_line, const int t_prev_col, Param && ...param)
|
||||||
{
|
{
|
||||||
return chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, T>(std::move(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward<Param>(param)...);
|
return chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, T>(std::move(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward<Param>(param)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a number from the input, detecting if it's an integer or floating point
|
/// Reads a number from the input, detecting if it's an integer or floating point
|
||||||
@ -914,7 +916,7 @@ namespace chaiscript
|
|||||||
} break;
|
} break;
|
||||||
case utility::fnv1a_32("__FUNC__"): {
|
case utility::fnv1a_32("__FUNC__"): {
|
||||||
std::string fun_name = "NOT_IN_FUNCTION";
|
std::string fun_name = "NOT_IN_FUNCTION";
|
||||||
for (size_t idx = m_match_stack.size() - 1; idx > 0; --idx)
|
for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 0; --idx)
|
||||||
{
|
{
|
||||||
if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id
|
if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id
|
||||||
&& m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) {
|
&& m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) {
|
||||||
@ -927,7 +929,7 @@ namespace chaiscript
|
|||||||
} break;
|
} break;
|
||||||
case utility::fnv1a_32("__CLASS__"): {
|
case utility::fnv1a_32("__CLASS__"): {
|
||||||
std::string fun_name = "NOT_IN_CLASS";
|
std::string fun_name = "NOT_IN_CLASS";
|
||||||
for (size_t idx = m_match_stack.size() - 1; idx > 1; --idx)
|
for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 1; --idx)
|
||||||
{
|
{
|
||||||
if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id
|
if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id
|
||||||
&& m_match_stack[idx-1]->identifier == AST_Node_Type::Id
|
&& m_match_stack[idx-1]->identifier == AST_Node_Type::Id
|
||||||
@ -995,7 +997,7 @@ namespace chaiscript
|
|||||||
int in_interpolation = 0;
|
int in_interpolation = 0;
|
||||||
bool in_quote = false;
|
bool in_quote = false;
|
||||||
|
|
||||||
while (m_position.has_more() && ((*m_position != '\"') || ((*m_position == '\"') && (in_interpolation > 0)) || ((*m_position == '\"') && (prev_char == '\\')))) {
|
while (m_position.has_more() && ((*m_position != '\"') || (in_interpolation > 0) || (prev_char == '\\'))) {
|
||||||
|
|
||||||
if (!Eol_()) {
|
if (!Eol_()) {
|
||||||
if (prev_char == '$' && *m_position == '{') {
|
if (prev_char == '$' && *m_position == '{') {
|
||||||
@ -1051,13 +1053,14 @@ namespace chaiscript
|
|||||||
Char_Parser &operator=(const Char_Parser &) = delete;
|
Char_Parser &operator=(const Char_Parser &) = delete;
|
||||||
|
|
||||||
~Char_Parser(){
|
~Char_Parser(){
|
||||||
if (is_octal) {
|
try {
|
||||||
process_octal();
|
if (is_octal) {
|
||||||
}
|
process_octal();
|
||||||
|
}
|
||||||
|
|
||||||
if (is_hex) {
|
if (is_hex) {
|
||||||
process_hex();
|
process_hex();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unicode_size > 0) {
|
if (unicode_size > 0) {
|
||||||
process_unicode();
|
process_unicode();
|
||||||
@ -1073,8 +1076,10 @@ namespace chaiscript
|
|||||||
|
|
||||||
void process_hex()
|
void process_hex()
|
||||||
{
|
{
|
||||||
auto val = stoll(hex_matches, nullptr, 16);
|
if (!hex_matches.empty()) {
|
||||||
match.push_back(char_type(val));
|
auto val = stoll(hex_matches, nullptr, 16);
|
||||||
|
match.push_back(char_type(val));
|
||||||
|
}
|
||||||
hex_matches.clear();
|
hex_matches.clear();
|
||||||
is_escaped = false;
|
is_escaped = false;
|
||||||
is_hex = false;
|
is_hex = false;
|
||||||
@ -1083,8 +1088,10 @@ namespace chaiscript
|
|||||||
|
|
||||||
void process_octal()
|
void process_octal()
|
||||||
{
|
{
|
||||||
auto val = stoll(octal_matches, nullptr, 8);
|
if (!octal_matches.empty()) {
|
||||||
match.push_back(char_type(val));
|
auto val = stoll(octal_matches, nullptr, 8);
|
||||||
|
match.push_back(char_type(val));
|
||||||
|
}
|
||||||
octal_matches.clear();
|
octal_matches.clear();
|
||||||
is_escaped = false;
|
is_escaped = false;
|
||||||
is_octal = false;
|
is_octal = false;
|
||||||
@ -1295,6 +1302,7 @@ namespace chaiscript
|
|||||||
cparser.saw_interpolation_marker = false;
|
cparser.saw_interpolation_marker = false;
|
||||||
} else {
|
} else {
|
||||||
cparser.parse(*s, start.line, start.col, *m_filename);
|
cparser.parse(*s, start.line, start.col, *m_filename);
|
||||||
|
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1323,7 +1331,7 @@ namespace chaiscript
|
|||||||
char prev_char = *m_position;
|
char prev_char = *m_position;
|
||||||
++m_position;
|
++m_position;
|
||||||
|
|
||||||
while (m_position.has_more() && ((*m_position != '\'') || ((*m_position == '\'') && (prev_char == '\\')))) {
|
while (m_position.has_more() && ((*m_position != '\'') || (prev_char == '\\'))) {
|
||||||
if (!Eol_()) {
|
if (!Eol_()) {
|
||||||
if (prev_char == '\\') {
|
if (prev_char == '\\') {
|
||||||
prev_char = 0;
|
prev_char = 0;
|
||||||
@ -1802,7 +1810,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
if ((is_if_init && num_children == 3)
|
if ((is_if_init && num_children == 3)
|
||||||
|| (!is_if_init && num_children == 2)) {
|
|| (!is_if_init && num_children == 2)) {
|
||||||
m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_if_init) {
|
if (!is_if_init) {
|
||||||
@ -1892,7 +1900,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1902,13 +1910,13 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Constant_AST_Node<Tracer>>(Boxed_Value(true)));
|
m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Constant_AST_Node<Tracer>>(Boxed_Value(true)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Equation())
|
if (!Equation())
|
||||||
{
|
{
|
||||||
m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1939,9 +1947,17 @@ namespace chaiscript
|
|||||||
throw exception::eval_error("Incomplete 'for' block", File_Position(m_position.line, m_position.col), *m_filename);
|
throw exception::eval_error("Incomplete 'for' block", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto num_children = m_match_stack.size() - prev_stack_top;
|
||||||
|
|
||||||
if (classic_for) {
|
if (classic_for) {
|
||||||
|
if (num_children != 4) {
|
||||||
|
throw exception::eval_error("Incomplete 'for' expression", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
|
}
|
||||||
build_match<eval::For_AST_Node<Tracer>>(prev_stack_top);
|
build_match<eval::For_AST_Node<Tracer>>(prev_stack_top);
|
||||||
} else {
|
} else {
|
||||||
|
if (num_children != 3) {
|
||||||
|
throw exception::eval_error("Incomplete ranged-for expression", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
|
}
|
||||||
build_match<eval::Ranged_For_AST_Node<Tracer>>(prev_stack_top);
|
build_match<eval::Ranged_For_AST_Node<Tracer>>(prev_stack_top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2048,7 +2064,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_match_stack.size() == prev_stack_top) {
|
if (m_match_stack.size() == prev_stack_top) {
|
||||||
m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
build_match<eval::Block_AST_Node<Tracer>>(prev_stack_top);
|
build_match<eval::Block_AST_Node<Tracer>>(prev_stack_top);
|
||||||
@ -2072,7 +2088,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_match_stack.size() == prev_stack_top) {
|
if (m_match_stack.size() == prev_stack_top) {
|
||||||
m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
build_match<eval::Block_AST_Node<Tracer>>(prev_stack_top);
|
build_match<eval::Block_AST_Node<Tracer>>(prev_stack_top);
|
||||||
@ -2148,13 +2164,13 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
if (m_match_stack.back()->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
|
if (m_match_stack.back()->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
}
|
}
|
||||||
auto dot_access = m_match_stack.back()->children[0];
|
auto dot_access = std::move(m_match_stack.back()->children[0]);
|
||||||
auto func_call = m_match_stack.back();
|
auto func_call = std::move(m_match_stack.back());
|
||||||
m_match_stack.pop_back();
|
m_match_stack.pop_back();
|
||||||
func_call->children.erase(func_call->children.begin());
|
func_call->children.erase(func_call->children.begin());
|
||||||
if (dot_access->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
|
if (dot_access->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
}
|
}
|
||||||
func_call->children.insert(func_call->children.begin(), dot_access->children.back());
|
func_call->children.insert(func_call->children.begin(), std::move(dot_access->children.back()));
|
||||||
dot_access->children.pop_back();
|
dot_access->children.pop_back();
|
||||||
dot_access->children.push_back(std::move(func_call));
|
dot_access->children.push_back(std::move(func_call));
|
||||||
if (dot_access->children.size() != 2) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
|
if (dot_access->children.size() != 2) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
@ -2215,7 +2231,7 @@ namespace chaiscript
|
|||||||
throw exception::eval_error("Incomplete variable declaration", File_Position(m_position.line, m_position.col), *m_filename);
|
throw exception::eval_error("Incomplete variable declaration", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (Keyword("GLOBAL") || Keyword("global")) {
|
} else if (Keyword("global")) {
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
if (!(Reference() || Id(true))) {
|
if (!(Reference() || Id(true))) {
|
||||||
@ -2560,24 +2576,23 @@ namespace chaiscript
|
|||||||
|
|
||||||
AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) override
|
AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) override
|
||||||
{
|
{
|
||||||
ChaiScript_Parser<Tracer, Optimizer> parser(*this);
|
ChaiScript_Parser<Tracer, Optimizer> parser(m_tracer, m_optimizer);
|
||||||
parser.m_match_stack.clear();
|
|
||||||
return parser.parse_internal(t_input, t_fname);
|
return parser.parse_internal(t_input, t_fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
eval::AST_Node_Impl_Ptr<Tracer> parse_instr_eval(const std::string &t_input)
|
eval::AST_Node_Impl_Ptr<Tracer> parse_instr_eval(const std::string &t_input)
|
||||||
{
|
{
|
||||||
const auto last_position = m_position;
|
auto last_position = m_position;
|
||||||
const auto last_filename = m_filename;
|
auto last_filename = m_filename;
|
||||||
const auto last_match_stack = std::exchange(m_match_stack, decltype(m_match_stack){});
|
auto last_match_stack = std::exchange(m_match_stack, decltype(m_match_stack){});
|
||||||
|
|
||||||
const auto retval = parse_internal(t_input, "instr eval");
|
auto retval = parse_internal(t_input, "instr eval");
|
||||||
|
|
||||||
m_position = std::move(last_position);
|
m_position = std::move(last_position);
|
||||||
m_filename = std::move(last_filename);
|
m_filename = std::move(last_filename);
|
||||||
m_match_stack = std::move(last_match_stack);
|
m_match_stack = std::move(last_match_stack);
|
||||||
|
|
||||||
return std::dynamic_pointer_cast<eval::AST_Node_Impl<Tracer>>(retval);
|
return eval::AST_Node_Impl_Ptr<Tracer>(dynamic_cast<eval::AST_Node_Impl<Tracer>*>(retval.release()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the given input string, tagging parsed ast_nodes with the given m_filename.
|
/// Parses the given input string, tagging parsed ast_nodes with the given m_filename.
|
||||||
@ -2589,20 +2604,21 @@ namespace chaiscript
|
|||||||
while (m_position.has_more() && (!Eol())) {
|
while (m_position.has_more() && (!Eol())) {
|
||||||
++m_position;
|
++m_position;
|
||||||
}
|
}
|
||||||
/// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Statements(true)) {
|
if (Statements(true)) {
|
||||||
if (m_position.has_more()) {
|
if (m_position.has_more()) {
|
||||||
throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), t_fname);
|
throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
} else {
|
} else {
|
||||||
build_match<eval::File_AST_Node<Tracer>>(0);
|
build_match<eval::File_AST_Node<Tracer>>(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_match_stack.front();
|
AST_NodePtr retval(std::move(m_match_stack.front()));
|
||||||
|
m_match_stack.clear();
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,7 +41,7 @@ namespace chaiscript
|
|||||||
struct DLSym
|
struct DLSym
|
||||||
{
|
{
|
||||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||||
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
|
: m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str())))
|
||||||
{
|
{
|
||||||
if (!m_symbol)
|
if (!m_symbol)
|
||||||
{
|
{
|
||||||
@ -49,19 +49,6 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static T cast_symbol(void *p)
|
|
||||||
{
|
|
||||||
union cast_union
|
|
||||||
{
|
|
||||||
T func_ptr;
|
|
||||||
void *in_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
cast_union c;
|
|
||||||
c.in_ptr = p;
|
|
||||||
return c.func_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
T m_symbol;
|
T m_symbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,11 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
Loadable_Module(const std::string &, const std::string &)
|
Loadable_Module(const std::string &, const std::string &)
|
||||||
{
|
{
|
||||||
|
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||||
|
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
|
||||||
|
#else
|
||||||
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
|
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ModulePtr m_moduleptr;
|
ModulePtr m_moduleptr;
|
||||||
|
|||||||
@ -131,7 +131,7 @@ class JSON
|
|||||||
}
|
}
|
||||||
|
|
||||||
Internal( double d ) : Float( d ), Type(Class::Floating) {}
|
Internal( double d ) : Float( d ), Type(Class::Floating) {}
|
||||||
Internal( long l ) : Int( l ), Type(Class::Integral) {}
|
Internal( int64_t l ) : Int( l ), Type(Class::Integral) {}
|
||||||
Internal( bool b ) : Bool( b ), Type(Class::Boolean) {}
|
Internal( bool b ) : Bool( b ), Type(Class::Boolean) {}
|
||||||
Internal( std::string s ) : String(std::make_unique<std::string>(std::move(s))), Type(Class::String) {}
|
Internal( std::string s ) : String(std::make_unique<std::string>(std::move(s))), Type(Class::String) {}
|
||||||
Internal() : Type(Class::Null) {}
|
Internal() : Type(Class::Null) {}
|
||||||
@ -192,7 +192,7 @@ class JSON
|
|||||||
std::unique_ptr<QuickFlatMap> Map;
|
std::unique_ptr<QuickFlatMap> Map;
|
||||||
std::unique_ptr<std::string> String;
|
std::unique_ptr<std::string> String;
|
||||||
double Float = 0;
|
double Float = 0;
|
||||||
long Int = 0;
|
int64_t Int = 0;
|
||||||
bool Bool = false;
|
bool Bool = false;
|
||||||
|
|
||||||
Class Type = Class::Null;
|
Class Type = Class::Null;
|
||||||
@ -248,7 +248,7 @@ class JSON
|
|||||||
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<bool>(b) ) {}
|
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<bool>(b) ) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<long>(i) ) {}
|
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<int64_t>(i) ) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) : internal( static_cast<double>(f) ) {}
|
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) : internal( static_cast<double>(f) ) {}
|
||||||
@ -335,8 +335,8 @@ class JSON
|
|||||||
return ok ? internal.Float : 0.0;
|
return ok ? internal.Float : 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
long to_int() const { bool b; return to_int( b ); }
|
int64_t to_int() const { bool b; return to_int( b ); }
|
||||||
long to_int( bool &ok ) const {
|
int64_t to_int( bool &ok ) const {
|
||||||
ok = (internal.Type == Class::Integral);
|
ok = (internal.Type == Class::Integral);
|
||||||
return ok ? internal.Int : 0;
|
return ok ? internal.Int : 0;
|
||||||
}
|
}
|
||||||
@ -392,7 +392,7 @@ class JSON
|
|||||||
bool skip = true;
|
bool skip = true;
|
||||||
for( auto &p : *internal.Map ) {
|
for( auto &p : *internal.Map ) {
|
||||||
if( !skip ) { s += ",\n"; }
|
if( !skip ) { s += ",\n"; }
|
||||||
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
|
s += ( pad + "\"" + json_escape(p.first) + "\" : " + p.second.dump( depth + 1, tab ) );
|
||||||
skip = false;
|
skip = false;
|
||||||
}
|
}
|
||||||
s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
|
s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
|
||||||
@ -463,7 +463,7 @@ struct JSONParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void consume_ws( const std::string &str, size_t &offset ) {
|
static void consume_ws( const std::string &str, size_t &offset ) {
|
||||||
while( isspace( str[offset] ) && offset <= str.size() ) { ++offset; }
|
while( isspace( str.at(offset) ) && offset <= str.size() ) { ++offset; }
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSON parse_object( const std::string &str, size_t &offset ) {
|
static JSON parse_object( const std::string &str, size_t &offset ) {
|
||||||
@ -471,29 +471,29 @@ struct JSONParser {
|
|||||||
|
|
||||||
++offset;
|
++offset;
|
||||||
consume_ws( str, offset );
|
consume_ws( str, offset );
|
||||||
if( str[offset] == '}' ) {
|
if( str.at(offset) == '}' ) {
|
||||||
++offset; return Object;
|
++offset; return Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;offset<str.size();) {
|
for (;offset<str.size();) {
|
||||||
JSON Key = parse_next( str, offset );
|
JSON Key = parse_next( str, offset );
|
||||||
consume_ws( str, offset );
|
consume_ws( str, offset );
|
||||||
if( str[offset] != ':' ) {
|
if( str.at(offset) != ':' ) {
|
||||||
throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str[offset] + "'\n");
|
throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str.at(offset) + "'\n");
|
||||||
}
|
}
|
||||||
consume_ws( str, ++offset );
|
consume_ws( str, ++offset );
|
||||||
JSON Value = parse_next( str, offset );
|
JSON Value = parse_next( str, offset );
|
||||||
Object[Key.to_string()] = Value;
|
Object[Key.to_string()] = Value;
|
||||||
|
|
||||||
consume_ws( str, offset );
|
consume_ws( str, offset );
|
||||||
if( str[offset] == ',' ) {
|
if( str.at(offset) == ',' ) {
|
||||||
++offset; continue;
|
++offset; continue;
|
||||||
}
|
}
|
||||||
else if( str[offset] == '}' ) {
|
else if( str.at(offset) == '}' ) {
|
||||||
++offset; break;
|
++offset; break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str[offset] + "'\n");
|
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str.at(offset) + "'\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,7 +506,7 @@ struct JSONParser {
|
|||||||
|
|
||||||
++offset;
|
++offset;
|
||||||
consume_ws( str, offset );
|
consume_ws( str, offset );
|
||||||
if( str[offset] == ']' ) {
|
if( str.at(offset) == ']' ) {
|
||||||
++offset; return Array;
|
++offset; return Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,14 +514,14 @@ struct JSONParser {
|
|||||||
Array[index++] = parse_next( str, offset );
|
Array[index++] = parse_next( str, offset );
|
||||||
consume_ws( str, offset );
|
consume_ws( str, offset );
|
||||||
|
|
||||||
if( str[offset] == ',' ) {
|
if( str.at(offset) == ',' ) {
|
||||||
++offset; continue;
|
++offset; continue;
|
||||||
}
|
}
|
||||||
else if( str[offset] == ']' ) {
|
else if( str.at(offset) == ']' ) {
|
||||||
++offset; break;
|
++offset; break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str[offset] + "'\n");
|
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str.at(offset) + "'\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,9 +530,9 @@ struct JSONParser {
|
|||||||
|
|
||||||
static JSON parse_string( const std::string &str, size_t &offset ) {
|
static JSON parse_string( const std::string &str, size_t &offset ) {
|
||||||
std::string val;
|
std::string val;
|
||||||
for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
|
for( char c = str.at(++offset); c != '\"' ; c = str.at(++offset) ) {
|
||||||
if( c == '\\' ) {
|
if( c == '\\' ) {
|
||||||
switch( str[ ++offset ] ) {
|
switch( str.at(++offset) ) {
|
||||||
case '\"': val += '\"'; break;
|
case '\"': val += '\"'; break;
|
||||||
case '\\': val += '\\'; break;
|
case '\\': val += '\\'; break;
|
||||||
case '/' : val += '/' ; break;
|
case '/' : val += '/' ; break;
|
||||||
@ -544,7 +544,7 @@ struct JSONParser {
|
|||||||
case 'u' : {
|
case 'u' : {
|
||||||
val += "\\u" ;
|
val += "\\u" ;
|
||||||
for( size_t i = 1; i <= 4; ++i ) {
|
for( size_t i = 1; i <= 4; ++i ) {
|
||||||
c = str[offset+i];
|
c = str.at(offset+i);
|
||||||
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) {
|
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) {
|
||||||
val += c;
|
val += c;
|
||||||
} else {
|
} else {
|
||||||
@ -567,12 +567,18 @@ struct JSONParser {
|
|||||||
std::string val, exp_str;
|
std::string val, exp_str;
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
bool isDouble = false;
|
bool isDouble = false;
|
||||||
long exp = 0;
|
bool isNegative = false;
|
||||||
|
int64_t exp = 0;
|
||||||
|
bool isExpNegative = false;
|
||||||
|
if( offset < str.size() && str.at(offset) == '-' ) {
|
||||||
|
isNegative = true;
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
for (; offset < str.size() ;) {
|
for (; offset < str.size() ;) {
|
||||||
c = str[offset++];
|
c = str.at(offset++);
|
||||||
if( (c == '-') || (c >= '0' && c <= '9') ) {
|
if( c >= '0' && c <= '9' ) {
|
||||||
val += c;
|
val += c;
|
||||||
} else if( c == '.' ) {
|
} else if( c == '.' && !isDouble ) {
|
||||||
val += c;
|
val += c;
|
||||||
isDouble = true;
|
isDouble = true;
|
||||||
} else {
|
} else {
|
||||||
@ -580,9 +586,9 @@ struct JSONParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( offset < str.size() && (c == 'E' || c == 'e' )) {
|
if( offset < str.size() && (c == 'E' || c == 'e' )) {
|
||||||
c = str[ offset++ ];
|
c = str.at(offset++);
|
||||||
if( c == '-' ) {
|
if( c == '-' ) {
|
||||||
exp_str += '-';
|
isExpNegative = true;
|
||||||
} else if( c == '+' ) {
|
} else if( c == '+' ) {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else {
|
} else {
|
||||||
@ -590,7 +596,7 @@ struct JSONParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (; offset < str.size() ;) {
|
for (; offset < str.size() ;) {
|
||||||
c = str[ offset++ ];
|
c = str.at(offset++);
|
||||||
if( c >= '0' && c <= '9' ) {
|
if( c >= '0' && c <= '9' ) {
|
||||||
exp_str += c;
|
exp_str += c;
|
||||||
} else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
|
} else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
|
||||||
@ -598,9 +604,9 @@ struct JSONParser {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exp = chaiscript::parse_num<long>( exp_str );
|
exp = chaiscript::parse_num<int64_t>( exp_str ) * (isExpNegative?-1:1);
|
||||||
}
|
}
|
||||||
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
|
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
|
||||||
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
|
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
|
||||||
@ -608,12 +614,12 @@ struct JSONParser {
|
|||||||
--offset;
|
--offset;
|
||||||
|
|
||||||
if( isDouble ) {
|
if( isDouble ) {
|
||||||
return JSON(chaiscript::parse_num<double>( val ) * std::pow( 10, exp ));
|
return JSON((isNegative?-1:1) * chaiscript::parse_num<double>( val ) * std::pow( 10, exp ));
|
||||||
} else {
|
} else {
|
||||||
if( !exp_str.empty() ) {
|
if( !exp_str.empty() ) {
|
||||||
return JSON(static_cast<double>(chaiscript::parse_num<long>( val )) * std::pow( 10, exp ));
|
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<int64_t>( val )) * std::pow( 10, exp ));
|
||||||
} else {
|
} else {
|
||||||
return JSON(chaiscript::parse_num<long>( val ));
|
return JSON((isNegative?-1:1) * chaiscript::parse_num<int64_t>( val ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -641,7 +647,7 @@ struct JSONParser {
|
|||||||
static JSON parse_next( const std::string &str, size_t &offset ) {
|
static JSON parse_next( const std::string &str, size_t &offset ) {
|
||||||
char value;
|
char value;
|
||||||
consume_ws( str, offset );
|
consume_ws( str, offset );
|
||||||
value = str[offset];
|
value = str.at(offset);
|
||||||
switch( value ) {
|
switch( value ) {
|
||||||
case '[' : return parse_array( str, offset );
|
case '[' : return parse_array( str, offset );
|
||||||
case '{' : return parse_object( str, offset );
|
case '{' : return parse_object( str, offset );
|
||||||
|
|||||||
@ -63,7 +63,11 @@ namespace chaiscript
|
|||||||
|
|
||||||
static Boxed_Value from_json(const std::string &t_json)
|
static Boxed_Value from_json(const std::string &t_json)
|
||||||
{
|
{
|
||||||
return from_json( json::JSON::Load(t_json) );
|
try {
|
||||||
|
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)
|
static std::string to_json(const Boxed_Value &t_bv)
|
||||||
@ -76,7 +80,7 @@ namespace chaiscript
|
|||||||
try {
|
try {
|
||||||
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv);
|
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 obj(json::JSON::Class::Object);
|
||||||
for (const auto &o : m)
|
for (const auto &o : m)
|
||||||
{
|
{
|
||||||
obj[o.first] = to_json_object(o.second);
|
obj[o.first] = to_json_object(o.second);
|
||||||
@ -89,7 +93,7 @@ namespace chaiscript
|
|||||||
try {
|
try {
|
||||||
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
|
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
|
||||||
|
|
||||||
json::JSON obj;
|
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]);
|
obj[i] = to_json_object(v[i]);
|
||||||
@ -106,7 +110,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
return json::JSON(bn.get_as<double>());
|
return json::JSON(bn.get_as<double>());
|
||||||
} else {
|
} else {
|
||||||
return json::JSON(bn.get_as<long>());
|
return json::JSON(bn.get_as<std::int64_t>());
|
||||||
}
|
}
|
||||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||||
// not a number
|
// not a number
|
||||||
@ -128,7 +132,7 @@ namespace chaiscript
|
|||||||
try {
|
try {
|
||||||
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
|
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
|
||||||
|
|
||||||
json::JSON obj;
|
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);
|
obj[attr.first] = to_json_object(attr.second);
|
||||||
@ -138,6 +142,8 @@ namespace chaiscript
|
|||||||
// not a dynamic object
|
// not a dynamic object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t_bv.is_null()) return json::JSON(); // a null value
|
||||||
|
|
||||||
throw std::runtime_error("Unknown object type to convert to JSON");
|
throw std::runtime_error("Unknown object type to convert to JSON");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
performance_tests/create_variables.chai
Normal file
11
performance_tests/create_variables.chai
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
def var_test(int n)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < n; ++i) {
|
||||||
|
var j = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var n = 500000
|
||||||
|
var_test(n) // takes 2.6 s
|
||||||
|
|
||||||
|
|
||||||
55
readme.md
55
readme.md
@ -25,7 +25,7 @@ Release under the BSD license, see "license.txt" for details.
|
|||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
|
||||||
[](https://gitter.im/ChaiScript/ChaiScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/ChaiScript/ChaiScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
ChaiScript is one of the only embedded scripting language designed from the
|
ChaiScript is one of the only embedded scripting language designed from the
|
||||||
ground up to directly target C++ and take advantage of modern C++ development
|
ground up to directly target C++ and take advantage of modern C++ development
|
||||||
@ -79,7 +79,7 @@ directory, and for more in-depth look at the language, the unit tests in the
|
|||||||
"unittests" directory cover the most ground.
|
"unittests" directory cover the most ground.
|
||||||
|
|
||||||
For examples of how to register parts of your C++ application, see
|
For examples of how to register parts of your C++ application, see
|
||||||
"example.cpp" in the "src" directory. Example.cpp is verbose and shows every
|
"example.cpp" in the "samples" directory. Example.cpp is verbose and shows every
|
||||||
possible way of working with the library. For further documentation generate
|
possible way of working with the library. For further documentation generate
|
||||||
the doxygen documentation in the build folder or see the website
|
the doxygen documentation in the build folder or see the website
|
||||||
http://www.chaiscript.com.
|
http://www.chaiscript.com.
|
||||||
@ -87,44 +87,21 @@ http://www.chaiscript.com.
|
|||||||
|
|
||||||
The shortest complete example possible follows:
|
The shortest complete example possible follows:
|
||||||
|
|
||||||
/// main.cpp
|
```C++
|
||||||
|
/// main.cpp
|
||||||
|
|
||||||
#include <chaiscript/chaiscript.hpp>
|
#include <chaiscript/chaiscript.hpp>
|
||||||
|
|
||||||
double function(int i, double j)
|
double function(int i, double j)
|
||||||
{
|
{
|
||||||
return i * j;
|
return i * j;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
chaiscript::ChaiScript chai;
|
|
||||||
chai.add(chaiscript::fun(&function), "function");
|
|
||||||
|
|
||||||
double d = chai.eval<double>("function(3, 4.75);");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Or, if you want to compile the std lib into your code, which reduces
|
|
||||||
runtime requirements.
|
|
||||||
|
|
||||||
/// main.cpp
|
|
||||||
|
|
||||||
#include <chaiscript/chaiscript.hpp>
|
|
||||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
|
||||||
|
|
||||||
double function(int i, double j)
|
|
||||||
{
|
|
||||||
return i * j;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
|
||||||
chai.add(chaiscript::fun(&function), "function");
|
|
||||||
|
|
||||||
double d = chai.eval<double>("function(3, 4.75);");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript chai;
|
||||||
|
chai.add(chaiscript::fun(&function), "function");
|
||||||
|
|
||||||
|
double d = chai.eval<double>("function(3, 4.75);");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
12
samples/BUCK
Normal file
12
samples/BUCK
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
cxx_binary(
|
||||||
|
name = 'example',
|
||||||
|
srcs = [
|
||||||
|
'example.cpp',
|
||||||
|
],
|
||||||
|
compiler_flags = [
|
||||||
|
'-std=c++14',
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
'//:chaiscript',
|
||||||
|
],
|
||||||
|
)
|
||||||
@ -51,11 +51,9 @@ struct System
|
|||||||
void do_callbacks(const std::string &inp)
|
void do_callbacks(const std::string &inp)
|
||||||
{
|
{
|
||||||
log("Running Callbacks: " + inp);
|
log("Running Callbacks: " + inp);
|
||||||
for (std::map<std::string, std::function<std::string (const std::string &)> >::iterator itr = m_callbacks.begin();
|
for (auto & m_callback : m_callbacks)
|
||||||
itr != m_callbacks.end();
|
|
||||||
++itr)
|
|
||||||
{
|
{
|
||||||
log("Callback: " + itr->first, itr->second(inp));
|
log("Callback: " + m_callback.first, m_callback.second(inp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -88,25 +86,25 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
|||||||
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
|
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
|
||||||
// in the "add_callback" function of struct System the chaiscript function is converted into a
|
// in the "add_callback" function of struct System the chaiscript function is converted into a
|
||||||
// std::function, so it can be handled and called easily and type-safely
|
// std::function, so it can be handled and called easily and type-safely
|
||||||
chai.eval("system.add_callback(\"#1\", fun(x) { \"Callback1 \" + x });");
|
chai.eval(R"(system.add_callback("#1", fun(x) { "Callback1 " + x });)");
|
||||||
|
|
||||||
// Because we are sharing the "system" object with the chaiscript engine we have equal
|
// Because we are sharing the "system" object with the chaiscript engine we have equal
|
||||||
// access to it both from within chaiscript and from C++ code
|
// access to it both from within chaiscript and from C++ code
|
||||||
system.do_callbacks("TestString");
|
system.do_callbacks("TestString");
|
||||||
chai.eval("system.do_callbacks(\"TestString\");");
|
chai.eval(R"(system.do_callbacks("TestString");)");
|
||||||
|
|
||||||
// The log function is overloaded, therefore we have to give the C++ compiler a hint as to which
|
// The log function is overloaded, therefore we have to give the C++ compiler a hint as to which
|
||||||
// version we want to register. One way to do this is to create a typedef of the function pointer
|
// version we want to register. One way to do this is to create a typedef of the function pointer
|
||||||
// then cast your function to that typedef.
|
// then cast your function to that typedef.
|
||||||
typedef void (*PlainLog)(const std::string &);
|
using PlainLog = void (*)(const std::string &);
|
||||||
typedef void (*ModuleLog)(const std::string &, const std::string &);
|
using ModuleLog = void (*)(const std::string &, const std::string &);
|
||||||
chai.add(fun(PlainLog(&log)), "log");
|
chai.add(fun(PlainLog(&log)), "log");
|
||||||
chai.add(fun(ModuleLog(&log)), "log");
|
chai.add(fun(ModuleLog(&log)), "log");
|
||||||
|
|
||||||
chai.eval("log(\"Test Message\")");
|
chai.eval(R"(log("Test Message"))");
|
||||||
|
|
||||||
// A shortcut to using eval is just to use the chai operator()
|
// A shortcut to using eval is just to use the chai operator()
|
||||||
chai("log(\"Test Module\", \"Test Message\");");
|
chai(R"(log("Test Module", "Test Message");)");
|
||||||
|
|
||||||
//Finally, it is possible to register a lambda as a system function, in this
|
//Finally, it is possible to register a lambda as a system function, in this
|
||||||
//way, we can, for instance add a bound member function to the system
|
//way, we can, for instance add a bound member function to the system
|
||||||
@ -115,7 +113,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
|||||||
//Call bound version of do_callbacks
|
//Call bound version of do_callbacks
|
||||||
chai("do_callbacks()");
|
chai("do_callbacks()");
|
||||||
|
|
||||||
std::function<void ()> caller = chai.eval<std::function<void ()> >("fun() { system.do_callbacks(\"From Functor\"); }");
|
std::function<void ()> caller = chai.eval<std::function<void ()> >(
|
||||||
|
R"(fun() { system.do_callbacks("From Functor"); })"
|
||||||
|
);
|
||||||
caller();
|
caller();
|
||||||
|
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
|||||||
std::cout << "scripti: " << scripti << '\n';
|
std::cout << "scripti: " << scripti << '\n';
|
||||||
scripti *= 2;
|
scripti *= 2;
|
||||||
std::cout << "scripti (updated): " << scripti << '\n';
|
std::cout << "scripti (updated): " << scripti << '\n';
|
||||||
chai("print(\"Scripti from chai: \" + to_string(scripti))");
|
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
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
|||||||
log("Functor test output", ss.str());
|
log("Functor test output", ss.str());
|
||||||
|
|
||||||
chai.add(var(std::shared_ptr<int>()), "nullvar");
|
chai.add(var(std::shared_ptr<int>()), "nullvar");
|
||||||
chai("print(\"This should be true.\"); print(nullvar.is_var_null())");
|
chai(R"(print("This should be true."); print(nullvar.is_var_null()))");
|
||||||
|
|
||||||
// test the global const action
|
// test the global const action
|
||||||
chai.add_global_const(const_var(1), "constvar");
|
chai.add_global_const(const_var(1), "constvar");
|
||||||
@ -160,7 +160,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
|||||||
|
|
||||||
|
|
||||||
// Test ability to register a function that excepts a shared_ptr version of a type
|
// Test ability to register a function that excepts a shared_ptr version of a type
|
||||||
chai("take_shared_ptr(\"Hello World as a shared_ptr\");");
|
chai(R"(take_shared_ptr("Hello World as a shared_ptr");)");
|
||||||
|
|
||||||
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
|
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
|
||||||
|
|
||||||
|
|||||||
@ -68,6 +68,7 @@ std::vector<std::string> default_search_paths()
|
|||||||
{
|
{
|
||||||
std::vector<std::string> paths;
|
std::vector<std::string> paths;
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_NO_DYNLOAD
|
||||||
#ifdef CHAISCRIPT_WINDOWS // force no unicode
|
#ifdef CHAISCRIPT_WINDOWS // force no unicode
|
||||||
CHAR path[4096];
|
CHAR path[4096];
|
||||||
int size = GetModuleFileNameA(0, path, sizeof(path) - 1);
|
int size = GetModuleFileNameA(0, path, sizeof(path) - 1);
|
||||||
@ -137,6 +138,7 @@ std::vector<std::string> default_search_paths()
|
|||||||
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
|
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif // ifndef CHAISCRIPT_NO_DYNLOAD
|
||||||
|
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
@ -250,7 +252,7 @@ void interactive(chaiscript::ChaiScript& chai)
|
|||||||
catch (const chaiscript::exception::eval_error &ee) {
|
catch (const chaiscript::exception::eval_error &ee) {
|
||||||
std::cout << ee.what();
|
std::cout << ee.what();
|
||||||
if (ee.call_stack.size() > 0) {
|
if (ee.call_stack.size() > 0) {
|
||||||
std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
|
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,7 +122,7 @@ int main()
|
|||||||
assert(myderived.getValue() == "1234");
|
assert(myderived.getValue() == "1234");
|
||||||
|
|
||||||
|
|
||||||
chai.eval("myderived.setValue(\"new\")"); // set the value via chaiscript
|
chai.eval(R"(myderived.setValue("new"))"); // set the value via chaiscript
|
||||||
assert(myderived.getValue() == "new");
|
assert(myderived.getValue() == "new");
|
||||||
|
|
||||||
// call the other derived method via chaiscript and return the value to c++ land:
|
// call the other derived method via chaiscript and return the value to c++ land:
|
||||||
|
|||||||
342
src/libfuzzer_client.cpp
Normal file
342
src/libfuzzer_client.cpp
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||||
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
|
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||||
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <chaiscript/chaiscript.hpp>
|
||||||
|
#include "../static_libs/chaiscript_parser.hpp"
|
||||||
|
#include "../static_libs/chaiscript_stdlib.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef READLINE_AVAILABLE
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#include <readline/history.h>
|
||||||
|
#else
|
||||||
|
|
||||||
|
char *mystrdup (const char *s) {
|
||||||
|
size_t len = strlen(s); // Space for length plus nul
|
||||||
|
char *d = static_cast<char*>(malloc (len+1));
|
||||||
|
if (d == nullptr) { return nullptr; } // No memory
|
||||||
|
#ifdef CHAISCRIPT_MSVC
|
||||||
|
strcpy_s(d, len+1, s); // Copy the characters
|
||||||
|
#else
|
||||||
|
strncpy(d,s,len); // Copy the characters
|
||||||
|
#endif
|
||||||
|
d[len] = '\0';
|
||||||
|
return d; // Return the new string
|
||||||
|
}
|
||||||
|
|
||||||
|
char* readline(const char* p)
|
||||||
|
{
|
||||||
|
std::string retval;
|
||||||
|
std::cout << p ;
|
||||||
|
std::getline(std::cin, retval);
|
||||||
|
return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void add_history(const char* /*unused*/){}
|
||||||
|
void using_history(){}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *cast_module_symbol(std::vector<std::string> (*t_path)())
|
||||||
|
{
|
||||||
|
union cast_union
|
||||||
|
{
|
||||||
|
std::vector<std::string> (*in_ptr)();
|
||||||
|
void *out_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
cast_union c;
|
||||||
|
c.in_ptr = t_path;
|
||||||
|
return c.out_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> default_search_paths()
|
||||||
|
{
|
||||||
|
std::vector<std::string> paths;
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_NO_DYNLOAD
|
||||||
|
#ifdef CHAISCRIPT_WINDOWS // force no unicode
|
||||||
|
CHAR path[4096];
|
||||||
|
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
|
||||||
|
|
||||||
|
std::string exepath(path, size);
|
||||||
|
|
||||||
|
size_t lastslash = exepath.rfind('\\');
|
||||||
|
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
|
||||||
|
if (lastslash != std::string::npos)
|
||||||
|
{
|
||||||
|
paths.push_back(exepath.substr(0, lastslash));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secondtolastslash != std::string::npos)
|
||||||
|
{
|
||||||
|
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
std::string exepath;
|
||||||
|
|
||||||
|
std::vector<char> buf(2048);
|
||||||
|
ssize_t size = -1;
|
||||||
|
|
||||||
|
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0)
|
||||||
|
{
|
||||||
|
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exepath.empty())
|
||||||
|
{
|
||||||
|
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
|
||||||
|
{
|
||||||
|
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exepath.empty())
|
||||||
|
{
|
||||||
|
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
|
||||||
|
{
|
||||||
|
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exepath.empty())
|
||||||
|
{
|
||||||
|
Dl_info rInfo;
|
||||||
|
memset( &rInfo, 0, sizeof(rInfo) );
|
||||||
|
if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) {
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
exepath = std::string(rInfo.dli_fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t lastslash = exepath.rfind('/');
|
||||||
|
|
||||||
|
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
|
||||||
|
if (lastslash != std::string::npos)
|
||||||
|
{
|
||||||
|
paths.push_back(exepath.substr(0, lastslash+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secondtolastslash != std::string::npos)
|
||||||
|
{
|
||||||
|
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // ifndef CHAISCRIPT_NO_DYNLOAD
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
void help(int n) {
|
||||||
|
if ( n >= 0 ) {
|
||||||
|
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
|
||||||
|
std::cout << "Additionally, you can inspect the runtime system using:\n";
|
||||||
|
std::cout << " dump_system() - outputs all functions registered to the system\n";
|
||||||
|
std::cout << " dump_object(x) - dumps information about the given symbol\n";
|
||||||
|
} else {
|
||||||
|
std::cout << "usage : chai [option]+\n";
|
||||||
|
std::cout << "option:" << '\n';
|
||||||
|
std::cout << " -h | --help" << '\n';
|
||||||
|
std::cout << " -i | --interactive" << '\n';
|
||||||
|
std::cout << " -c | --command cmd" << '\n';
|
||||||
|
std::cout << " -v | --version" << '\n';
|
||||||
|
std::cout << " - --stdin" << '\n';
|
||||||
|
std::cout << " filepath" << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool throws_exception(const std::function<void ()> &f)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
f();
|
||||||
|
} catch (...) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
f();
|
||||||
|
} catch (const chaiscript::exception::eval_error &e) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("no exception throw");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_next_command() {
|
||||||
|
std::string retval("quit");
|
||||||
|
if ( ! std::cin.eof() ) {
|
||||||
|
char *input_raw = readline("eval> ");
|
||||||
|
if ( input_raw != nullptr ) {
|
||||||
|
add_history(input_raw);
|
||||||
|
|
||||||
|
std::string val(input_raw);
|
||||||
|
size_t pos = val.find_first_not_of("\t \n");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
val.erase(0, pos);
|
||||||
|
}
|
||||||
|
pos = val.find_last_not_of("\t \n");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
val.erase(pos+1, std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = val;
|
||||||
|
|
||||||
|
::free(input_raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( retval == "quit"
|
||||||
|
|| retval == "exit"
|
||||||
|
|| retval == "help"
|
||||||
|
|| retval == "version")
|
||||||
|
{
|
||||||
|
retval += "(0)";
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to wrap exit with our own because Clang has a hard time with
|
||||||
|
// function pointers to functions with special attributes (system exit being marked NORETURN)
|
||||||
|
void myexit(int return_val) {
|
||||||
|
exit(return_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void interactive(chaiscript::ChaiScript_Basic& chai)
|
||||||
|
{
|
||||||
|
using_history();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
std::string input = get_next_command();
|
||||||
|
try {
|
||||||
|
// evaluate input
|
||||||
|
chaiscript::Boxed_Value val = chai.eval(input);
|
||||||
|
|
||||||
|
//Then, we try to print the result of the evaluation to the user
|
||||||
|
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
|
||||||
|
try {
|
||||||
|
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
|
||||||
|
}
|
||||||
|
catch (...) {} //If we can't, do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const chaiscript::exception::eval_error &ee) {
|
||||||
|
std::cout << ee.what();
|
||||||
|
if ( !ee.call_stack.empty() ) {
|
||||||
|
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
|
||||||
|
}
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) {
|
||||||
|
std::cout << e.what();
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double now()
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
auto now = high_resolution_clock::now();
|
||||||
|
return duration_cast<duration<double>>(now.time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
chaiscript::ChaiScript chai;
|
||||||
|
|
||||||
|
chai.eval( R"chaiscript(
|
||||||
|
def assert_equal(x, y)
|
||||||
|
{
|
||||||
|
if (x == y)
|
||||||
|
{
|
||||||
|
// Passes
|
||||||
|
} else {
|
||||||
|
// Fails
|
||||||
|
print("assert_equal failure: got '" + to_string(y) + "' expected '" + to_string(x) + "'");
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def assert_false(f)
|
||||||
|
{
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
print("assert_false failure");
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def assert_true(f)
|
||||||
|
{
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
print("assert_true failure");
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def assert_not_equal(x, y)
|
||||||
|
{
|
||||||
|
if (!(x == y))
|
||||||
|
{
|
||||||
|
// Passes
|
||||||
|
} else {
|
||||||
|
// Fails
|
||||||
|
print("assert_not_equal failure: got " + to_string(y) + " which was not expected.");
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def assert_throws(desc, x)
|
||||||
|
{
|
||||||
|
if (throws_exception(x))
|
||||||
|
{
|
||||||
|
// Passes
|
||||||
|
} else {
|
||||||
|
// Fails
|
||||||
|
print("assert_throws failure, function did not throw exception: " + to_string(desc));
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
})chaiscript");
|
||||||
|
|
||||||
|
try {
|
||||||
|
chai.eval(std::string(reinterpret_cast<const char *>(data), size));
|
||||||
|
} catch (const chaiscript::exception::eval_error &ee) {
|
||||||
|
std::cout << ee.pretty_print();
|
||||||
|
std::cout << '\n';
|
||||||
|
} catch (const chaiscript::Boxed_Value &e) {
|
||||||
|
std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n';
|
||||||
|
} catch (const chaiscript::exception::load_module_error &e) {
|
||||||
|
std::cout << "Unhandled module load error\n" << e.what() << '\n';
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
std::cout << "unhandled unknown exception: " << e.what() << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
25
src/main.cpp
25
src/main.cpp
@ -71,6 +71,7 @@ std::vector<std::string> default_search_paths()
|
|||||||
{
|
{
|
||||||
std::vector<std::string> paths;
|
std::vector<std::string> paths;
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_NO_DYNLOAD
|
||||||
#ifdef CHAISCRIPT_WINDOWS // force no unicode
|
#ifdef CHAISCRIPT_WINDOWS // force no unicode
|
||||||
CHAR path[4096];
|
CHAR path[4096];
|
||||||
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
|
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
|
||||||
@ -140,6 +141,7 @@ std::vector<std::string> default_search_paths()
|
|||||||
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
|
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif // ifndef CHAISCRIPT_NO_DYNLOAD
|
||||||
|
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
@ -245,7 +247,7 @@ void interactive(chaiscript::ChaiScript_Basic& chai)
|
|||||||
catch (const chaiscript::exception::eval_error &ee) {
|
catch (const chaiscript::exception::eval_error &ee) {
|
||||||
std::cout << ee.what();
|
std::cout << ee.what();
|
||||||
if ( !ee.call_stack.empty() ) {
|
if ( !ee.call_stack.empty() ) {
|
||||||
std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
|
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
|
||||||
}
|
}
|
||||||
std::cout << '\n';
|
std::cout << '\n';
|
||||||
}
|
}
|
||||||
@ -306,6 +308,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
bool eval_error_ok = false;
|
bool eval_error_ok = false;
|
||||||
bool boxed_exception_ok = false;
|
bool boxed_exception_ok = false;
|
||||||
|
bool any_exception_ok = false;
|
||||||
|
|
||||||
for (int i = 0; i < argc; ++i) {
|
for (int i = 0; i < argc; ++i) {
|
||||||
if ( i == 0 && argc > 1 ) {
|
if ( i == 0 && argc > 1 ) {
|
||||||
@ -342,6 +345,9 @@ int main(int argc, char *argv[])
|
|||||||
} else if ( arg == "--exception" ) {
|
} else if ( arg == "--exception" ) {
|
||||||
boxed_exception_ok = true;
|
boxed_exception_ok = true;
|
||||||
continue;
|
continue;
|
||||||
|
} else if ( arg == "--any-exception" ) {
|
||||||
|
any_exception_ok = true;
|
||||||
|
continue;
|
||||||
} else if ( arg == "-i" || arg == "--interactive" ) {
|
} else if ( arg == "-i" || arg == "--interactive" ) {
|
||||||
mode = eInteractive ;
|
mode = eInteractive ;
|
||||||
} else if ( arg.find('-') == 0 ) {
|
} else if ( arg.find('-') == 0 ) {
|
||||||
@ -381,11 +387,18 @@ int main(int argc, char *argv[])
|
|||||||
catch (const chaiscript::exception::load_module_error &e) {
|
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 (std::exception &e) {
|
||||||
// catch (std::exception &e) {
|
std::cout << "Unhandled standard exception: " << e.what() << '\n';
|
||||||
// std::cout << e.what() << '\n';
|
if (!any_exception_ok) {
|
||||||
// return EXIT_FAILURE;
|
throw;
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
std::cout << "Unhandled unknown exception" << '\n';
|
||||||
|
if (!any_exception_ok) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
19076
unittests/catch.hpp
19076
unittests/catch.hpp
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,8 @@
|
|||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||||
|
// This one is necessary for the const return non-reference test
|
||||||
|
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -380,7 +382,7 @@ TEST_CASE("Set and restore chai state")
|
|||||||
// set state should have reverted the state of the functions and dropped
|
// set state should have reverted the state of the functions and dropped
|
||||||
// the 'myfun'
|
// the 'myfun'
|
||||||
|
|
||||||
CHECK_THROWS_AS(chai.eval<int>("myfun()"), chaiscript::exception::eval_error &);
|
CHECK_THROWS_AS(chai.eval<int>("myfun()"), chaiscript::exception::eval_error);
|
||||||
|
|
||||||
// set state should not affect the local variables
|
// set state should not affect the local variables
|
||||||
CHECK(chai.eval<int>("i") == 1);
|
CHECK(chai.eval<int>("i") == 1);
|
||||||
@ -388,7 +390,7 @@ TEST_CASE("Set and restore chai state")
|
|||||||
// After resetting the locals we expect the 'i' to be gone
|
// After resetting the locals we expect the 'i' to be gone
|
||||||
chai.set_locals(locals);
|
chai.set_locals(locals);
|
||||||
|
|
||||||
CHECK_THROWS_AS(chai.eval<int>("i"), chaiscript::exception::eval_error &);
|
CHECK_THROWS_AS(chai.eval<int>("i"), chaiscript::exception::eval_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -466,8 +468,8 @@ TEST_CASE("Simultaneous ChaiScript tests")
|
|||||||
CHECK(chai.eval<int>("do_something(" + std::to_string(i) + ")") == i + 2);
|
CHECK(chai.eval<int>("do_something(" + std::to_string(i) + ")") == i + 2);
|
||||||
CHECK(chai2.eval<int>("do_something_else(" + std::to_string(i) + ")") == i * 2);
|
CHECK(chai2.eval<int>("do_something_else(" + std::to_string(i) + ")") == i * 2);
|
||||||
|
|
||||||
CHECK_THROWS_AS(chai2.eval("do_something(1)"), chaiscript::exception::eval_error &);
|
CHECK_THROWS_AS(chai2.eval("do_something(1)"), chaiscript::exception::eval_error);
|
||||||
CHECK_THROWS_AS(chai2.eval("i"), chaiscript::exception::eval_error &);
|
CHECK_THROWS_AS(chai2.eval("i"), chaiscript::exception::eval_error);
|
||||||
CHECK_NOTHROW(chai2.eval("do_something_else(1)"));
|
CHECK_NOTHROW(chai2.eval("do_something_else(1)"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1280,3 +1282,54 @@ TEST_CASE("Test unicode matches C++")
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const int add_3(const int &i)
|
||||||
|
{
|
||||||
|
return i + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test returning by const non-reference")
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||||
|
// Note, C++ will not allow us to do this:
|
||||||
|
// chai.add(chaiscript::fun(&Reference_MyClass::x) , "x");
|
||||||
|
chai.add(chaiscript::fun(&add_3), "add_3");
|
||||||
|
auto v = chai.eval<int>("add_3(12)");
|
||||||
|
CHECK(v == 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct MyException : std::runtime_error
|
||||||
|
{
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
int value = 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
void throws_a_thing()
|
||||||
|
{
|
||||||
|
throw MyException("Hello World");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test throwing and catching custom exception")
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||||
|
chai.add(chaiscript::user_type<MyException>(), "MyException");
|
||||||
|
chai.add(chaiscript::base_class<std::runtime_error, MyException>()); // be sure to register base class relationship
|
||||||
|
chai.add(chaiscript::fun(&throws_a_thing), "throws_a_thing");
|
||||||
|
chai.add(chaiscript::fun(&MyException::value), "value");
|
||||||
|
|
||||||
|
const auto s = chai.eval<std::string>("fun(){ try { throws_a_thing(); } catch (MyException ex) { return ex.what(); } }()");
|
||||||
|
CHECK(s == "Hello World");
|
||||||
|
|
||||||
|
// this has an explicit clone to prevent returning a pointer to the `value` from inside of MyException
|
||||||
|
const auto i = chai.eval<int>("fun(){ try { throws_a_thing(); } catch (MyException ex) { var v = clone(ex.value); print(v); return v; } }()");
|
||||||
|
CHECK(i == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Test ability to get 'use' function from default construction")
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript chai;
|
||||||
|
const auto use_function = chai.eval<std::function<chaiscript::Boxed_Value (const std::string &)>>("use");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -40,3 +40,13 @@ assert_equal(res3[2], "member2")
|
|||||||
assert_true(__FILE__.find("execution_context.chai") != -1)
|
assert_true(__FILE__.find("execution_context.chai") != -1)
|
||||||
|
|
||||||
|
|
||||||
|
assert_equal(eval("__FILE__"), "__EVAL__")
|
||||||
|
assert_equal(eval("__LINE__"), 1)
|
||||||
|
assert_equal(eval("__FUNC__"), "NOT_IN_FUNCTION")
|
||||||
|
assert_equal(eval("__CLASS__"), "NOT_IN_CLASS")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
53
unittests/fuzz_unit_test.inc
Normal file
53
unittests/fuzz_unit_test.inc
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
def assert_equal(x, y)
|
||||||
|
{
|
||||||
|
if (x == y)
|
||||||
|
{
|
||||||
|
// Passes
|
||||||
|
} else {
|
||||||
|
// Fails
|
||||||
|
print("assert_equal failure: got '" + to_string(y) + "' expected '" + to_string(x) + "'");
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def assert_false(f)
|
||||||
|
{
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
print("assert_false failure");
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def assert_true(f)
|
||||||
|
{
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
print("assert_true failure");
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def assert_not_equal(x, y)
|
||||||
|
{
|
||||||
|
if (!(x == y))
|
||||||
|
{
|
||||||
|
// Passes
|
||||||
|
} else {
|
||||||
|
// Fails
|
||||||
|
print("assert_not_equal failure: got " + to_string(y) + " which was not expected.");
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def assert_throws(desc, x)
|
||||||
|
{
|
||||||
|
if (throws_exception(x))
|
||||||
|
{
|
||||||
|
// Passes
|
||||||
|
} else {
|
||||||
|
// Fails
|
||||||
|
print("assert_throws failure, function did not throw exception: " + to_string(desc));
|
||||||
|
// exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
BIN
unittests/fuzzy_tests-2017-07-20.tar.bz2
Normal file
BIN
unittests/fuzzy_tests-2017-07-20.tar.bz2
Normal file
Binary file not shown.
@ -1,12 +1,12 @@
|
|||||||
// Test global
|
// Test global
|
||||||
|
|
||||||
GLOBAL g = 3;
|
global g = 3;
|
||||||
assert_true(g == 3);
|
assert_true(g == 3);
|
||||||
|
|
||||||
var v := g;
|
var v := g;
|
||||||
assert_true(v == 3);
|
assert_true(v == 3);
|
||||||
|
|
||||||
GLOBAL g = 2;
|
global g = 2;
|
||||||
assert_true(g == 2);
|
assert_true(g == 2);
|
||||||
assert_true(v == 2);
|
assert_true(v == 2);
|
||||||
|
|
||||||
|
|||||||
5
unittests/json_14.chai
Normal file
5
unittests/json_14.chai
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
assert_equal(from_json("9.9e-02"), 9.9e-02)
|
||||||
|
assert_equal(from_json("-13.57e+3"), -13570.0)
|
||||||
|
assert_equal(from_json("1E-01"), 0.1)
|
||||||
|
assert_equal(from_json("-314159e-5"), -3.14159)
|
||||||
|
assert_equal(from_json("5e+04"), 50000)
|
||||||
19
unittests/json_15.chai
Normal file
19
unittests/json_15.chai
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Various to_json() tests
|
||||||
|
assert_equal(to_json(-13570), "-13570")
|
||||||
|
assert_equal(to_json(0.654321), "0.654321")
|
||||||
|
assert_equal(to_json("ChaiScript"), "\"ChaiScript\"")
|
||||||
|
assert_equal(to_json(true), "true")
|
||||||
|
assert_equal(to_json([1, 2, 3]), "[1, 2, 3]")
|
||||||
|
assert_equal(to_json(Vector()), "[]") // empty vector
|
||||||
|
assert_equal(to_json([]), "[]") // empty vector
|
||||||
|
assert_equal(to_json(Map()), "{\n\n}") // empty map
|
||||||
|
assert_equal(to_json(Dynamic_Object()), "{\n\n}") // empty object
|
||||||
|
|
||||||
|
// Round-trip JSON tests
|
||||||
|
assert_equal(from_json(to_json([])), [])
|
||||||
|
assert_equal(from_json(to_json(Map())), Map())
|
||||||
|
assert_equal(to_json(from_json("null")), "null")
|
||||||
|
assert_equal(from_json(to_json(["a": 5, "b": "stuff"])), ["a": 5, "b": "stuff"])
|
||||||
|
auto x = [3.5, true, false, "test", [], Vector(), Map()]
|
||||||
|
assert_equal(from_json(to_json(x)), x)
|
||||||
|
assert_equal(from_json(to_json(["aa\\zz":"aa\\zz"])), ["aa\\zz": "aa\\zz"])
|
||||||
@ -1 +1,3 @@
|
|||||||
assert_equal(from_json("100"), 100)
|
assert_equal(from_json("100"), 100)
|
||||||
|
assert_equal(from_json("-100"), -100)
|
||||||
|
assert_equal(to_json(4294967295), "4294967295")
|
||||||
|
|||||||
@ -1 +1,22 @@
|
|||||||
assert_equal(from_json("1.234"), 1.234)
|
assert_equal(from_json("1.234"), 1.234)
|
||||||
|
assert_equal(from_json("-1.234"), -1.234)
|
||||||
|
|
||||||
|
auto caught = false;
|
||||||
|
try {
|
||||||
|
from_json("-1-5.3");
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
assert_equal("JSON ERROR: Number: unexpected character '-'", e.what());
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
assert_equal(caught, true);
|
||||||
|
|
||||||
|
caught = false;
|
||||||
|
try {
|
||||||
|
from_json("-15.3.2");
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
assert_equal("JSON ERROR: Number: unexpected character '.'", e.what());
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
assert_equal(caught, true);
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
assert_equal(from_json("[1,2,3]"), [1,2,3])
|
assert_equal(from_json("[1,-2,3]"), [1,-2,3])
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||||
|
#include <chaiscript/chaiscript.hpp>
|
||||||
|
#endif
|
||||||
#include <chaiscript/chaiscript_basic.hpp>
|
#include <chaiscript/chaiscript_basic.hpp>
|
||||||
#include <chaiscript/language/chaiscript_parser.hpp>
|
#include <chaiscript/language/chaiscript_parser.hpp>
|
||||||
|
|
||||||
@ -57,18 +60,22 @@ int main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> modulepaths;
|
std::vector<std::string> modulepaths;
|
||||||
|
|
||||||
|
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||||
|
chaiscript::ChaiScript chai(/* unused */modulepaths, usepaths);
|
||||||
|
#else
|
||||||
modulepaths.push_back("");
|
modulepaths.push_back("");
|
||||||
if (modulepath)
|
if (modulepath)
|
||||||
{
|
{
|
||||||
modulepaths.push_back(modulepath);
|
modulepaths.push_back(modulepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// For this test we are going to load the dynamic stdlib
|
// For this test we are going to load the dynamic stdlib
|
||||||
// to make sure it continues to work
|
// to make sure it continues to work
|
||||||
chaiscript::ChaiScript_Basic chai(
|
chaiscript::ChaiScript_Basic chai(
|
||||||
std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>(),
|
std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>(),
|
||||||
modulepaths,usepaths);
|
modulepaths,usepaths);
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<std::shared_ptr<std::thread> > threads;
|
std::vector<std::shared_ptr<std::thread> > threads;
|
||||||
|
|
||||||
|
|||||||
7
unittests/namespaces.chai
Normal file
7
unittests/namespaces.chai
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace("math")
|
||||||
|
|
||||||
|
math.square = fun(x) { x * x }
|
||||||
|
math.sum_squares = fun(x, y) { math.square(x) + math.square(y) }
|
||||||
|
|
||||||
|
assert_equal(16, math.square(4))
|
||||||
|
assert_equal(29, math.sum_squares(2, 5))
|
||||||
9
unittests/namespaces_nested_copy.chai
Normal file
9
unittests/namespaces_nested_copy.chai
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace("parent")
|
||||||
|
namespace("child")
|
||||||
|
|
||||||
|
child.x = 3.0
|
||||||
|
parent.child = child
|
||||||
|
parent.child.x = 5.0
|
||||||
|
|
||||||
|
assert_equal(3.0, child.x)
|
||||||
|
assert_equal(5.0, parent.child.x)
|
||||||
@ -18,4 +18,9 @@ for (x : retro(range([1,2,3,4]))) {
|
|||||||
|
|
||||||
assert_true(result > .6 && result < .7);
|
assert_true(result > .6 && result < .7);
|
||||||
|
|
||||||
|
var m=["a": ["t": "val"], "b": ["t": "val"]];
|
||||||
|
|
||||||
|
for (i : m) {
|
||||||
|
var &ref=i.second["t"];
|
||||||
|
print(ref);
|
||||||
|
}
|
||||||
|
|||||||
11
unittests/static_chaiscript.cpp
Normal file
11
unittests/static_chaiscript.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
#define CHAISCRIPT_NO_THREADS
|
||||||
|
|
||||||
|
/// ChaiScript as a static is unsupported with thread support enabled
|
||||||
|
///
|
||||||
|
|
||||||
|
#include <chaiscript/chaiscript.hpp>
|
||||||
|
|
||||||
|
static chaiscript::ChaiScript chai;
|
||||||
|
|
||||||
|
int main() {}
|
||||||
Loading…
x
Reference in New Issue
Block a user