Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop

This commit is contained in:
Stephen Berry 2017-09-05 12:13:29 -05:00
commit a9fc1d492e
81 changed files with 3446 additions and 1950 deletions

0
.buckconfig Normal file
View File

5
.gitignore vendored Normal file
View File

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

View File

@ -1,33 +1,67 @@
language: cpp language: cpp
compiler:
- gcc
env:
matrix:
- GCC_VER="4.9"
- GCC_VER="5"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.9
- g++-5
- g++-6
coverity_scan:
project:
name: "ChaiScript/ChaiScript"
description: "Build submitted via Travis CI"
notification_email: jason@emptycrate.com
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
build_command: "cmake --build . -- -j2"
branch_pattern: coverity_scan
matrix:
include:
- os: linux
sudo: false
env: GCC_VER="4.9"
compiler: gcc
- os: linux
sudo: false
env: GCC_VER="4.9" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
compiler: gcc
- os: linux
sudo: false
env: GCC_VER="5" CPPCHECK=1 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
- os: osx
compiler: clang
osx_image: xcode8
- os: osx
compiler: clang
osx_image: xcode8
env: CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
env:
global: global:
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU= - secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
- secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM=" - secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM="
before_install: before_install:
- export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" - if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
- if [ "$GCC_VER" = "5" ]; then export COVERAGE=1 CPPCHECK=1; fi - pip install --user cpp-coveralls
- if [ ${COVERAGE} = 1 ]; then export FUZZY_CMD="-D RUN_FUZZY_TESTS:BOOL=TRUE"; fi
- sudo pip install cpp-coveralls
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
- sudo apt-get update
- sudo apt-get install -qq g++-$GCC_VER
script: script:
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $FUZZY_CMD . ; fi - cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS .
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -j2 ; fi - cmake --build . -- -j2
- make test - 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
notifications: notifications:
@ -42,15 +76,3 @@ notifications:
on_success: change # options: [always|never|change] default: always on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always
on_start: false # default: false on_start: false # default: false
addons:
coverity_scan:
project:
name: "ChaiScript/ChaiScript"
description: "Build submitted via Travis CI"
notification_email: jason@emptycrate.com
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
build_command: "cmake --build . -- -j2"
branch_pattern: coverity_scan

11
BUCK Normal file
View 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',
],
)

View File

@ -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,12 +151,20 @@ 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)
@ -178,7 +188,7 @@ 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)
@ -196,12 +206,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 +231,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 +314,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 +428,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})

View File

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

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

View File

@ -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
@ -91,6 +94,49 @@ chai.add(chaiscript::user_type<MyClass>(), "MyClass");
User defined type conversions are possible, defined in either script or in C++. User defined type conversions are possible, defined in either script or in C++.
### ChaiScript Defined Conversions
Function objects (including lambdas) can be used to add type conversions
from inside of ChaiScript:
```
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
```
### C++ Defined Conversions
Invoking a C++ type conversion possible with `static_cast`
```
chai.add(chaiscript::type_conversion<T, bool>());
```
Calling a user defined type conversion that takes a lambda
```
chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ }));
```
### Class Hierarchies
If you want objects to be convertable between base and derived classes, you must tell ChaiScritp about the relationship.
```
chai.add(chaiscript::base_class<Base, Derived>());
```
If you have multiple classes in your inheritance graph, you will probably want to tell ChaiScript about all relationships.
```
chai.add(chaiscript::base_class<Base, Derived>());
chai.add(chaiscript::base_class<Derived, MoreDerived>());
chai.add(chaiscript::base_class<Base, MoreDerived>());
```
### Helpers
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition: A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
``` ```
@ -104,6 +150,7 @@ chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
``` ```
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>` This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
## Adding Objects ## Adding Objects
@ -211,7 +258,7 @@ Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you
```cpp ```cpp
// ok this is supported, you can register it with chaiscript engine // ok this is supported, you can register it with chaiscript engine
void nullify_shared_ptr(std::shared_ptr<int> &t) { void nullify_shared_ptr(std::shared_ptr<int> &t) {
t == nullptr t = nullptr
} }
``` ```
@ -318,6 +365,15 @@ while (some_condition()) { /* do something */ }
for (x : [1,2,3]) { print(i); } for (x : [1,2,3]) { print(i); }
``` ```
Each of the loop styles can be broken using the `break` statement. For example:
```
while (some_condition()) {
/* do something */
if (another_condition()) { break; }
}
```
## Conditionals ## Conditionals
``` ```
@ -502,9 +558,33 @@ the contained function.
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins. If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
## Context
* `__LINE__` Current file line number
* `__FILE__` Full path of current file
* `__CLASS__` Name of current class
* `__FUNC__` Mame of current function
# Built In Functions # Built In Functions
## Disabling Built-Ins
When constructing a ChaiScript object, a vector of parameters can be passed in to disable or enable various built-in methods.
Current options:
```
enum class Options
{
Load_Modules,
No_Load_Modules,
External_Scripts,
No_External_Scripts
};
```
## Evaluation ## Evaluation
``` ```
@ -516,4 +596,7 @@ use("filename") // evals file exactly once and returns value of last statement
Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor
## JSON
* `from_json` converts a JSON string into its strongly typed (map, vector, int, double, string) representations
* `to_json` converts a ChaiScript object (either a `Object` or one of map, vector, int, double, string) tree into its JSON string representation

View File

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

View File

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

View File

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

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HPP_ #ifndef CHAISCRIPT_HPP_
#define CHAISCRIPT_HPP_ #define CHAISCRIPT_HPP_
@ -65,7 +69,7 @@
/// int main() /// int main()
/// { /// {
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(&function, "function"); /// chai.add(chaiscript::fun(&function), "function");
/// ///
/// double d = chai.eval<double>("function(3, 4.75);"); /// double d = chai.eval<double>("function(3, 4.75);");
/// } /// }
@ -827,11 +831,12 @@ 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 = 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>>(),
t_modulepaths, t_usepaths) t_modulepaths, t_usepaths, t_opts)
{ {
} }
}; };

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_BASIC_HPP_ #ifndef CHAISCRIPT_BASIC_HPP_

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_ #ifndef CHAISCRIPT_DEFINES_HPP_
@ -9,9 +9,13 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#define CHAISCRIPT_STRINGIZE(x) "" #x #define CHAISCRIPT_STRINGIZE(x) "" #x
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE(_MSC_FULL_VER) #define CHAISCRIPT_STRINGIZE_EXPANDED(x) CHAISCRIPT_STRINGIZE(x)
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE_EXPANDED(_MSC_FULL_VER)
#define CHAISCRIPT_MSVC _MSC_VER #define CHAISCRIPT_MSVC _MSC_VER
#define CHAISCRIPT_HAS_DECLSPEC #define CHAISCRIPT_HAS_DECLSPEC
static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required");
#else #else
#define CHAISCRIPT_COMPILER_VERSION __VERSION__ #define CHAISCRIPT_COMPILER_VERSION __VERSION__
#endif #endif
@ -44,10 +48,6 @@
#endif #endif
#endif #endif
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP))
/// \todo Make this support other compilers when possible
#define CHAISCRIPT_HAS_THREAD_LOCAL
#endif
#if defined(__llvm__) #if defined(__llvm__)
#define CHAISCRIPT_CLANG #define CHAISCRIPT_CLANG
@ -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()
{ {
@ -145,7 +155,7 @@ namespace chaiscript {
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;
for (char c = *t_str; (c = *t_str); ++t_str) { for (char c = *t_str; (c = *t_str) != 0; ++t_str) {
if (c < '0' || c > '9') { if (c < '0' || c > '9') {
return t; return t;
} }
@ -206,6 +216,22 @@ namespace chaiscript {
return parse_num<T>(t_str.c_str()); return parse_num<T>(t_str.c_str());
} }
enum class Options
{
No_Load_Modules,
Load_Modules,
No_External_Scripts,
External_Scripts
};
static inline std::vector<Options> default_options()
{
#ifdef CHAISCRIPT_NO_DYNLOAD
return {Options::No_Load_Modules, Options::External_Scripts};
#else
return {Options::Load_Modules, Options::External_Scripts};
#endif
}
} }
#endif #endif

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_THREADING_HPP_ #ifndef CHAISCRIPT_THREADING_HPP_
#define CHAISCRIPT_THREADING_HPP_ #define CHAISCRIPT_THREADING_HPP_
@ -57,118 +61,54 @@ namespace chaiscript
using std::recursive_mutex; using std::recursive_mutex;
#ifdef CHAISCRIPT_HAS_THREAD_LOCAL
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If /// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from. /// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
template<typename T> template<typename T>
class Thread_Storage class Thread_Storage
{ {
public: public:
Thread_Storage() = default;
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;
} }
}; };
#else
#pragma message ("Threading without thread_local support is not well supported.")
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
///
/// This version is used if the compiler does not support thread_local
template<typename T>
class Thread_Storage
{
public:
explicit Thread_Storage(void *)
{
}
inline const T *operator->() const
{
return get_tls().get();
}
inline const T &operator*() const
{
return *get_tls();
}
inline T *operator->()
{
return get_tls().get();
}
inline T &operator*()
{
return *get_tls();
}
private:
/// \todo this leaks thread instances. It needs to be culled from time to time
std::shared_ptr<T> get_tls() const
{
unique_lock<mutex> lock(m_mutex);
const auto id = std::this_thread::get_id();
auto itr = m_instances.find(id);
if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(std::make_shared<T>());
m_instances.insert(std::make_pair(id, new_instance));
return new_instance;
}
mutable mutex m_mutex;
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
};
#endif // threading enabled but no tls
#else // threading disabled #else // threading disabled
template<typename T> template<typename T>
class unique_lock class unique_lock
@ -204,7 +144,7 @@ namespace chaiscript
class Thread_Storage class Thread_Storage
{ {
public: public:
explicit Thread_Storage(void *) explicit Thread_Storage()
{ {
} }

View File

@ -72,7 +72,7 @@ namespace chaiscript {
{ {
} }
virtual void *data() override void *data() override
{ {
return &m_data; return &m_data;
} }

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_ #define CHAISCRIPT_BAD_BOXED_CAST_HPP_
@ -31,12 +35,12 @@ namespace chaiscript
public: public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
std::string t_what) noexcept std::string t_what) noexcept
: from(std::move(t_from)), to(&t_to), m_what(std::move(t_what)) : from(t_from), to(&t_to), m_what(std::move(t_what))
{ {
} }
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name()) : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
{ {
} }
@ -46,10 +50,10 @@ namespace chaiscript
} }
bad_boxed_cast(const bad_boxed_cast &) = default; bad_boxed_cast(const bad_boxed_cast &) = default;
virtual ~bad_boxed_cast() noexcept = default; ~bad_boxed_cast() noexcept override = default;
/// \brief Description of what error occurred /// \brief Description of what error occurred
virtual const char * what() const noexcept override const char * what() const noexcept override
{ {
return m_what.c_str(); return m_what.c_str();
} }

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BIND_FIRST_HPP_ #ifndef CHAISCRIPT_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_ #define CHAISCRIPT_BIND_FIRST_HPP_

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_ #ifndef CHAISCRIPT_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_ #define CHAISCRIPT_BOOTSTRAP_HPP_
@ -301,13 +305,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 {
@ -541,7 +545,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"} }
); );
@ -570,7 +574,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"}
} }

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/// \file /// \file
/// This file contains utility functions for registration of STL container /// This file contains utility functions for registration of STL container
/// classes. The methodology used is based on the SGI STL concepts. /// classes. The methodology used is based on the SGI STL concepts.
@ -37,7 +41,7 @@ namespace chaiscript
/// Bidir_Range, based on the D concept of ranges. /// Bidir_Range, based on the D concept of ranges.
/// \todo Update the Range code to base its capabilities on /// \todo Update the Range code to base its capabilities on
/// the user_typetraits of the iterator passed in /// the user_typetraits of the iterator passed in
template<typename Container> template<typename Container, typename IterType>
struct Bidir_Range struct Bidir_Range
{ {
typedef Container container_type; typedef Container container_type;
@ -79,64 +83,6 @@ namespace chaiscript
return (*m_begin); return (*m_begin);
} }
decltype(auto) back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
typename Container::iterator pos = m_end;
--pos;
return (*(pos));
}
typename Container::iterator m_begin;
typename Container::iterator m_end;
};
template<typename Container>
struct Const_Bidir_Range
{
typedef const Container container_type;
typedef typename std::iterator_traits<typename Container::const_iterator>::reference const_reference_type;
Const_Bidir_Range(const Container &c)
: m_begin(c.begin()), m_end(c.end())
{
}
bool empty() const
{
return m_begin == m_end;
}
void pop_front()
{
if (empty())
{
throw std::range_error("Range empty");
}
++m_begin;
}
void pop_back()
{
if (empty())
{
throw std::range_error("Range empty");
}
--m_end;
}
decltype(auto) front() const
{
if (empty())
{
throw std::range_error("Range empty");
}
return (*m_begin);
}
decltype(auto) back() const decltype(auto) back() const
{ {
if (empty()) if (empty())
@ -148,8 +94,8 @@ namespace chaiscript
return (*(pos)); return (*(pos));
} }
typename Container::const_iterator m_begin; IterType m_begin;
typename Container::const_iterator m_end; IterType m_end;
}; };
namespace detail { namespace detail {
@ -229,8 +175,8 @@ namespace chaiscript
template<typename ContainerType> template<typename ContainerType>
void input_range_type(const std::string &type, Module& m) void input_range_type(const std::string &type, Module& m)
{ {
detail::input_range_type_impl<Bidir_Range<ContainerType> >(type,m); detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator> >(type,m);
detail::input_range_type_impl<Const_Bidir_Range<ContainerType> >("Const_" + type, m); detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator> >("Const_" + type,m);
} }
template<typename ContainerType> template<typename ContainerType>
ModulePtr input_range_type(const std::string &type) ModulePtr input_range_type(const std::string &type)
@ -389,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 &);
@ -434,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{
@ -631,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);

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_ #define CHAISCRIPT_BOXED_CAST_HPP_

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
@ -25,7 +29,7 @@ namespace chaiscript
template<typename T> template<typename T>
T* throw_if_null(T *t) T* throw_if_null(T *t)
{ {
if (t) return t; if (t) { return t; }
throw std::runtime_error("Attempted to dereference null Boxed_Value"); throw std::runtime_error("Attempted to dereference null Boxed_Value");
} }
@ -135,6 +139,50 @@ namespace chaiscript
} }
}; };
/// Cast_Helper_Inner for casting to a && type
template<typename Result>
struct Cast_Helper_Inner<Result &&>
{
static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &&>
{
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &>
{
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<const std::unique_ptr<Result> &>
{
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type /// Cast_Helper_Inner for casting to a std::shared_ptr<> type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<std::shared_ptr<Result> >

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_ #ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_
#define CHAISCRIPT_BOXED_NUMERIC_HPP_ #define CHAISCRIPT_BOXED_NUMERIC_HPP_
@ -28,9 +31,9 @@ namespace chaiscript
{ {
struct arithmetic_error : std::runtime_error struct arithmetic_error : std::runtime_error
{ {
arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {} explicit arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {}
arithmetic_error(const arithmetic_error &) = default; arithmetic_error(const arithmetic_error &) = default;
virtual ~arithmetic_error() noexcept = default; ~arithmetic_error() noexcept override = default;
}; };
} }
} }
@ -585,6 +588,67 @@ namespace chaiscript
} }
template<typename Source, typename Target>
static void check_type()
{
#ifdef CHAISCRIPT_MSVC
// MSVC complains about this being redundant / tautologica l
#pragma warning(push)
#pragma warning(disable : 4127 6287)
#endif
if (sizeof(Source) != sizeof(Target)
|| std::is_signed<Source>() != std::is_signed<Target>()
|| std::is_floating_point<Source>() != std::is_floating_point<Target>())
{
throw chaiscript::detail::exception::bad_any_cast();
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
template<typename Target> Target get_as_checked() const
{
switch (get_common_type(bv)) {
case Common_Types::t_int32:
check_type<int32_t, Target>();
return get_as_aux<Target, int32_t>(bv);
case Common_Types::t_uint8:
check_type<uint8_t, Target>();
return get_as_aux<Target, uint8_t>(bv);
case Common_Types::t_int8:
check_type<int8_t, Target>();
return get_as_aux<Target, int8_t>(bv);
case Common_Types::t_uint16:
check_type<uint16_t, Target>();
return get_as_aux<Target, uint16_t>(bv);
case Common_Types::t_int16:
check_type<int16_t, Target>();
return get_as_aux<Target, int16_t>(bv);
case Common_Types::t_uint32:
check_type<uint32_t, Target>();
return get_as_aux<Target, uint32_t>(bv);
case Common_Types::t_uint64:
check_type<uint64_t, Target>();
return get_as_aux<Target, uint64_t>(bv);
case Common_Types::t_int64:
check_type<int64_t, Target>();
return get_as_aux<Target, int64_t>(bv);
case Common_Types::t_double:
check_type<double, Target>();
return get_as_aux<Target, double>(bv);
case Common_Types::t_float:
check_type<float, Target>();
return get_as_aux<Target, float>(bv);
case Common_Types::t_long_double:
check_type<long double, Target>();
return get_as_aux<Target, long double>(bv);
}
throw chaiscript::detail::exception::bad_any_cast();
}
template<typename Target> Target get_as() const template<typename Target> Target get_as() const
{ {
switch (get_common_type(bv)) { switch (get_common_type(bv)) {

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_ #ifndef CHAISCRIPT_BOXED_VALUE_HPP_
#define CHAISCRIPT_BOXED_VALUE_HPP_ #define CHAISCRIPT_BOXED_VALUE_HPP_
@ -35,11 +39,11 @@ namespace chaiscript
{ {
Data(const Type_Info &ti, Data(const Type_Info &ti,
chaiscript::detail::Any to, chaiscript::detail::Any to,
bool tr, bool is_ref,
const void *t_void_ptr, const void *t_void_ptr,
bool t_return_value) bool t_return_value)
: m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr), : m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
m_is_ref(tr), m_return_value(t_return_value) m_is_ref(is_ref), m_return_value(t_return_value)
{ {
} }
@ -54,7 +58,7 @@ namespace chaiscript
if (rhs.m_attrs) if (rhs.m_attrs)
{ {
m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*rhs.m_attrs)); m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
} }
return *this; return *this;
@ -119,6 +123,8 @@ namespace chaiscript
); );
} }
template<typename T> template<typename T>
static auto get(T *t, bool t_return_value) static auto get(T *t, bool t_return_value)
{ {
@ -145,6 +151,19 @@ namespace chaiscript
); );
} }
template<typename T>
static auto get(std::unique_ptr<T> &&obj, bool t_return_value)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
true,
ptr,
t_return_value
);
}
template<typename T> template<typename T>
static auto get(T t, bool t_return_value) static auto get(T t, bool t_return_value)
{ {
@ -236,8 +255,9 @@ namespace chaiscript
~Sentinel() ~Sentinel()
{ {
// save new pointer data // save new pointer data
m_data.get().m_data_ptr = m_ptr.get().get(); const auto ptr_ = m_ptr.get().get();
m_data.get().m_const_data_ptr = m_ptr.get().get(); m_data.get().m_data_ptr = ptr_;
m_data.get().m_const_data_ptr = ptr_;
} }
Sentinel& operator=(Sentinel&&s) = default; Sentinel& operator=(Sentinel&&s) = default;
@ -302,7 +322,7 @@ namespace chaiscript
{ {
if (!m_data->m_attrs) if (!m_data->m_attrs)
{ {
m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>()); m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
} }
auto &attr = (*m_data->m_attrs)[t_name]; auto &attr = (*m_data->m_attrs)[t_name];
@ -319,7 +339,7 @@ namespace chaiscript
{ {
if (t_obj.m_data->m_attrs) if (t_obj.m_data->m_attrs)
{ {
m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*t_obj.m_data->m_attrs)); m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
} }
return *this; return *this;
} }
@ -342,8 +362,8 @@ namespace chaiscript
// necessary to avoid hitting the templated && constructor of Boxed_Value // necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction{}; struct Internal_Construction{};
Boxed_Value(const std::shared_ptr<Data> &t_data, Internal_Construction) Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
: m_data(t_data) { : m_data(std::move(t_data)) {
} }
std::shared_ptr<Data> m_data = Object_Data::get(); std::shared_ptr<Data> m_data = Object_Data::get();

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_ #ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
@ -25,7 +25,7 @@ namespace chaiscript {
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename ... Param>
struct Const_Caller struct Const_Caller
{ {
Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {} explicit Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
template<typename ... Inner> template<typename ... Inner>
Ret operator()(const Class &o, Inner&& ... inner) const { Ret operator()(const Class &o, Inner&& ... inner) const {
@ -38,7 +38,7 @@ namespace chaiscript {
template<typename Ret, typename ... Param> template<typename Ret, typename ... Param>
struct Fun_Caller struct Fun_Caller
{ {
Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {} explicit Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
template<typename ... Inner> template<typename ... Inner>
Ret operator()(Inner&& ... inner) const { Ret operator()(Inner&& ... inner) const {
@ -51,7 +51,7 @@ namespace chaiscript {
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename ... Param>
struct Caller struct Caller
{ {
Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {} explicit Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
template<typename ... Inner> template<typename ... Inner>
Ret operator()(Class &o, Inner&& ... inner) const { Ret operator()(Class &o, Inner&& ... inner) const {

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DISPATCHKIT_HPP_ #ifndef CHAISCRIPT_DISPATCHKIT_HPP_
#define CHAISCRIPT_DISPATCHKIT_HPP_ #define CHAISCRIPT_DISPATCHKIT_HPP_
@ -67,7 +71,7 @@ namespace chaiscript
reserved_word_error(const reserved_word_error &) = default; reserved_word_error(const reserved_word_error &) = default;
virtual ~reserved_word_error() noexcept = default; ~reserved_word_error() noexcept override = default;
std::string word() const std::string word() const
{ {
@ -89,7 +93,7 @@ namespace chaiscript
illegal_name_error(const illegal_name_error &) = default; illegal_name_error(const illegal_name_error &) = default;
virtual ~illegal_name_error() noexcept = default; ~illegal_name_error() noexcept override = default;
std::string name() const std::string name() const
{ {
@ -112,7 +116,7 @@ namespace chaiscript
name_conflict_error(const name_conflict_error &) = default; name_conflict_error(const name_conflict_error &) = default;
virtual ~name_conflict_error() noexcept = default; ~name_conflict_error() noexcept override = default;
std::string name() const std::string name() const
{ {
@ -135,7 +139,7 @@ namespace chaiscript
} }
global_non_const(const global_non_const &) = default; global_non_const(const global_non_const &) = default;
virtual ~global_non_const() noexcept = default; ~global_non_const() noexcept override = default;
}; };
} }
@ -147,7 +151,7 @@ namespace chaiscript
public: public:
Module &add(Type_Info ti, std::string name) Module &add(Type_Info ti, std::string name)
{ {
m_typeinfos.emplace_back(std::move(ti), std::move(name)); m_typeinfos.emplace_back(ti, std::move(name));
return *this; return *this;
} }
@ -266,7 +270,7 @@ namespace chaiscript
class Dispatch_Function final : public dispatch::Proxy_Function_Base class Dispatch_Function final : public dispatch::Proxy_Function_Base
{ {
public: public:
Dispatch_Function(std::vector<Proxy_Function> t_funcs) explicit Dispatch_Function(std::vector<Proxy_Function> t_funcs)
: Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)), : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)),
m_funcs(std::move(t_funcs)) m_funcs(std::move(t_funcs))
{ {
@ -356,7 +360,7 @@ namespace chaiscript
++begin; ++begin;
} }
assert(type_infos.size() > 0 && " type_info vector size is < 0, this is only possible if something else is broken"); assert(!type_infos.empty() && " type_info vector size is < 0, this is only possible if something else is broken");
if (size_mismatch) if (size_mismatch)
{ {
@ -447,8 +451,8 @@ namespace chaiscript
Type_Name_Map m_types; Type_Name_Map m_types;
}; };
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)
{ {
} }
@ -681,7 +685,7 @@ namespace chaiscript
} }
t_loc = static_cast<uint_fast32_t>(Loc::located); t_loc = static_cast<uint_fast32_t>(Loc::located);
} else if (loc & static_cast<uint_fast32_t>(Loc::is_local)) { } else if ((loc & static_cast<uint_fast32_t>(Loc::is_local)) != 0u) {
auto &stack = get_stack_data(t_holder); auto &stack = get_stack_data(t_holder);
return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second; return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second;
@ -698,9 +702,9 @@ namespace chaiscript
// no? is it a function object? // no? is it a function object?
auto obj = get_function_object_int(name, loc); auto obj = get_function_object_int(name, loc);
if (obj.first != loc) t_loc = uint_fast32_t(obj.first); if (obj.first != loc) { t_loc = uint_fast32_t(obj.first); }
return obj.second;
return obj.second;
} }
@ -763,7 +767,10 @@ namespace chaiscript
{ {
uint_fast32_t method_missing_loc = m_method_missing_loc; uint_fast32_t method_missing_loc = m_method_missing_loc;
auto method_missing_funs = get_function("method_missing", method_missing_loc); auto method_missing_funs = get_function("method_missing", method_missing_loc);
if (method_missing_funs.first != method_missing_loc) m_method_missing_loc = uint_fast32_t(method_missing_funs.first); if (method_missing_funs.first != method_missing_loc) {
m_method_missing_loc = uint_fast32_t(method_missing_funs.first);
}
return std::move(method_missing_funs.second); return std::move(method_missing_funs.second);
} }
@ -954,7 +961,7 @@ namespace chaiscript
{ {
uint_fast32_t loc = t_loc; uint_fast32_t loc = t_loc;
const auto funs = get_function(t_name, loc); const auto funs = get_function(t_name, loc);
if (funs.first != loc) t_loc = uint_fast32_t(funs.first); if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); }
const auto do_attribute_call = const auto do_attribute_call =
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value [this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value
@ -977,14 +984,21 @@ namespace chaiscript
This_Foist fi(*this, l_params.front()); This_Foist fi(*this, l_params.front());
auto func = boxed_cast<const dispatch::Proxy_Function_Base *>(bv);
try { try {
return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions); auto func = boxed_cast<const dispatch::Proxy_Function_Base *>(bv);
try {
return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions);
} catch (const chaiscript::exception::bad_boxed_cast &) {
} catch (const chaiscript::exception::arity_error &) {
} catch (const chaiscript::exception::guard_error &) {
}
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()},
std::vector<Const_Proxy_Function>{boxed_cast<Const_Proxy_Function>(bv)});
} catch (const chaiscript::exception::bad_boxed_cast &) { } catch (const chaiscript::exception::bad_boxed_cast &) {
} catch (const chaiscript::exception::arity_error &) { // unable to convert bv into a Proxy_Function_Base
} catch (const chaiscript::exception::guard_error &) { throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()},
std::vector<Const_Proxy_Function>(l_funs.begin(), l_funs.end()));
} }
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector<Const_Proxy_Function>{boxed_cast<Const_Proxy_Function>(bv)});
} else { } else {
return bv; return bv;
} }
@ -1067,7 +1081,8 @@ namespace chaiscript
{ {
uint_fast32_t loc = t_loc; uint_fast32_t loc = t_loc;
const auto funs = get_function(t_name, loc); const auto funs = get_function(t_name, loc);
if (funs.first != loc) t_loc = uint_fast32_t(funs.first); if (funs.first != loc) { t_loc = uint_fast32_t(funs.first);
}
return dispatch::dispatch(*funs.second, params, t_conversions); return dispatch::dispatch(*funs.second, params, t_conversions);
} }
@ -1191,7 +1206,7 @@ namespace chaiscript
static void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params) static void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params)
{ {
t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(t_params)); t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params);
} }
static void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params) static void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params)
@ -1209,7 +1224,7 @@ namespace chaiscript
void save_function_params(std::initializer_list<Boxed_Value> t_params) void save_function_params(std::initializer_list<Boxed_Value> t_params)
{ {
save_function_params(*m_stack_holder, std::move(t_params)); save_function_params(*m_stack_holder, t_params);
} }
void save_function_params(std::vector<Boxed_Value> &&t_params) void save_function_params(std::vector<Boxed_Value> &&t_params)
@ -1505,7 +1520,7 @@ namespace chaiscript
class Dispatch_State class Dispatch_State
{ {
public: public:
Dispatch_State(Dispatch_Engine &t_engine) explicit Dispatch_State(Dispatch_Engine &t_engine)
: m_engine(t_engine), : m_engine(t_engine),
m_stack_holder(t_engine.get_stack_holder()), m_stack_holder(t_engine.get_stack_holder()),
m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves()) m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves())

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
@ -25,7 +29,7 @@ namespace chaiscript
namespace dispatch namespace dispatch
{ {
struct option_explicit_set : std::runtime_error { struct option_explicit_set : std::runtime_error {
option_explicit_set(const std::string &t_param_name) explicit option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") : std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
{ {
@ -33,13 +37,13 @@ namespace chaiscript
option_explicit_set(const option_explicit_set &) = default; option_explicit_set(const option_explicit_set &) = default;
virtual ~option_explicit_set() noexcept = default; ~option_explicit_set() noexcept override = default;
}; };
class Dynamic_Object class Dynamic_Object
{ {
public: public:
Dynamic_Object(std::string t_type_name) explicit Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name)), m_option_explicit(false) : m_type_name(std::move(t_type_name)), m_option_explicit(false)
{ {
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
@ -99,7 +99,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{ {
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{ {
@ -109,7 +109,7 @@ namespace chaiscript
} }
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override
{ {
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
} }
@ -151,7 +151,7 @@ namespace chaiscript
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name, bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
{ {
if (bvs.size() > 0) if (!bvs.empty())
{ {
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions); return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else { } else {
@ -202,7 +202,7 @@ namespace chaiscript
bool operator==(const Proxy_Function_Base &f) const override bool operator==(const Proxy_Function_Base &f) const override
{ {
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f); const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_HPP_

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
@ -33,7 +37,7 @@ namespace chaiscript
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{ {
if (t_conversions) { if (t_conversions != nullptr) {
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions); return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions);
} else { } else {
Type_Conversions conv; Type_Conversions conv;
@ -52,7 +56,7 @@ namespace chaiscript
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{ {
if (t_conversions) { if (t_conversions != nullptr) {
return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>(); return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>();
} else { } else {
Type_Conversions conv; Type_Conversions conv;
@ -72,7 +76,7 @@ namespace chaiscript
static void call(const std::vector<Const_Proxy_Function> &t_funcs, static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{ {
if (t_conversions) { if (t_conversions != nullptr) {
dispatch::dispatch(t_funcs, params, *t_conversions); dispatch::dispatch(t_funcs, params, *t_conversions);
} else { } else {
Type_Conversions conv; Type_Conversions conv;

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_ #ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
#define CHAISCRIPT_HANDLE_RETURN_HPP_ #define CHAISCRIPT_HANDLE_RETURN_HPP_
@ -27,9 +31,7 @@ namespace chaiscript
namespace detail namespace detail
{ {
/** /// Used internally for handling a return value from a Proxy_Function call
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret> template<typename Ret>
struct Handle_Return struct Handle_Return
{ {
@ -155,6 +157,18 @@ namespace chaiscript
{ {
}; };
template<typename Ret>
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &>
{
static Boxed_Value handle(std::unique_ptr<Ret> &&r)
{
return Boxed_Value(std::move(r), true);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret &> struct Handle_Return<const Ret &>
{ {
@ -167,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));
} }
}; };

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_OPERATORS_HPP_ #ifndef CHAISCRIPT_OPERATORS_HPP_
#define CHAISCRIPT_OPERATORS_HPP_ #define CHAISCRIPT_OPERATORS_HPP_

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_HPP_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_HPP_
@ -38,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
{ {
@ -53,7 +56,7 @@ namespace chaiscript
m_doti(user_type<Dynamic_Object>()) m_doti(user_type<Dynamic_Object>())
{} {}
Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types) explicit Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
: m_types(std::move(t_types)), : m_types(std::move(t_types)),
m_has_types(false), m_has_types(false),
m_doti(user_type<Dynamic_Object>()) m_doti(user_type<Dynamic_Object>())
@ -63,7 +66,7 @@ namespace chaiscript
void push_front(std::string t_name, Type_Info t_ti) void push_front(std::string t_name, Type_Info t_ti)
{ {
m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti)); m_types.emplace(m_types.begin(), std::move(t_name), t_ti);
update_has_types(); update_has_types();
} }
@ -72,10 +75,51 @@ namespace chaiscript
return m_types == t_rhs.m_types; return m_types == t_rhs.m_types;
} }
bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const std::vector<Boxed_Value> convert(std::vector<Boxed_Value> vals, const Type_Conversions_State &t_conversions) const
{ {
if (!m_has_types) return true; for (size_t i = 0; i < vals.size(); ++i)
if (vals.size() != m_types.size()) return false; {
const auto &name = m_types[i].first;
if (!name.empty()) {
const auto &bv = vals[i];
if (!bv.get_type_info().bare_equal(m_doti))
{
const auto &ti = m_types[i].second;
if (!ti.is_undef())
{
if (!bv.get_type_info().bare_equal(ti)) {
if (t_conversions->converts(ti, bv.get_type_info())) {
try {
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
vals[i] = t_conversions->boxed_type_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
} catch (...) {
try {
// try going the other way
vals[i] = t_conversions->boxed_type_down_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), *m_types[i].second.bare_type_info());
}
}
}
}
}
}
}
}
return vals;
}
// first result: is a match
// second result: needs conversions
std::pair<bool, bool> match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
{
bool needs_conversion = false;
if (!m_has_types) { return std::make_pair(true, needs_conversion); }
if (vals.size() != m_types.size()) { return std::make_pair(false, needs_conversion); }
for (size_t i = 0; i < vals.size(); ++i) for (size_t i = 0; i < vals.size(); ++i)
{ {
@ -87,25 +131,31 @@ namespace chaiscript
{ {
try { try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions); const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name; if (!(name == "Dynamic_Object" || d.get_type_name() == name)) {
return std::make_pair(false, false);
}
} catch (const std::bad_cast &) { } catch (const std::bad_cast &) {
return false; return std::make_pair(false, false);
} }
} else { } else {
const auto &ti = m_types[i].second; const auto &ti = m_types[i].second;
if (!ti.is_undef()) if (!ti.is_undef())
{ {
if (!bv.get_type_info().bare_equal(ti)) { if (!bv.get_type_info().bare_equal(ti)) {
return false; if (!t_conversions->converts(ti, bv.get_type_info())) {
return std::make_pair(false, false);
} else {
needs_conversion = true;
}
} }
} else { } else {
return false; return std::make_pair(false, false);
} }
} }
} }
} }
return true; return std::make_pair(true, needs_conversion);
} }
const std::vector<std::pair<std::string, Type_Info>> &types() const const std::vector<std::pair<std::string, Type_Info>> &types() const
@ -282,7 +332,7 @@ namespace chaiscript
guard_error(const guard_error &) = default; guard_error(const guard_error &) = default;
virtual ~guard_error() noexcept = default; ~guard_error() noexcept override = default;
}; };
} }
@ -296,32 +346,32 @@ 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);
} }
virtual bool operator==(const Proxy_Function_Base &rhs) const override bool operator==(const Proxy_Function_Base &rhs) const override
{ {
const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs); const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs);
return this == &rhs return this == &rhs
|| (prhs || ((prhs != nullptr)
&& this->m_arity == prhs->m_arity && this->m_arity == prhs->m_arity
&& !this->m_guard && !prhs->m_guard && !this->m_guard && !prhs->m_guard
&& this->m_param_types == prhs->m_param_types); && this->m_param_types == prhs->m_param_types);
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
{ {
return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions))) return call_match_internal(vals, t_conversions).first;
&& test_guard(vals, t_conversions);
} }
@ -330,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");
}
} }
@ -353,6 +411,26 @@ namespace chaiscript
} }
} }
// first result: is a match
// second result: needs conversions
std::pair<bool, bool> call_match_internal(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
{
const auto comparison_result = [&](){
if (m_arity < 0) {
return std::make_pair(true, false);
} else if (vals.size() == size_t(m_arity)) {
return m_param_types.match(vals, t_conversions);
} else {
return std::make_pair(false, false);
}
}();
return std::make_pair(
comparison_result.first && test_guard(vals, t_conversions),
comparison_result.second
);
}
private: private:
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types) static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
{ {
@ -371,9 +449,12 @@ namespace chaiscript
return types; return types;
} }
protected:
Param_Types m_param_types; Param_Types m_param_types;
private:
Proxy_Function m_guard; Proxy_Function m_guard;
AST_NodePtr m_parsenode; std::shared_ptr<AST_Node> m_parsenode;
}; };
@ -385,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(
@ -402,9 +483,14 @@ namespace chaiscript
protected: protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{ {
if (call_match(params, t_conversions) && test_guard(params, t_conversions)) const auto match_results = call_match_internal(params, t_conversions);
if (match_results.first)
{ {
return m_f(params); if (match_results.second) {
return m_f(m_param_types.convert(params, t_conversions));
} else {
return m_f(params);
}
} else { } else {
throw exception::guard_error(); throw exception::guard_error();
} }
@ -516,7 +602,7 @@ namespace chaiscript
return retval; return retval;
} }
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{ {
return (*m_f)(build_param_list(params), t_conversions); return (*m_f)(build_param_list(params), t_conversions);
} }
@ -529,7 +615,7 @@ namespace chaiscript
class Proxy_Function_Impl_Base : public Proxy_Function_Base class Proxy_Function_Impl_Base : public Proxy_Function_Base
{ {
public: public:
Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types) explicit Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
: Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1) : Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
{ {
} }
@ -550,7 +636,7 @@ namespace chaiscript
class Proxy_Function_Callable_Impl final : public Proxy_Function_Impl_Base class Proxy_Function_Callable_Impl final : public Proxy_Function_Impl_Base
{ {
public: public:
Proxy_Function_Callable_Impl(Callable f) explicit Proxy_Function_Callable_Impl(Callable f)
: Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))), : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
m_f(std::move(f)) m_f(std::move(f))
{ {
@ -581,7 +667,7 @@ namespace chaiscript
class Assignable_Proxy_Function : public Proxy_Function_Impl_Base class Assignable_Proxy_Function : public Proxy_Function_Impl_Base
{ {
public: public:
Assignable_Proxy_Function(const std::vector<Type_Info> &t_types) explicit Assignable_Proxy_Function(const std::vector<Type_Info> &t_types)
: Proxy_Function_Impl_Base(t_types) : Proxy_Function_Impl_Base(t_types)
{ {
} }
@ -637,7 +723,7 @@ namespace chaiscript
class Attribute_Access final : public Proxy_Function_Base class Attribute_Access final : public Proxy_Function_Base
{ {
public: public:
Attribute_Access(T Class::* t_attr) explicit Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types(), 1), : Proxy_Function_Base(param_types(), 1),
m_attr(t_attr) m_attr(t_attr)
{ {
@ -742,7 +828,7 @@ namespace chaiscript
dispatch_error(const dispatch_error &) = default; dispatch_error(const dispatch_error &) = default;
virtual ~dispatch_error() noexcept = default; ~dispatch_error() noexcept override = default;
std::vector<Boxed_Value> parameters; std::vector<Boxed_Value> parameters;
std::vector<Const_Proxy_Function> functions; std::vector<Const_Proxy_Function> functions;
@ -759,7 +845,7 @@ namespace chaiscript
{ {
const std::vector<Type_Info> &types = t_func->get_param_types(); const std::vector<Type_Info> &types = t_func->get_param_types();
if (t_func->get_arity() == -1) return false; if (t_func->get_arity() == -1) { return false; }
assert(plist.size() == types.size() - 1); assert(plist.size() == types.size() - 1);
@ -843,11 +929,9 @@ namespace chaiscript
} }
} }
/** /// Take a vector of functions and a vector of parameters. Attempt to execute
* Take a vector of functions and a vector of parameters. Attempt to execute /// each function against the set of parameters, in order, until a matching
* each function against the set of parameters, in order, until a matching /// function is found or throw dispatch_error if no matching function is found
* function is found or throw dispatch_error if no matching function is found
*/
template<typename Funcs> template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs, Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Type_Conversions_State &t_conversions) const std::vector<Boxed_Value> &plist, const Type_Conversions_State &t_conversions)

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
@ -44,7 +48,7 @@ namespace chaiscript
arity_error(const arity_error &) = default; arity_error(const arity_error &) = default;
virtual ~arity_error() noexcept {} ~arity_error() noexcept override = default;
int got; int got;
int expected; int expected;
@ -115,7 +119,15 @@ namespace chaiscript
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions); call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4702)
#endif
// MSVC is reporting that this is unreachable code - and it's wrong.
return Handle_Return<void>::handle(); return Handle_Return<void>::handle();
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
} }
} }

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_ #ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_ #define CHAISCRIPT_REGISTER_FUNCTION_HPP_
@ -44,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...))
{ {
@ -73,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
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
@ -107,31 +144,6 @@ namespace chaiscript
return fun(detail::bind_first(std::forward<T>(t), q)); return fun(detail::bind_first(std::forward<T>(t), q));
} }
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it
/// \param[in] t Function / member to expose
/// \param[in] q Value to bind to first parameter
/// \param[in] r Value to bind to second parameter
///
/// \b Example:
/// \code
/// struct MyClass
/// {
/// void memberfunction(int);
/// };
///
/// MyClass obj;
/// chaiscript::ChaiScript chai;
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
/// // memberfunction() will be equivalent to obj.memberfunction(1)
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
/// \endcode
///
/// \sa \ref adding_functions
template<typename T, typename Q, typename R>
Proxy_Function fun(T &&t, Q &&q, R &&r)
{
return fun(detail::bind_first(detail::bind_first(std::forward<T>(t), std::forward<Q>(q)), std::forward<R>(r)));
}
} }

View File

@ -84,12 +84,14 @@ arena<N, alignment>::deallocate(char* p, std::size_t n) noexcept
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena"); assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
if (pointer_in_buffer(p)) if (pointer_in_buffer(p))
{ {
n = align_up(n); n = align_up(n);
if (p + n == ptr_) if (p + n == ptr_) {
ptr_ = p; ptr_ = p;
}
}
else {
::operator delete(p);
} }
else
::operator delete(p);
} }
template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)> template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
@ -108,13 +110,13 @@ public:
short_alloc(const short_alloc&) = default; short_alloc(const short_alloc&) = default;
short_alloc& operator=(const short_alloc&) = delete; short_alloc& operator=(const short_alloc&) = delete;
short_alloc(arena_type& a) noexcept : a_(a) explicit short_alloc(arena_type& a) noexcept : a_(a)
{ {
static_assert(size % alignment == 0, static_assert(size % alignment == 0,
"size N needs to be a multiple of alignment Align"); "size N needs to be a multiple of alignment Align");
} }
template <class U> template <class U>
short_alloc(const short_alloc<U, N, alignment>& a) noexcept explicit short_alloc(const short_alloc<U, N, alignment>& a) noexcept
: a_(a.a_) {} : a_(a.a_) {}
template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;}; template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;};

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
@ -39,14 +43,14 @@ namespace chaiscript
{ {
} }
bad_boxed_dynamic_cast(const std::string &w) noexcept explicit bad_boxed_dynamic_cast(const std::string &w) noexcept
: bad_boxed_cast(w) : bad_boxed_cast(w)
{ {
} }
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default; bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
virtual ~bad_boxed_dynamic_cast() noexcept = default; ~bad_boxed_dynamic_cast() noexcept override = default;
}; };
class bad_boxed_type_cast : public bad_boxed_cast class bad_boxed_type_cast : public bad_boxed_cast
@ -63,14 +67,14 @@ namespace chaiscript
{ {
} }
bad_boxed_type_cast(const std::string &w) noexcept explicit bad_boxed_type_cast(const std::string &w) noexcept
: bad_boxed_cast(w) : bad_boxed_cast(w)
{ {
} }
bad_boxed_type_cast(const bad_boxed_type_cast &) = default; bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
virtual ~bad_boxed_type_cast() noexcept = default; ~bad_boxed_type_cast() noexcept override = default;
}; };
} }
@ -100,8 +104,8 @@ namespace chaiscript
virtual ~Type_Conversion_Base() = default; virtual ~Type_Conversion_Base() = default;
protected: protected:
Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from) Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
: m_to(t_to), m_from(t_from) : m_to(std::move(t_to)), m_from(std::move(t_from))
{ {
} }
@ -286,7 +290,7 @@ namespace chaiscript
{ {
public: public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(std::move(t_to), std::move(t_from)), : Type_Conversion_Base(t_to, t_from),
m_func(std::move(t_func)) m_func(std::move(t_func))
{ {
} }
@ -302,7 +306,7 @@ namespace chaiscript
return m_func(t_from); return m_func(t_from);
} }
virtual bool bidir() const override bool bidir() const override
{ {
return false; return false;
} }
@ -334,21 +338,15 @@ 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)
{ {
} }
Type_Conversions(const Type_Conversions &t_other) Type_Conversions(const Type_Conversions &t_other) = delete;
: m_mutex(), Type_Conversions(Type_Conversions &&) = default;
m_conversions(t_other.get_conversions()),
m_convertableTypes(t_other.m_convertableTypes), Type_Conversions &operator=(const Type_Conversions &) = delete;
m_num_types(m_conversions.size()), Type_Conversions &operator=(Type_Conversions &&) = default;
m_thread_cache(this),
m_conversion_saves(this)
{
}
const std::set<const std::type_info *, Less_Than> &thread_cache() const const std::set<const std::type_info *, Less_Than> &thread_cache() const
{ {
@ -397,28 +395,39 @@ namespace chaiscript
template<typename To> template<typename To>
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
{ {
try { return boxed_type_conversion(user_type<To>(), t_saves, from);
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
if (t_saves.enabled) t_saves.saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation");
}
} }
template<typename From> template<typename From>
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const
{
return boxed_type_down_conversion(user_type<From>(), t_saves, to);
}
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const
{ {
try { try {
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to); Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
if (t_saves.enabled) t_saves.saves.push_back(ret); if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion"); throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) { } catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation"); throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation");
}
}
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const
{
try {
Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation");
} }
} }

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_TYPE_INFO_HPP_ #ifndef CHAISCRIPT_TYPE_INFO_HPP_
#define CHAISCRIPT_TYPE_INFO_HPP_ #define CHAISCRIPT_TYPE_INFO_HPP_

View File

@ -1,12 +1,18 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_ #ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_
#include "../utility/fnv1a.hpp"
#include <string> #include <string>
namespace chaiscript namespace chaiscript
@ -51,76 +57,48 @@ namespace chaiscript
static Opers to_operator(const std::string &t_str, bool t_is_unary = false) static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
{ {
if (t_str == "==") #ifdef CHAISCRIPT_MSVC
{ #pragma warning(push)
return Opers::equals; #pragma warning(disable : 4307)
} else if (t_str == "<") { #endif
return Opers::less_than;
} else if (t_str == ">") { const auto op_hash = utility::fnv1a_32(t_str.c_str());
return Opers::greater_than; switch (op_hash) {
} else if (t_str == "<=") { case utility::fnv1a_32("=="): { return Opers::equals; }
return Opers::less_than_equal; case utility::fnv1a_32("<"): { return Opers::less_than; }
} else if (t_str == ">=") { case utility::fnv1a_32(">"): { return Opers::greater_than; }
return Opers::greater_than_equal; case utility::fnv1a_32("<="): { return Opers::less_than_equal; }
} else if (t_str == "!=") { case utility::fnv1a_32(">="): { return Opers::greater_than_equal; }
return Opers::not_equal; case utility::fnv1a_32("!="): { return Opers::not_equal; }
} else if (t_str == "=") { case utility::fnv1a_32("="): { return Opers::assign; }
return Opers::assign; case utility::fnv1a_32("++"): { return Opers::pre_increment; }
} else if (t_str == "++") { case utility::fnv1a_32("--"): { return Opers::pre_decrement; }
return Opers::pre_increment; case utility::fnv1a_32("*="): { return Opers::assign_product; }
} else if (t_str == "--") { case utility::fnv1a_32("+="): { return Opers::assign_sum; }
return Opers::pre_decrement; case utility::fnv1a_32("-="): { return Opers::assign_difference; }
} else if (t_str == "*=") { case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; }
return Opers::assign_product; case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; }
} else if (t_str == "+=") { case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; }
return Opers::assign_sum; case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; }
} else if (t_str == "-=") { case utility::fnv1a_32("%="): { return Opers::assign_remainder; }
return Opers::assign_difference; case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; }
} else if (t_str == "&=") { case utility::fnv1a_32("<<"): { return Opers::shift_left; }
return Opers::assign_bitwise_and; case utility::fnv1a_32(">>"): { return Opers::shift_right; }
} else if (t_str == "|=") { case utility::fnv1a_32("%"): { return Opers::remainder; }
return Opers::assign_bitwise_or; case utility::fnv1a_32("&"): { return Opers::bitwise_and; }
} else if (t_str == "<<=") { case utility::fnv1a_32("|"): { return Opers::bitwise_or; }
return Opers::assign_shift_left; case utility::fnv1a_32("^"): { return Opers::bitwise_xor; }
} else if (t_str == ">>=") { case utility::fnv1a_32("~"): { return Opers::bitwise_complement; }
return Opers::assign_shift_right; case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; }
} else if (t_str == "%=") { case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; }
return Opers::assign_remainder; case utility::fnv1a_32("/"): { return Opers::quotient; }
} else if (t_str == "^=") { case utility::fnv1a_32("*"): { return Opers::product; }
return Opers::assign_bitwise_xor; default: { return Opers::invalid; }
} else if (t_str == "<<") { }
return Opers::shift_left; #ifdef CHAISCRIPT_MSVC
} else if (t_str == ">>") { #pragma warning(pop)
return Opers::shift_right; #endif
} else if (t_str == "%") {
return Opers::remainder;
} else if (t_str == "&") {
return Opers::bitwise_and;
} else if (t_str == "|") {
return Opers::bitwise_or;
} else if (t_str == "^") {
return Opers::bitwise_xor;
} else if (t_str == "~") {
return Opers::bitwise_complement;
} else if (t_str == "+") {
if (t_is_unary) {
return Opers::unary_plus;
} else {
return Opers::sum;
}
} else if (t_str == "-") {
if (t_is_unary) {
return Opers::unary_minus;
} else {
return Opers::difference;
}
} else if (t_str == "/") {
return Opers::quotient;
} else if (t_str == "*") {
return Opers::product;
} else {
return Opers::invalid;
}
} }
}; };

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_COMMON_HPP_ #ifndef CHAISCRIPT_COMMON_HPP_
#define CHAISCRIPT_COMMON_HPP_ #define CHAISCRIPT_COMMON_HPP_
@ -31,7 +35,8 @@ namespace chaiscript
{ {
static const std::set<std::string> m_reserved_words static const std::set<std::string> m_reserved_words
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto", = {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_"}; "return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_",
"__LINE__", "__FILE__", "__FUNC__", "__CLASS__"};
return m_reserved_words.count(name) > 0; return m_reserved_words.count(name) > 0;
} }
@ -61,7 +66,7 @@ namespace chaiscript
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,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled
}; };
enum class Operator_Precidence { Ternary_Cond, Logical_Or, enum class Operator_Precidence { Ternary_Cond, Logical_Or,
@ -71,12 +76,12 @@ namespace chaiscript
namespace namespace
{ {
/// Helper lookup to get the name of each node type /// Helper lookup to get the name of each node type
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",
"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",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"}; "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
return ast_node_types[static_cast<int>(ast_node_type)]; return ast_node_types[static_cast<int>(ast_node_type)];
} }
@ -119,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.
@ -129,7 +136,7 @@ namespace chaiscript
/// \brief Thrown if an error occurs while attempting to load a binary module /// \brief Thrown if an error occurs while attempting to load a binary module
struct load_module_error : std::runtime_error struct load_module_error : std::runtime_error
{ {
load_module_error(const std::string &t_reason) noexcept explicit load_module_error(const std::string &t_reason) noexcept
: std::runtime_error(t_reason) : std::runtime_error(t_reason)
{ {
} }
@ -140,7 +147,7 @@ namespace chaiscript
} }
load_module_error(const load_module_error &) = default; load_module_error(const load_module_error &) = default;
virtual ~load_module_error() noexcept = default; ~load_module_error() noexcept override = default;
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors) static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
{ {
@ -163,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,
@ -187,7 +194,7 @@ namespace chaiscript
reason(t_why), start_position(t_where), filename(t_fname) reason(t_why), start_position(t_where), filename(t_fname)
{} {}
eval_error(const std::string &t_why) noexcept explicit eval_error(const std::string &t_why) noexcept
: std::runtime_error("Error: \"" + t_why + "\" "), : std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why) reason(t_why)
{} {}
@ -199,7 +206,7 @@ namespace chaiscript
std::ostringstream ss; std::ostringstream ss;
ss << what(); ss << what();
if (call_stack.size() > 0) { if (!call_stack.empty()) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n"; ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
ss << '\n' << detail << '\n'; ss << '\n' << detail << '\n';
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'"; ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
@ -216,33 +223,33 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
virtual ~eval_error() noexcept = default; ~eval_error() noexcept override = default;
private: private:
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();
} }
@ -255,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();
@ -303,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;
@ -325,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,
@ -348,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";
@ -475,19 +479,19 @@ namespace chaiscript
/// Errors generated when loading a file /// Errors generated when loading a file
struct file_not_found_error : std::runtime_error { struct file_not_found_error : std::runtime_error {
file_not_found_error(const std::string &t_filename) noexcept explicit file_not_found_error(const std::string &t_filename) noexcept
: std::runtime_error("File Not Found: " + t_filename) : std::runtime_error("File Not Found: " + t_filename)
{ } { }
file_not_found_error(const file_not_found_error &) = default; file_not_found_error(const file_not_found_error &) = default;
virtual ~file_not_found_error() noexcept {} ~file_not_found_error() noexcept override = default;
}; };
} }
/// \brief Struct that doubles as both a parser ast_node and an AST node. /// \brief Struct that doubles as both a parser ast_node and an AST node.
struct AST_Node : std::enable_shared_from_this<AST_Node> { struct AST_Node {
public: public:
const AST_Node_Type identifier; const AST_Node_Type identifier;
const std::string text; const std::string text;
@ -511,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;
@ -529,16 +533,16 @@ 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();
} }
static bool get_bool_condition(const Boxed_Value &t_bv) { static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
try { try {
return boxed_cast<bool>(t_bv); return t_ss->boxed_cast<bool>(t_bv);
} }
catch (const exception::bad_boxed_cast &) { catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("Condition not boolean"); throw exception::eval_error("Condition not boolean");
@ -563,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;
@ -596,19 +648,19 @@ namespace chaiscript
struct Return_Value { struct Return_Value {
Boxed_Value retval; Boxed_Value retval;
Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { } explicit Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
}; };
/// Special type indicating a call to 'break' /// Special type indicating a call to 'break'
struct Break_Loop { struct Break_Loop {
Break_Loop() { } Break_Loop() = default;
}; };
/// Special type indicating a call to 'continue' /// Special type indicating a call to 'continue'
struct Continue_Loop { struct Continue_Loop {
Continue_Loop() { } Continue_Loop() = default;
}; };
@ -620,7 +672,7 @@ namespace chaiscript
Scope_Push_Pop(const Scope_Push_Pop &) = delete; Scope_Push_Pop(const Scope_Push_Pop &) = delete;
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete; Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds->new_scope(m_ds.stack_holder()); m_ds->new_scope(m_ds.stack_holder());
@ -644,7 +696,7 @@ namespace chaiscript
Function_Push_Pop(const Function_Push_Pop &) = delete; Function_Push_Pop(const Function_Push_Pop &) = delete;
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete; Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
@ -662,7 +714,7 @@ namespace chaiscript
void save_params(std::initializer_list<Boxed_Value> t_params) void save_params(std::initializer_list<Boxed_Value> t_params)
{ {
m_ds->save_function_params(std::move(t_params)); m_ds->save_function_params(t_params);
} }
@ -678,7 +730,7 @@ namespace chaiscript
Stack_Push_Pop(const Stack_Push_Pop &) = delete; Stack_Push_Pop(const Stack_Push_Pop &) = delete;
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete; Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds->new_stack(m_ds.stack_holder()); m_ds->new_stack(m_ds.stack_holder());

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ENGINE_HPP_ #ifndef CHAISCRIPT_ENGINE_HPP_
#define CHAISCRIPT_ENGINE_HPP_ #define CHAISCRIPT_ENGINE_HPP_
@ -32,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"
@ -94,7 +99,7 @@ namespace chaiscript
{ {
try { try {
const auto p = m_parser->parse(t_input, t_filename); const auto p = m_parser->parse(t_input, t_filename);
return p->eval(m_engine); return p->eval(chaiscript::detail::Dispatch_State(m_engine));
} }
catch (chaiscript::eval::detail::Return_Value &rv) { catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval; return rv.retval;
@ -139,7 +144,7 @@ namespace chaiscript
} }
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude. /// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
void build_eval_system(const ModulePtr &t_lib) { void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) {
if (t_lib) if (t_lib)
{ {
add(t_lib); add(t_lib);
@ -160,9 +165,6 @@ namespace chaiscript
}) })
, "call_exists"); , "call_exists");
// m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
//
//
m_engine.add(fun( m_engine.add(fun(
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value { [=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
@ -184,13 +186,22 @@ namespace chaiscript
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return load_module(t_module, t_file); }), "load_module"); if (std::find(t_opts.begin(), t_opts.end(), Options::No_Load_Modules) == t_opts.end()
m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module"); && std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end())
{
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return load_module(t_module, t_file); }), "load_module");
m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module");
}
if (std::find(t_opts.begin(), t_opts.end(), Options::No_External_Scripts) == t_opts.end()
&& std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end())
{
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use");
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
}
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use");
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval"); m_engine.add(fun([this](const 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");
@ -228,59 +239,29 @@ namespace chaiscript
} }
} }
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths)
{
if (paths.empty()) { return {""}; }
else { return paths; }
}
public: public:
/// \brief Constructor for ChaiScript /// \brief Constructor for ChaiScript
/// \param[in] t_lib Standard library to apply to this ChaiScript instance /// \param[in] t_lib Standard library to apply to this ChaiScript instance
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module /// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file /// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
ChaiScript_Basic(const ModulePtr &t_lib, ChaiScript_Basic(const ModulePtr &t_lib,
std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser, std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_modulepaths = {}, std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_usepaths = {}) std::vector<std::string> t_use_paths = {},
: m_module_paths(std::move(t_modulepaths)), const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
m_use_paths(std::move(t_usepaths)), : m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths))),
m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths))),
m_parser(std::move(parser)), m_parser(std::move(parser)),
m_engine(*m_parser) m_engine(*m_parser)
{ {
if (m_module_paths.empty()) #if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
{
m_module_paths.push_back("");
}
if (m_use_paths.empty())
{
m_use_paths.push_back("");
}
build_eval_system(t_lib);
}
/// \brief Constructor for ChaiScript.
///
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
/// at runtime generates an error if it cannot be found.
///
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_modulepaths = {},
std::vector<std::string> t_usepaths = {})
: m_module_paths(std::move(t_modulepaths)),
m_use_paths(std::move(t_usepaths)),
m_parser(std::move(parser)),
m_engine(*m_parser)
{
if (m_module_paths.empty())
{
m_module_paths.push_back("");
}
if (m_use_paths.empty())
{
m_use_paths.push_back("");
}
#if 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
@ -294,7 +275,7 @@ namespace chaiscript
memset( &rInfo, 0, sizeof(rInfo) ); memset( &rInfo, 0, sizeof(rInfo) );
cast_union u; cast_union u;
u.in_ptr = &ChaiScript_Basic::use; u.in_ptr = &ChaiScript_Basic::use;
if ( dladdr(static_cast<void*>(u.out_ptr), &rInfo) && rInfo.dli_fname ) { if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) {
std::string dllpath(rInfo.dli_fname); std::string dllpath(rInfo.dli_fname);
const size_t lastslash = dllpath.rfind('/'); const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos) if (lastslash != std::string::npos)
@ -313,8 +294,23 @@ namespace chaiscript
m_module_paths.insert(m_module_paths.begin(), dllpath+"/"); m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
} }
#endif #endif
build_eval_system(t_lib, t_opts);
}
#ifndef CHAISCRIPT_NO_DYNLOAD
/// \brief Constructor for ChaiScript.
///
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
/// at runtime generates an error if it cannot be found.
///
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
: ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts)
{
try { try {
// attempt to load the stdlib // attempt to load the stdlib
load_module("chaiscript_stdlib-" + Build_Info::version()); load_module("chaiscript_stdlib-" + Build_Info::version());
@ -330,15 +326,23 @@ namespace chaiscript
<< t_err.what(); << t_err.what();
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
build_eval_system(ModulePtr()); parser::ChaiScript_Parser_Base &get_parser()
{
return *m_parser;
} }
const Boxed_Value eval(const AST_Node &t_ast)
const Boxed_Value eval(const AST_NodePtr &t_ast)
{ {
try { try {
return t_ast->eval(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);
} }
@ -346,9 +350,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;
} }
@ -570,6 +574,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());
@ -603,6 +611,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

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_EVAL_HPP_ #ifndef CHAISCRIPT_EVAL_HPP_
#define CHAISCRIPT_EVAL_HPP_ #define CHAISCRIPT_EVAL_HPP_
@ -43,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) { 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 *{
@ -64,7 +68,7 @@ namespace chaiscript
}(); }();
chaiscript::eval::detail::Stack_Push_Pop tpp(state); chaiscript::eval::detail::Stack_Push_Pop tpp(state);
if (thisobj) state.add_object("this", *thisobj); if (thisobj && !has_this_capture) { state.add_object("this", *thisobj); }
if (t_locals) { if (t_locals) {
for (const auto &local : *t_locals) { for (const auto &local : *t_locals) {
@ -79,7 +83,7 @@ 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);
} }
@ -91,14 +95,25 @@ namespace chaiscript
{ {
AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc, AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc,
std::vector<AST_Node_Impl_Ptr<T>> t_children = std::vector<AST_Node_Impl_Ptr<T>>()) std::vector<AST_Node_Impl_Ptr<T>> t_children = std::vector<AST_Node_Impl_Ptr<T>>())
: AST_Node(std::move(t_ast_node_text), std::move(t_id), std::move(t_loc)), : AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc)),
children(std::move(t_children)) children(std::move(t_children))
{ {
} }
static bool get_scoped_bool_condition(const AST_Node_Impl<T> &node, const chaiscript::detail::Dispatch_State &t_ss) {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
return get_bool_condition(node.eval(t_ss), t_ss);
}
std::vector<AST_NodePtr> get_children() const final {
return {children.begin(), children.end()}; std::vector<std::reference_wrapper<AST_Node>> get_children() const final {
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
@ -107,7 +122,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;
} }
} }
@ -238,7 +253,7 @@ namespace chaiscript
{ {
} }
Constant_AST_Node(Boxed_Value t_value) explicit Constant_AST_Node(Boxed_Value t_value)
: AST_Node_Impl<T>("", AST_Node_Type::Constant, Parse_Location()), : AST_Node_Impl<T>("", AST_Node_Type::Constant, Parse_Location()),
m_value(std::move(t_value)) m_value(std::move(t_value))
{ {
@ -270,60 +285,15 @@ namespace chaiscript
mutable std::atomic_uint_fast32_t m_loc = {0}; mutable std::atomic_uint_fast32_t m_loc = {0};
}; };
template<typename T> template<typename T>
struct Unused_Return_Fun_Call_AST_Node final : AST_Node_Impl<T> { struct Fun_Call_AST_Node : AST_Node_Impl<T> {
Unused_Return_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::Unused_Return_Fun_Call, std::move(t_loc), std::move(t_children)) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params;
params.reserve(this->children[1]->children.size());
for (const auto &child : this->children[1]->children) {
params.push_back(child->eval(t_ss));
}
Boxed_Value fn(this->children[0]->eval(t_ss));
try {
return (*t_ss->boxed_cast<const dispatch::Proxy_Function_Base *>(fn))(params, t_ss.conversions());
}
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);
}
catch(const exception::bad_boxed_cast &){
try {
Const_Proxy_Function f = t_ss->boxed_cast<const Const_Proxy_Function &>(fn);
// 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);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
}
}
catch(const exception::arity_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(const exception::guard_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(detail::Return_Value &rv) {
return rv.retval;
}
}
};
template<typename T>
struct Fun_Call_AST_Node final : 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());
}
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override template<bool Save_Params>
Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const
{ {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
@ -334,7 +304,9 @@ namespace chaiscript
params.push_back(child->eval(t_ss)); params.push_back(child->eval(t_ss));
} }
fpp.save_params(params); if (Save_Params) {
fpp.save_params(params);
}
Boxed_Value fn(this->children[0]->eval(t_ss)); Boxed_Value fn(this->children[0]->eval(t_ss));
@ -364,10 +336,28 @@ namespace chaiscript
} }
} }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{
return do_eval_internal<true>(t_ss);
}
}; };
template<typename T>
struct Unused_Return_Fun_Call_AST_Node final : Fun_Call_AST_Node<T> {
Unused_Return_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<T>(std::move(t_ast_node_text), std::move(t_loc), std::move(t_children)) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{
return this->template do_eval_internal<false>(t_ss);
}
};
template<typename T> template<typename T>
struct Arg_AST_Node final : AST_Node_Impl<T> { struct Arg_AST_Node final : AST_Node_Impl<T> {
@ -382,44 +372,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));
@ -455,13 +445,13 @@ namespace chaiscript
try { try {
if (lhs.is_undef()) { if (lhs.is_undef()) {
if ((!this->children.empty() if (!this->children.empty()
&& ((this->children[0]->identifier == AST_Node_Type::Reference) && ((this->children[0]->identifier == AST_Node_Type::Reference)
|| (!this->children[0]->children.empty() || (!this->children[0]->children.empty()
&& this->children[0]->children[0]->identifier == AST_Node_Type::Reference) && this->children[0]->children[0]->identifier == AST_Node_Type::Reference)
) )
)
) )
{ {
/// \todo This does not handle the case of an unassigned reference variable /// \todo This does not handle the case of an unassigned reference variable
/// being assigned outside of its declaration /// being assigned outside of its declaration
@ -639,8 +629,16 @@ 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,
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 {
@ -653,25 +651,34 @@ 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](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); 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
) )
); );
} }
static bool has_this_capture(const std::vector<AST_Node_Impl_Ptr<T>> &children) {
return std::any_of(std::begin(children), std::end(children),
[](const auto &child){
return child->children[0]->text == "this";
}
);
}
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 std::shared_ptr<AST_Node_Impl<T>> m_lambda_node;
}; };
template<typename T> template<typename T>
@ -706,55 +713,81 @@ 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)))
),
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() + "'");
@ -773,7 +806,7 @@ namespace chaiscript
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
try { try {
while (this->get_bool_condition(this->children[0]->eval(t_ss))) { while (this->get_scoped_bool_condition(*this->children[0], t_ss)) {
try { try {
this->children[1]->eval(t_ss); this->children[1]->eval(t_ss);
} catch (detail::Continue_Loop &) { } catch (detail::Continue_Loop &) {
@ -808,22 +841,6 @@ namespace chaiscript
} }
}; };
template<typename T>
struct Ternary_Cond_AST_Node final : AST_Node_Impl<T> {
Ternary_Cond_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::Ternary_Cond, std::move(t_loc), std::move(t_children))
{ assert(this->children.size() == 3); }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
if (this->get_bool_condition(this->children[0]->eval(t_ss))) {
return this->children[1]->eval(t_ss);
} else {
return this->children[2]->eval(t_ss);
}
}
};
template<typename T> template<typename T>
struct If_AST_Node final : AST_Node_Impl<T> { struct If_AST_Node final : AST_Node_Impl<T> {
@ -834,7 +851,7 @@ namespace chaiscript
} }
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 {
if (this->get_bool_condition(this->children[0]->eval(t_ss))) { if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) {
return this->children[1]->eval(t_ss); return this->children[1]->eval(t_ss);
} else { } else {
return this->children[2]->eval(t_ss); return this->children[2]->eval(t_ss);
@ -852,7 +869,7 @@ namespace chaiscript
const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){ const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){
uint_fast32_t hint = t_hint; uint_fast32_t hint = t_hint;
auto funs = t_ss->get_function(t_name, hint); auto funs = t_ss->get_function(t_name, hint);
if (funs.first != hint) t_hint = uint_fast32_t(funs.first); if (funs.first != hint) { t_hint = uint_fast32_t(funs.first); }
return std::move(funs.second); return std::move(funs.second);
}; };
@ -932,7 +949,7 @@ namespace chaiscript
try { try {
for ( for (
this->children[0]->eval(t_ss); this->children[0]->eval(t_ss);
this->get_bool_condition(this->children[1]->eval(t_ss)); this->get_scoped_bool_condition(*this->children[1], t_ss);
this->children[2]->eval(t_ss) this->children[2]->eval(t_ss)
) { ) {
try { try {
@ -1253,32 +1270,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())) ).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);
@ -1286,7 +1303,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;
} }
} }
@ -1312,11 +1329,8 @@ namespace chaiscript
try { try {
retval = this->children[0]->eval(t_ss); retval = this->children[0]->eval(t_ss);
} }
catch (exception::eval_error &) { catch (const exception::eval_error &e) {
if (this->children.back()->identifier == AST_Node_Type::Finally) { retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
this->children.back()->children[0]->eval(t_ss);
}
throw;
} }
catch (const std::runtime_error &e) { catch (const std::runtime_error &e) {
retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
@ -1361,55 +1375,50 @@ 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{
AST_Node_Impl_Ptr<T> guardnode; AST_Node_Impl_Ptr<T> guardnode;
const auto d = t_ss->get_parent_locals(); const std::string & class_name = this->children[0]->text;
const auto itr = d.find("_current_class_name");
const auto class_offset = (itr != d.end())?-1:0;
const std::string & class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
//The first param of a method is always the implied this ptr. //The first param of a method is always the implied this ptr.
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() > static_cast<size_t>(3 + class_offset)) if ((this->children.size() > 2)
&& (this->children[static_cast<size_t>(2 + class_offset)]->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[static_cast<size_t>(2 + class_offset)]); 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[static_cast<size_t>(2 + class_offset)], t_ss); param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[2], t_ss);
if (this->children.size() > static_cast<size_t>(4 + class_offset)) {
guardnode = this->children[static_cast<size_t>(3 + class_offset)];
}
}
else {
//no parameters
if (this->children.size() > static_cast<size_t>(3 + class_offset)) {
guardnode = this->children[static_cast<size_t>(2 + class_offset)];
}
} }
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[static_cast<size_t>(1 + class_offset)]->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());
@ -1417,10 +1426,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);
@ -1431,15 +1440,17 @@ 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) {
std::cout << "Method!!" << std::endl;
throw exception::eval_error("Method redefined '" + e.name() + "'"); throw exception::eval_error("Method redefined '" + e.name() + "'");
} }
return void_var(); return void_var();
@ -1454,13 +1465,10 @@ namespace chaiscript
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
{ {
const auto &d = t_ss->get_parent_locals(); std::string class_name = this->children[0]->text;
const auto itr = d.find("_current_class_name");
const auto class_offset = (itr != d.end())?-1:0;
std::string class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
try { try {
std::string attr_name = this->children[static_cast<size_t>(1 + class_offset)]->text; std::string attr_name = this->children[1]->text;
t_ss->add( t_ss->add(
std::make_shared<dispatch::detail::Dynamic_Object_Function>( std::make_shared<dispatch::detail::Dynamic_Object_Function>(
@ -1470,7 +1478,7 @@ namespace chaiscript
}), }),
true true
), this->children[static_cast<size_t>(1 + class_offset)]->text); ), this->children[1]->text);
} catch (const exception::name_conflict_error &e) { } catch (const exception::name_conflict_error &e) {
throw exception::eval_error("Attribute redefined '" + e.name() + "'"); throw exception::eval_error("Attribute redefined '" + e.name() + "'");
} }
@ -1488,8 +1496,8 @@ namespace chaiscript
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
{ {
return const_var(this->get_bool_condition(this->children[0]->eval(t_ss)) return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
&& this->get_bool_condition(this->children[1]->eval(t_ss))); && this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
} }
}; };
@ -1502,8 +1510,8 @@ namespace chaiscript
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
{ {
return const_var(this->get_bool_condition(this->children[0]->eval(t_ss)) return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
|| this->get_bool_condition(this->children[1]->eval(t_ss))); || this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
} }
}; };
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_OPTIMIZER_HPP_ #ifndef CHAISCRIPT_OPTIMIZER_HPP_
@ -17,24 +17,33 @@ namespace chaiscript {
struct Optimizer : T... struct Optimizer : T...
{ {
Optimizer() = default; Optimizer() = default;
Optimizer(T ... t) explicit Optimizer(T ... t)
: T(std::move(t))... : T(std::move(t))...
{ {
} }
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) {
return true; return true;
} }
@ -96,8 +105,8 @@ 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
&& contains_var_decl_in_scope(child)) { && contains_var_decl_in_scope(child)) {
return true; return true;
} }
@ -108,15 +117,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 +137,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 +145,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 +157,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 +176,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.size() > 0) && !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));
} }
} }
} }
@ -195,17 +210,17 @@ namespace chaiscript {
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 || node->identifier == AST_Node_Type::Ternary_Cond) 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 +231,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 +243,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 +260,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 +269,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 +287,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 +296,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 +310,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 +328,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 +360,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::Equation
&& 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::Var_Decl
&& 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(child_at(eq_node,0), 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(child_at(eq_node,0), 0).text)
{ {
const Boxed_Value &begin = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(eq_node, 1))->m_value; const Boxed_Value &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 +397,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);

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_POSIX_HPP_ #ifndef CHAISCRIPT_POSIX_HPP_
@ -15,10 +15,10 @@ namespace chaiscript
{ {
struct DLModule struct DLModule
{ {
DLModule(const std::string &t_filename) explicit DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW)) : m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{ {
if (!m_data) if (m_data == nullptr)
{ {
throw chaiscript::exception::load_module_error(dlerror()); throw chaiscript::exception::load_module_error(dlerror());
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and 2009-2016, Jason Turner (jason@emptycrate.com) // and 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_ #ifndef CHAISCRIPT_PRELUDE_HPP_

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_TRACER_HPP_ #ifndef CHAISCRIPT_TRACER_HPP_
@ -10,10 +10,11 @@
namespace chaiscript { namespace chaiscript {
namespace eval { namespace eval {
struct Noop_Tracer
struct Noop_Tracer_Detail
{ {
template<typename T> template<typename T>
static void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *) void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
{ {
} }
}; };
@ -22,13 +23,13 @@ namespace chaiscript {
struct Tracer : T... struct Tracer : T...
{ {
Tracer() = default; Tracer() = default;
Tracer(T ... t) explicit Tracer(T ... t)
: T(std::move(t))... : T(std::move(t))...
{ {
} }
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) { void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(void)std::initializer_list<int>{ (T::trace(ds, node), 0)... }; (void)std::initializer_list<int>{ (static_cast<T&>(*this).trace(ds, node), 0)... };
} }
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) { static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
@ -36,6 +37,8 @@ namespace chaiscript {
} }
}; };
typedef Tracer<Noop_Tracer_Detail> Noop_Tracer;
} }
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_UNKNOWN_HPP_ #ifndef CHAISCRIPT_UNKNOWN_HPP_
@ -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;

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_WINDOWS_HPP_ #ifndef CHAISCRIPT_WINDOWS_HPP_
@ -80,7 +80,7 @@ namespace chaiscript
struct DLModule struct DLModule
{ {
DLModule(const std::string &t_filename) explicit DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str())) : m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
{ {
if (!m_data) if (!m_data)

View File

@ -0,0 +1,50 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include <cstdint>
#include "../chaiscript_defines.hpp"
namespace chaiscript
{
namespace utility
{
static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193));
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
}
}
#endif

View File

@ -386,12 +386,12 @@ class JSON
return "null"; return "null";
case Class::Object: { case Class::Object: {
std::string pad = ""; std::string pad = "";
for( long i = 0; i < depth; ++i, pad += tab ); for( long i = 0; i < depth; ++i, pad += tab ) { }
std::string s = "{\n"; std::string s = "{\n";
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 + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
skip = false; skip = false;
} }
@ -402,7 +402,7 @@ class JSON
std::string s = "["; std::string s = "[";
bool skip = true; bool skip = true;
for( auto &p : *internal.List ) { for( auto &p : *internal.List ) {
if( !skip ) s += ", "; if( !skip ) { s += ", "; }
s += p.dump( depth + 1, tab ); s += p.dump( depth + 1, tab );
skip = false; skip = false;
} }
@ -426,8 +426,8 @@ class JSON
private: private:
static std::string json_escape( const std::string &str ) { static std::string json_escape( const std::string &str ) {
std::string output; std::string output;
for( size_t i = 0; i < str.length(); ++i ) for(char i : str) {
switch( str[i] ) { switch( i ) {
case '\"': output += "\\\""; break; case '\"': output += "\\\""; break;
case '\\': output += "\\\\"; break; case '\\': output += "\\\\"; break;
case '\b': output += "\\b"; break; case '\b': output += "\\b"; break;
@ -435,8 +435,9 @@ class JSON
case '\n': output += "\\n"; break; case '\n': output += "\\n"; break;
case '\r': output += "\\r"; break; case '\r': output += "\\r"; break;
case '\t': output += "\\t"; break; case '\t': output += "\\t"; break;
default : output += str[i]; break; default : output += i; break;
} }
}
return output; return output;
} }
@ -462,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 ) {
@ -470,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");
} }
} }
@ -505,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;
} }
@ -513,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");
} }
} }
@ -529,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;
@ -543,10 +544,10 @@ 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 {
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'"); throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
} }
} }
@ -554,9 +555,9 @@ struct JSONParser {
} break; } break;
default : val += '\\'; break; default : val += '\\'; break;
} }
} } else {
else
val += c; val += c;
}
} }
++offset; ++offset;
return JSON(val); return JSON(val);
@ -566,33 +567,43 @@ struct JSONParser {
std::string val, exp_str; std::string val, exp_str;
char c = '\0'; char c = '\0';
bool isDouble = false; bool isDouble = false;
bool isNegative = false;
long exp = 0; long exp = 0;
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
break; break;
}
} }
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 == '-' ) { exp_str += '-';} if( c == '-' ) {
else if( c == '+' ) { } exp_str += '-';
else --offset; } else if( c == '+' ) {
// do nothing
} else {
--offset;
}
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 != '}' ) {
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'"); throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
} }
else else {
break; break;
}
} }
exp = chaiscript::parse_num<long>( exp_str ); exp = chaiscript::parse_num<long>( exp_str );
} }
@ -602,12 +613,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<long>( val )) * std::pow( 10, exp ));
} else { } else {
return JSON(chaiscript::parse_num<long>( val )); return JSON((isNegative?-1:1) * chaiscript::parse_num<long>( val ));
} }
} }
} }
@ -635,7 +646,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 );
@ -643,8 +654,9 @@ struct JSONParser {
case 't' : case 't' :
case 'f' : return parse_bool( str, offset ); case 'f' : return parse_bool( str, offset );
case 'n' : return parse_null( str, offset ); case 'n' : return parse_null( str, offset );
default : if( ( value <= '9' && value >= '0' ) || value == '-' ) default : if( ( value <= '9' && value >= '0' ) || value == '-' ) {
return parse_number( str, offset ); return parse_number( str, offset );
}
} }
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'"); throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
} }

View File

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

View File

@ -0,0 +1,37 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
namespace chaiscript
{
namespace utility
{
struct Static_String
{
template<size_t N>
constexpr Static_String(const char (&str)[N])
: m_size(N-1), data(&str[0])
{
}
constexpr size_t size() const {
return m_size;
}
constexpr const char *c_str() const {
return data;
}
const size_t m_size;
const char *data = nullptr;
};
}
}
#endif

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ #ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
#define CHAISCRIPT_UTILITY_UTILITY_HPP_ #define CHAISCRIPT_UTILITY_UTILITY_HPP_
@ -89,6 +93,29 @@ namespace chaiscript
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
} }
} }
template<typename EnumClass, typename ModuleType>
typename std::enable_if<std::is_enum<EnumClass>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<EnumClass, std::string>> &t_constants
)
{
t_module.add(chaiscript::user_type<EnumClass>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass(const EnumClass &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<EnumClass>(t_module);
not_equal<EnumClass>(t_module);
assign<EnumClass>(t_module);
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second);
}
}
} }
} }

View File

@ -17,7 +17,7 @@ ChaiScript
http://www.chaiscript.com http://www.chaiscript.com
(c) 2009-2012 Jonathan Turner (c) 2009-2012 Jonathan Turner
(c) 2009-2016 Jason Turner (c) 2009-2017 Jason Turner
Release under the BSD license, see "license.txt" for details. Release under the BSD license, see "license.txt" for details.
@ -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);");
}
```

View File

@ -26,13 +26,20 @@ Current Version: 6.0.0
* Modular optimization system; this can be accessed via the ChaiScript_Basic interface * Modular optimization system; this can be accessed via the ChaiScript_Basic interface
* Execution tracing capability; also accessed via ChaiScript_Basic interface * Execution tracing capability; also accessed via ChaiScript_Basic interface
* range-based for loops `for( id : container ) { }` * range-based for loops `for( id : container ) { }` (much better performance than other loop types)
* If-init expressions (ala C++17)
* Support for passing r-value references to functions
* Support for containing unique_ptr
* Add helpers for exposing enum classes to ChaiScript
* Allow typed ChaiScript defined functions to perform conversions on call #303
#### Improvements #### Improvements
* Compile time improvements * Compile time improvements
* Compile size improvements * Compile size improvements
* Significant runtime improvements (see "Modular optimization system") * Significant runtime improvements (see "Modular optimization system")
* Significant parser improvements, both with parse-time and parser initialization time (Thanks @niXman)
* Fix type conversion to bool in conditionals
#### Improvements Still Need To Be Made #### Improvements Still Need To Be Made
@ -41,6 +48,9 @@ Current Version: 6.0.0
### Changes since 5.8.5 ### Changes since 5.8.5
* Optimize away `return` statements in lambdas also * Optimize away `return` statements in lambdas also
* Allow conversions to bool in conditionals
* Don't allow `class` statements inside of scopes
* Properly error when a dynamic object non-function member is called
### Changes since 5.8.4 ### Changes since 5.8.4
* Fix order of operations for prefix operators * Fix order of operations for prefix operators

12
samples/BUCK Normal file
View File

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

View File

@ -108,9 +108,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
// A shortcut to using eval is just to use the chai operator() // A shortcut to using eval is just to use the chai operator()
chai("log(\"Test Module\", \"Test Message\");"); chai("log(\"Test Module\", \"Test Message\");");
//Finally, it is possible to register any std::function 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
chai.add(fun(&System::do_callbacks, std::ref(system), std::string("Bound Test")), "do_callbacks"); chai.add(fun([&system](){ return system.do_callbacks("Bound Test"); }), "do_callbacks");
//Call bound version of do_callbacks //Call bound version of do_callbacks
chai("do_callbacks()"); chai("do_callbacks()");

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <regex> #include <regex>
@ -64,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);
@ -133,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;
} }
@ -246,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;
} }

342
src/libfuzzer_client.cpp Normal file
View 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;
}

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <regex> #include <regex>
@ -25,7 +29,7 @@
char *mystrdup (const char *s) { char *mystrdup (const char *s) {
size_t len = strlen(s); // Space for length plus nul size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char*>(malloc (len+1)); char *d = static_cast<char*>(malloc (len+1));
if (d == nullptr) return nullptr; // No memory if (d == nullptr) { return nullptr; } // No memory
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
strcpy_s(d, len+1, s); // Copy the characters strcpy_s(d, len+1, s); // Copy the characters
#else #else
@ -44,7 +48,7 @@ char* readline(const char* p)
} }
void add_history(const char*){} void add_history(const char* /*unused*/){}
void using_history(){} void using_history(){}
#endif #endif
@ -67,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);
@ -116,7 +121,7 @@ std::vector<std::string> default_search_paths()
{ {
Dl_info rInfo; Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) ); memset( &rInfo, 0, sizeof(rInfo) );
if ( !dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname ) { if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) {
return paths; return paths;
} }
@ -136,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;
} }
@ -184,7 +190,7 @@ std::string get_next_command() {
std::string retval("quit"); std::string retval("quit");
if ( ! std::cin.eof() ) { if ( ! std::cin.eof() ) {
char *input_raw = readline("eval> "); char *input_raw = readline("eval> ");
if ( input_raw ) { if ( input_raw != nullptr ) {
add_history(input_raw); add_history(input_raw);
std::string val(input_raw); std::string val(input_raw);
@ -240,8 +246,8 @@ 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.size() > 0) { 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';
} }
@ -277,7 +283,7 @@ int main(int argc, char *argv[])
std::vector<std::string> usepaths; std::vector<std::string> usepaths;
usepaths.push_back(""); usepaths.push_back("");
if (usepath) if (usepath != nullptr)
{ {
usepaths.push_back(usepath); usepaths.push_back(usepath);
} }
@ -286,7 +292,7 @@ int main(int argc, char *argv[])
std::vector<std::string> searchpaths = default_search_paths(); std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end()); modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.push_back(""); modulepaths.push_back("");
if (modulepath) if (modulepath != nullptr)
{ {
modulepaths.push_back(modulepath); modulepaths.push_back(modulepath);
} }
@ -302,13 +308,14 @@ int main(int argc, char *argv[])
bool eval_error_ok = false; bool eval_error_ok = false;
bool boxed_exception_ok = false; bool boxed_exception_ok = false;
bool any_exception_ok = false;
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
if ( i == 0 && argc > 1 ) { if ( i == 0 && argc > 1 ) {
++i; ++i;
} }
std::string arg( i ? argv[i] : "--interactive" ); std::string arg( i != 0 ? argv[i] : "--interactive" );
enum { eInteractive enum { eInteractive
, eCommand , eCommand
@ -319,9 +326,9 @@ int main(int argc, char *argv[])
if ( (i+1) >= argc ) { if ( (i+1) >= argc ) {
std::cout << "insufficient input following " << arg << '\n'; std::cout << "insufficient input following " << arg << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} else { }
arg = argv[++i]; arg = argv[++i];
}
} else if ( arg == "-" || arg == "--stdin" ) { } else if ( arg == "-" || arg == "--stdin" ) {
arg = "" ; arg = "" ;
std::string line; std::string line;
@ -338,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 ) {
@ -377,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;

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <chaiscript/chaiscript_basic.hpp> #include <chaiscript/chaiscript_basic.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp> #include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <list> #include <list>

View File

@ -1,6 +1,6 @@
/* /*
* Catch v1.3.5 * Catch v1.5.7
* Generated: 2016-02-29 08:16:42.342094 * Generated: 2016-09-27 10:45:46.824849
* ---------------------------------------------------------- * ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly * This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@ -62,7 +62,11 @@
#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #ifdef CATCH_CONFIG_COUNTER
# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
#else
# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
#endif
#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
@ -89,7 +93,7 @@
// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
// **************** // ****************
// Note to maintainers: if new toggles are added please document them // Note to maintainers: if new toggles are added please document them
// in configuration.md, too // in configuration.md, too
@ -102,8 +106,16 @@
// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
#if defined(__cplusplus) && __cplusplus >= 201103L #ifdef __cplusplus
# define CATCH_CPP11_OR_GREATER
# if __cplusplus >= 201103L
# define CATCH_CPP11_OR_GREATER
# endif
# if __cplusplus >= 201402L
# define CATCH_CPP14_OR_GREATER
# endif
#endif #endif
#ifdef __clang__ #ifdef __clang__
@ -185,6 +197,15 @@
#endif #endif
// Use __COUNTER__ if the compiler supports it
#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \
( defined __clang__ && __clang_major__ >= 3 )
#define CATCH_INTERNAL_CONFIG_COUNTER
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// C++ language feature support // C++ language feature support
@ -256,6 +277,9 @@
#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) #if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_UNIQUE_PTR # define CATCH_CONFIG_CPP11_UNIQUE_PTR
#endif #endif
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
# define CATCH_CONFIG_COUNTER
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
@ -686,24 +710,28 @@ void registerTestCaseFunction
#ifdef CATCH_CONFIG_VARIADIC_MACROS #ifdef CATCH_CONFIG_VARIADIC_MACROS
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
static void TestName(); \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
static void TestName()
#define INTERNAL_CATCH_TESTCASE( ... ) \ #define INTERNAL_CATCH_TESTCASE( ... ) \
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
namespace{ \ namespace{ \
struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ struct TestName : ClassName{ \
void test(); \ void test(); \
}; \ }; \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
} \ } \
void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() void TestName::test()
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
@ -711,24 +739,28 @@ void registerTestCaseFunction
#else #else
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
static void TestName(); \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
static void TestName()
#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
namespace{ \ namespace{ \
struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ struct TestCaseName : ClassName{ \
void test(); \ void test(); \
}; \ }; \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
} \ } \
void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() void TestCaseName::test()
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
@ -2041,7 +2073,7 @@ namespace Catch {
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
} \ } \
INTERNAL_CATCH_REACT( __catchResult ) \ INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::isTrue( false && static_cast<bool>(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look } while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
@ -2578,10 +2610,12 @@ namespace Catch {
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ static std::string translatorName( signature ); \
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) static std::string translatorName( signature )
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
// #included from: internal/catch_approx.hpp // #included from: internal/catch_approx.hpp
#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
@ -3189,10 +3223,11 @@ namespace Catch {
bool matches( TestCaseInfo const& testCase ) const { bool matches( TestCaseInfo const& testCase ) const {
// All patterns in a filter must match for the filter to be a match // All patterns in a filter must match for the filter to be a match
for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
if( !(*it)->matches( testCase ) ) if( !(*it)->matches( testCase ) )
return false; return false;
return true; }
return true;
} }
}; };
@ -3424,7 +3459,7 @@ namespace Catch {
}; };
class DebugOutStream : public IStream { class DebugOutStream : public IStream {
std::auto_ptr<StreamBufBase> m_streamBuf; CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
mutable std::ostream m_os; mutable std::ostream m_os;
public: public:
DebugOutStream(); DebugOutStream();
@ -3572,7 +3607,7 @@ namespace Catch {
} }
ConfigData m_data; ConfigData m_data;
std::auto_ptr<IStream const> m_stream; CATCH_AUTO_PTR( IStream const ) m_stream;
TestSpec m_testSpec; TestSpec m_testSpec;
}; };
@ -3592,7 +3627,7 @@ namespace Catch {
#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
// #included from: ../external/clara.h // #included from: ../external/clara.h
// Version 0.0.1.1 // Version 0.0.2.4
// Only use header guard if we are not using an outer namespace // Only use header guard if we are not using an outer namespace
#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
@ -3908,6 +3943,10 @@ namespace Tbc {
#include <stdexcept> #include <stdexcept>
#include <memory> #include <memory>
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define CLARA_PLATFORM_WINDOWS
#endif
// Use optional outer namespace // Use optional outer namespace
#ifdef STITCH_CLARA_OPEN_NAMESPACE #ifdef STITCH_CLARA_OPEN_NAMESPACE
STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
@ -3931,9 +3970,6 @@ namespace Clara {
const unsigned int consoleWidth = 80; const unsigned int consoleWidth = 80;
#endif #endif
// Use this to try and stop compiler from warning about unreachable code
inline bool isTrue( bool value ) { return value; }
using namespace Tbc; using namespace Tbc;
inline bool startsWith( std::string const& str, std::string const& prefix ) { inline bool startsWith( std::string const& str, std::string const& prefix ) {
@ -3969,14 +4005,6 @@ namespace Clara {
else else
throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
} }
inline void convertInto( bool _source, bool& _dest ) {
_dest = _source;
}
template<typename T>
inline void convertInto( bool, T& ) {
if( isTrue( true ) )
throw std::runtime_error( "Invalid conversion" );
}
template<typename ConfigT> template<typename ConfigT>
struct IArgFunction { struct IArgFunction {
@ -3986,7 +4014,6 @@ namespace Clara {
IArgFunction( IArgFunction const& ) = default; IArgFunction( IArgFunction const& ) = default;
#endif #endif
virtual void set( ConfigT& config, std::string const& value ) const = 0; virtual void set( ConfigT& config, std::string const& value ) const = 0;
virtual void setFlag( ConfigT& config ) const = 0;
virtual bool takesArg() const = 0; virtual bool takesArg() const = 0;
virtual IArgFunction* clone() const = 0; virtual IArgFunction* clone() const = 0;
}; };
@ -4008,9 +4035,6 @@ namespace Clara {
void set( ConfigT& config, std::string const& value ) const { void set( ConfigT& config, std::string const& value ) const {
functionObj->set( config, value ); functionObj->set( config, value );
} }
void setFlag( ConfigT& config ) const {
functionObj->setFlag( config );
}
bool takesArg() const { return functionObj->takesArg(); } bool takesArg() const { return functionObj->takesArg(); }
bool isSet() const { bool isSet() const {
@ -4023,7 +4047,6 @@ namespace Clara {
template<typename C> template<typename C>
struct NullBinder : IArgFunction<C>{ struct NullBinder : IArgFunction<C>{
virtual void set( C&, std::string const& ) const {} virtual void set( C&, std::string const& ) const {}
virtual void setFlag( C& ) const {}
virtual bool takesArg() const { return true; } virtual bool takesArg() const { return true; }
virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
}; };
@ -4034,9 +4057,6 @@ namespace Clara {
virtual void set( C& p, std::string const& stringValue ) const { virtual void set( C& p, std::string const& stringValue ) const {
convertInto( stringValue, p.*member ); convertInto( stringValue, p.*member );
} }
virtual void setFlag( C& p ) const {
convertInto( true, p.*member );
}
virtual bool takesArg() const { return !IsBool<M>::value; } virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
M C::* member; M C::* member;
@ -4049,11 +4069,6 @@ namespace Clara {
convertInto( stringValue, value ); convertInto( stringValue, value );
(p.*member)( value ); (p.*member)( value );
} }
virtual void setFlag( C& p ) const {
typename RemoveConstRef<M>::type value;
convertInto( true, value );
(p.*member)( value );
}
virtual bool takesArg() const { return !IsBool<M>::value; } virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
void (C::*member)( M ); void (C::*member)( M );
@ -4067,9 +4082,6 @@ namespace Clara {
if( value ) if( value )
(p.*member)(); (p.*member)();
} }
virtual void setFlag( C& p ) const {
(p.*member)();
}
virtual bool takesArg() const { return false; } virtual bool takesArg() const { return false; }
virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
void (C::*member)(); void (C::*member)();
@ -4084,9 +4096,6 @@ namespace Clara {
if( value ) if( value )
function( obj ); function( obj );
} }
virtual void setFlag( C& p ) const {
function( p );
}
virtual bool takesArg() const { return false; } virtual bool takesArg() const { return false; }
virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
void (*function)( C& ); void (*function)( C& );
@ -4100,11 +4109,6 @@ namespace Clara {
convertInto( stringValue, value ); convertInto( stringValue, value );
function( obj, value ); function( obj, value );
} }
virtual void setFlag( C& obj ) const {
typename RemoveConstRef<T>::type value;
convertInto( true, value );
function( obj, value );
}
virtual bool takesArg() const { return !IsBool<T>::value; } virtual bool takesArg() const { return !IsBool<T>::value; }
virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
void (*function)( C&, T ); void (*function)( C&, T );
@ -4112,8 +4116,20 @@ namespace Clara {
} // namespace Detail } // namespace Detail
struct Parser { inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
Parser() : separators( " \t=:" ) {} std::vector<std::string> args( static_cast<std::size_t>( argc ) );
for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
args[i] = argv[i];
return args;
}
class Parser {
enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
Mode mode;
std::size_t from;
bool inQuotes;
public:
struct Token { struct Token {
enum Type { Positional, ShortOpt, LongOpt }; enum Type { Positional, ShortOpt, LongOpt };
@ -4122,38 +4138,75 @@ namespace Clara {
std::string data; std::string data;
}; };
void parseIntoTokens( int argc, char const* const argv[], std::vector<Parser::Token>& tokens ) const { Parser() : mode( None ), from( 0 ), inQuotes( false ){}
void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
const std::string doubleDash = "--"; const std::string doubleDash = "--";
for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
parseIntoTokens( argv[i] , tokens); parseIntoTokens( args[i], tokens);
} }
void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
while( !arg.empty() ) { void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
Parser::Token token( Parser::Token::Positional, arg ); for( std::size_t i = 0; i <= arg.size(); ++i ) {
arg = ""; char c = arg[i];
if( token.data[0] == '-' ) { if( c == '"' )
if( token.data.size() > 1 && token.data[1] == '-' ) { inQuotes = !inQuotes;
token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); mode = handleMode( i, c, arg, tokens );
}
else {
token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
arg = "-" + token.data.substr( 1 );
token.data = token.data.substr( 0, 1 );
}
}
}
if( token.type != Parser::Token::Positional ) {
std::size_t pos = token.data.find_first_of( separators );
if( pos != std::string::npos ) {
arg = token.data.substr( pos+1 );
token.data = token.data.substr( 0, pos );
}
}
tokens.push_back( token );
} }
} }
std::string separators; Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
switch( mode ) {
case None: return handleNone( i, c );
case MaybeShortOpt: return handleMaybeShortOpt( i, c );
case ShortOpt:
case LongOpt:
case SlashOpt: return handleOpt( i, c, arg, tokens );
case Positional: return handlePositional( i, c, arg, tokens );
default: throw std::logic_error( "Unknown mode" );
}
}
Mode handleNone( std::size_t i, char c ) {
if( inQuotes ) {
from = i;
return Positional;
}
switch( c ) {
case '-': return MaybeShortOpt;
#ifdef CLARA_PLATFORM_WINDOWS
case '/': from = i+1; return SlashOpt;
#endif
default: from = i; return Positional;
}
}
Mode handleMaybeShortOpt( std::size_t i, char c ) {
switch( c ) {
case '-': from = i+1; return LongOpt;
default: from = i; return ShortOpt;
}
}
Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
return mode;
std::string optName = arg.substr( from, i-from );
if( mode == ShortOpt )
for( std::size_t j = 0; j < optName.size(); ++j )
tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
else if( mode == SlashOpt && optName.size() == 1 )
tokens.push_back( Token( Token::ShortOpt, optName ) );
else
tokens.push_back( Token( Token::LongOpt, optName ) );
return None;
}
Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
return mode;
std::string data = arg.substr( from, i-from );
tokens.push_back( Token( Token::Positional, data ) );
return None;
}
}; };
template<typename ConfigT> template<typename ConfigT>
@ -4456,21 +4509,21 @@ namespace Clara {
return oss.str(); return oss.str();
} }
ConfigT parse( int argc, char const* const argv[] ) const { ConfigT parse( std::vector<std::string> const& args ) const {
ConfigT config; ConfigT config;
parseInto( argc, argv, config ); parseInto( args, config );
return config; return config;
} }
std::vector<Parser::Token> parseInto( int argc, char const* argv[], ConfigT& config ) const { std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
std::string processName = argv[0]; std::string processName = args[0];
std::size_t lastSlash = processName.find_last_of( "/\\" ); std::size_t lastSlash = processName.find_last_of( "/\\" );
if( lastSlash != std::string::npos ) if( lastSlash != std::string::npos )
processName = processName.substr( lastSlash+1 ); processName = processName.substr( lastSlash+1 );
m_boundProcessName.set( config, processName ); m_boundProcessName.set( config, processName );
std::vector<Parser::Token> tokens; std::vector<Parser::Token> tokens;
Parser parser; Parser parser;
parser.parseIntoTokens( argc, argv, tokens ); parser.parseIntoTokens( args, tokens );
return populate( tokens, config ); return populate( tokens, config );
} }
@ -4501,7 +4554,7 @@ namespace Clara {
arg.boundField.set( config, tokens[++i].data ); arg.boundField.set( config, tokens[++i].data );
} }
else { else {
arg.boundField.setFlag( config ); arg.boundField.set( config, "true" );
} }
break; break;
} }
@ -4667,8 +4720,11 @@ namespace Catch {
std::string line; std::string line;
while( std::getline( f, line ) ) { while( std::getline( f, line ) ) {
line = trim(line); line = trim(line);
if( !line.empty() && !startsWith( line, "#" ) ) if( !line.empty() && !startsWith( line, "#" ) ) {
addTestOrTags( config, "\"" + line + "\"," ); if( !startsWith( line, "\"" ) )
line = "\"" + line + "\"";
addTestOrTags( config, line + "," );
}
} }
} }
@ -5209,6 +5265,8 @@ namespace Catch
bool aborting; bool aborting;
}; };
class MultipleReporters;
struct IStreamingReporter : IShared { struct IStreamingReporter : IShared {
virtual ~IStreamingReporter(); virtual ~IStreamingReporter();
@ -5236,6 +5294,8 @@ namespace Catch
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
virtual void skipTest( TestCaseInfo const& testInfo ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
}; };
struct IReporterFactory : IShared { struct IReporterFactory : IShared {
@ -5312,7 +5372,10 @@ namespace Catch {
++it ) { ++it ) {
matchedTests++; matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
Catch::cout() << testCaseInfo.name << std::endl; if( startsWith( testCaseInfo.name, "#" ) )
Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl;
else
Catch::cout() << testCaseInfo.name << std::endl;
} }
return matchedTests; return matchedTests;
} }
@ -5453,6 +5516,10 @@ namespace TestCaseTracking {
virtual void addChild( Ptr<ITracker> const& child ) = 0; virtual void addChild( Ptr<ITracker> const& child ) = 0;
virtual ITracker* findChild( std::string const& name ) = 0; virtual ITracker* findChild( std::string const& name ) = 0;
virtual void openChild() = 0; virtual void openChild() = 0;
// Debug/ checking
virtual bool isSectionTracker() const = 0;
virtual bool isIndexTracker() const = 0;
}; };
class TrackerContext { class TrackerContext {
@ -5577,6 +5644,10 @@ namespace TestCaseTracking {
m_parent->openChild(); m_parent->openChild();
} }
} }
virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
void open() { void open() {
m_runState = Executing; m_runState = Executing;
moveToThis(); moveToThis();
@ -5640,13 +5711,16 @@ namespace TestCaseTracking {
{} {}
virtual ~SectionTracker(); virtual ~SectionTracker();
virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
SectionTracker* section = CATCH_NULL; SectionTracker* section = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker(); ITracker& currentTracker = ctx.currentTracker();
if( ITracker* childTracker = currentTracker.findChild( name ) ) { if( ITracker* childTracker = currentTracker.findChild( name ) ) {
section = dynamic_cast<SectionTracker*>( childTracker ); assert( childTracker );
assert( section ); assert( childTracker->isSectionTracker() );
section = static_cast<SectionTracker*>( childTracker );
} }
else { else {
section = new SectionTracker( name, ctx, &currentTracker ); section = new SectionTracker( name, ctx, &currentTracker );
@ -5671,13 +5745,16 @@ namespace TestCaseTracking {
{} {}
virtual ~IndexTracker(); virtual ~IndexTracker();
virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
IndexTracker* tracker = CATCH_NULL; IndexTracker* tracker = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker(); ITracker& currentTracker = ctx.currentTracker();
if( ITracker* childTracker = currentTracker.findChild( name ) ) { if( ITracker* childTracker = currentTracker.findChild( name ) ) {
tracker = dynamic_cast<IndexTracker*>( childTracker ); assert( childTracker );
assert( tracker ); assert( childTracker->isIndexTracker() );
tracker = static_cast<IndexTracker*>( childTracker );
} }
else { else {
tracker = new IndexTracker( name, ctx, &currentTracker, size ); tracker = new IndexTracker( name, ctx, &currentTracker, size );
@ -5884,6 +5961,11 @@ namespace Catch {
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
Totals deltaTotals = m_totals.delta( prevTotals ); Totals deltaTotals = m_totals.delta( prevTotals );
if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
deltaTotals.assertions.failed++;
deltaTotals.testCases.passed--;
deltaTotals.testCases.failed++;
}
m_totals.testCases += deltaTotals.testCases; m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded( TestCaseStats( testInfo, m_reporter->testCaseEnded( TestCaseStats( testInfo,
deltaTotals, deltaTotals,
@ -6275,10 +6357,10 @@ namespace Catch {
Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
} }
int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
try { try {
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
if( m_configData.showHelp ) if( m_configData.showHelp )
showHelp( m_configData.processName ); showHelp( m_configData.processName );
m_config.reset(); m_config.reset();
@ -6302,16 +6384,13 @@ namespace Catch {
m_config.reset(); m_config.reset();
} }
int run( int argc, char const* argv[] ) { int run( int argc, char const* const* const argv ) {
int returnCode = applyCommandLine( argc, argv ); int returnCode = applyCommandLine( argc, argv );
if( returnCode == 0 ) if( returnCode == 0 )
returnCode = run(); returnCode = run();
return returnCode; return returnCode;
} }
int run( int argc, char* argv[] ) {
return run( argc, const_cast<char const**>( argv ) );
}
int run() { int run() {
if( m_configData.showHelp ) if( m_configData.showHelp )
@ -6375,13 +6454,31 @@ namespace Catch {
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#ifdef CATCH_CPP14_OR_GREATER
#include <random>
#endif
namespace Catch { namespace Catch {
struct LexSort {
bool operator() (TestCase i,TestCase j) const { return (i<j);}
};
struct RandomNumberGenerator { struct RandomNumberGenerator {
int operator()( int n ) const { return std::rand() % n; } typedef int result_type;
result_type operator()( result_type n ) const { return std::rand() % n; }
#ifdef CATCH_CPP14_OR_GREATER
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return 1000000; }
result_type operator()() const { return std::rand() % max(); }
#endif
template<typename V>
static void shuffle( V& vector ) {
RandomNumberGenerator rng;
#ifdef CATCH_CPP14_OR_GREATER
std::shuffle( vector.begin(), vector.end(), rng );
#else
std::random_shuffle( vector.begin(), vector.end(), rng );
#endif
}
}; };
inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
@ -6390,14 +6487,12 @@ namespace Catch {
switch( config.runOrder() ) { switch( config.runOrder() ) {
case RunTests::InLexicographicalOrder: case RunTests::InLexicographicalOrder:
std::sort( sorted.begin(), sorted.end(), LexSort() ); std::sort( sorted.begin(), sorted.end() );
break; break;
case RunTests::InRandomOrder: case RunTests::InRandomOrder:
{ {
seedRng( config ); seedRng( config );
RandomNumberGenerator::shuffle( sorted );
RandomNumberGenerator rng;
std::random_shuffle( sorted.begin(), sorted.end(), rng );
} }
break; break;
case RunTests::InDeclarationOrder: case RunTests::InDeclarationOrder:
@ -6416,13 +6511,15 @@ namespace Catch {
it != itEnd; it != itEnd;
++it ) { ++it ) {
std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it ); std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
if( !prev.second ){ if( !prev.second ) {
Catch::cerr() std::ostringstream ss;
<< Colour( Colour::Red )
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" ss << Colour( Colour::Red )
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
exit(1); << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
throw std::runtime_error(ss.str());
} }
} }
} }
@ -7481,7 +7578,7 @@ namespace Catch {
return os; return os;
} }
Version libraryVersion( 1, 3, 5, "", 0 ); Version libraryVersion( 1, 5, 7, "", 0 );
} }
@ -8460,13 +8557,18 @@ public: // IStreamingReporter
++it ) ++it )
(*it)->skipTest( testInfo ); (*it)->skipTest( testInfo );
} }
virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
return this;
}
}; };
Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) { Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
Ptr<IStreamingReporter> resultingReporter; Ptr<IStreamingReporter> resultingReporter;
if( existingReporter ) { if( existingReporter ) {
MultipleReporters* multi = dynamic_cast<MultipleReporters*>( existingReporter.get() ); MultipleReporters* multi = existingReporter->tryAsMulti();
if( !multi ) { if( !multi ) {
multi = new MultipleReporters; multi = new MultipleReporters;
resultingReporter = Ptr<IStreamingReporter>( multi ); resultingReporter = Ptr<IStreamingReporter>( multi );
@ -8646,7 +8748,7 @@ namespace Catch {
virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
virtual bool assertionEnded( AssertionStats const& assertionStats ) { virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
assert( !m_sectionStack.empty() ); assert( !m_sectionStack.empty() );
SectionNode& sectionNode = *m_sectionStack.back(); SectionNode& sectionNode = *m_sectionStack.back();
sectionNode.assertions.push_back( assertionStats ); sectionNode.assertions.push_back( assertionStats );
@ -8856,9 +8958,10 @@ namespace Catch {
break; break;
default: default:
// Escape control chars - based on contribution by @espenalb in PR #465 // Escape control chars - based on contribution by @espenalb in PR #465 and
// by @mrpi PR #588
if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
os << "&#x" << std::uppercase << std::hex << static_cast<int>( c ); os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';';
else else
os << c; os << c;
} }
@ -8913,13 +9016,20 @@ namespace Catch {
: m_tagIsOpen( false ), : m_tagIsOpen( false ),
m_needsNewline( false ), m_needsNewline( false ),
m_os( &Catch::cout() ) m_os( &Catch::cout() )
{} {
// We encode control characters, which requires
// XML 1.1
// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
XmlWriter( std::ostream& os ) XmlWriter( std::ostream& os )
: m_tagIsOpen( false ), : m_tagIsOpen( false ),
m_needsNewline( false ), m_needsNewline( false ),
m_os( &os ) m_os( &os )
{} {
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
~XmlWriter() { ~XmlWriter() {
while( !m_tags.empty() ) while( !m_tags.empty() )
@ -9086,7 +9196,7 @@ namespace Catch {
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseStarting(testInfo); StreamingReporterBase::testCaseStarting(testInfo);
m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.name );
if ( m_config->showDurations() == ShowDurations::Always ) if ( m_config->showDurations() == ShowDurations::Always )
m_testCaseTimer.start(); m_testCaseTimer.start();
@ -9777,7 +9887,7 @@ namespace Catch {
if( totals.testCases.total() == 0 ) { if( totals.testCases.total() == 0 ) {
stream << Colour( Colour::Warning ) << "No tests ran\n"; stream << Colour( Colour::Warning ) << "No tests ran\n";
} }
else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
stream << Colour( Colour::ResultSuccess ) << "All tests passed"; stream << Colour( Colour::ResultSuccess ) << "All tests passed";
stream << " (" stream << " ("
<< pluralise( totals.assertions.passed, "assertion" ) << " in " << pluralise( totals.assertions.passed, "assertion" ) << " in "

View File

@ -0,0 +1,8 @@
try {
parse("{ class C { var data; def C() {} } }")
assert_false(true)
} catch (e) {
assert_true(true)
}

View File

@ -12,9 +12,12 @@
#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
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_basic.hpp> #include <chaiscript/chaiscript_basic.hpp>
#include <chaiscript/utility/utility.hpp> #include <chaiscript/utility/utility.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp> #include <chaiscript/dispatchkit/bootstrap_stl.hpp>
@ -197,7 +200,7 @@ TEST_CASE("Throw int or double")
chai.eval("throw(1.0)", chaiscript::exception_specification<int, double>()); chai.eval("throw(1.0)", chaiscript::exception_specification<int, double>());
REQUIRE(false); REQUIRE(false);
} catch (const double e) { } catch (const double e) {
CHECK(e == 1.0); CHECK(e == Approx(1.0));
} }
} }
@ -982,4 +985,341 @@ TEST_CASE("type_conversion to bool")
module->add(chaiscript::type_conversion<T, bool>()); module->add(chaiscript::type_conversion<T, bool>());
} }
TEST_CASE("Make sure ChaiScript object still compiles / executes")
{
chaiscript::ChaiScript chai;
}
struct Count_Tracer
{
int count = 0;
template<typename T>
void trace(const chaiscript::detail::Dispatch_State &, const chaiscript::eval::AST_Node_Impl<T> *)
{
++count;
}
};
TEST_CASE("Test count tracer")
{
typedef chaiscript::parser::ChaiScript_Parser< chaiscript::eval::Tracer<Count_Tracer>, chaiscript::optimizer::Optimizer_Default > Parser_Type;
chaiscript::ChaiScript_Basic chai(chaiscript::Std_Lib::library(),
std::make_unique<Parser_Type>());
Parser_Type &parser = dynamic_cast<Parser_Type &>(chai.get_parser());
const auto count = parser.get_tracer().count;
chai.eval("");
CHECK(parser.get_tracer().count > count);
}
TEST_CASE("Test stdlib options")
{
const auto test_has_external_scripts = [](chaiscript::ChaiScript_Basic &chai) {
CHECK_NOTHROW(chai.eval("`use`"));
CHECK_NOTHROW(chai.eval("`eval_file`"));
};
const auto test_no_external_scripts = [](chaiscript::ChaiScript_Basic &chai) {
CHECK_THROWS(chai.eval("`use`"));
CHECK_THROWS(chai.eval("`eval_file`"));
};
const auto test_has_load_modules = [](chaiscript::ChaiScript_Basic &chai) {
CHECK_NOTHROW(chai.eval("`load_module`"));
};
const auto test_no_load_modules = [](chaiscript::ChaiScript_Basic &chai) {
CHECK_THROWS(chai.eval("`load_module`"));
};
SECTION( "Defaults" ) {
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
test_has_external_scripts(chai);
test_has_load_modules(chai);
}
SECTION( "Load_Modules, External_Scripts" ) {
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
{chaiscript::Options::Load_Modules, chaiscript::Options::External_Scripts} );
test_has_external_scripts(chai);
test_has_load_modules(chai);
}
SECTION( "No_Load_Modules, No_External_Scripts" ) {
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
{chaiscript::Options::No_Load_Modules, chaiscript::Options::No_External_Scripts} );
test_no_external_scripts(chai);
test_no_load_modules(chai);
}
SECTION( "No_Load_Modules, Load_Modules" ) {
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
{chaiscript::Options::No_Load_Modules, chaiscript::Options::Load_Modules} );
test_no_external_scripts(chai);
test_no_load_modules(chai);
}
SECTION( "No_External_Scripts, External_Scripts" ) {
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
{chaiscript::Options::No_External_Scripts, chaiscript::Options::External_Scripts} );
test_no_external_scripts(chai);
test_no_load_modules(chai);
}
SECTION( "No_External_Scripts, Load_Modules" ) {
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
{chaiscript::Options::No_External_Scripts, chaiscript::Options::Load_Modules} );
test_no_external_scripts(chai);
test_has_load_modules(chai);
}
SECTION( "External_Scripts, No_Load_Modules" ) {
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
{chaiscript::Options::External_Scripts, chaiscript::Options::No_Load_Modules} );
test_has_external_scripts(chai);
test_no_load_modules(chai);
}
}
void uservalueref(int &&)
{
}
void usemoveonlytype(std::unique_ptr<int> &&)
{
}
TEST_CASE("Pass r-value reference to func")
{
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
chai.add(chaiscript::fun(&uservalueref), "uservalueref");
chai.add(chaiscript::fun(&usemoveonlytype), "usemoveonlytype");
chai.add(chaiscript::var(std::make_unique<int>(1)), "iptr");
chai.eval("usemoveonlytype(iptr)");
}
TEST_CASE("Use unique_ptr")
{
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
chai.add(chaiscript::fun([](int &i){ ++i; }), "inci");
chai.add(chaiscript::fun([](int i){ ++i; }), "copyi");
chai.add(chaiscript::fun([](int *i){ ++(*i); }), "derefi");
chai.add(chaiscript::fun([](const std::unique_ptr<int> &i){ ++(*i); }), "constrefuniqptri");
chai.add(chaiscript::fun([](std::unique_ptr<int> &i){ ++(*i); }), "refuniqptri");
chai.add(chaiscript::fun([](std::unique_ptr<int> &&i){ ++(*i); }), "rvaluniqptri");
chai.add(chaiscript::var(std::make_unique<int>(1)), "iptr");
CHECK(chai.eval<int>("iptr") == 1);
chai.eval("inci(iptr)");
CHECK(chai.eval<int>("iptr") == 2);
chai.eval("copyi(iptr)");
CHECK(chai.eval<int>("iptr") == 2);
chai.eval("derefi(iptr)");
CHECK(chai.eval<int>("iptr") == 3);
chai.eval("constrefuniqptri(iptr)");
CHECK(chai.eval<int>("iptr") == 4);
chai.eval("refuniqptri(iptr)");
CHECK(chai.eval<int>("iptr") == 5);
chai.eval("rvaluniqptri(iptr)");
CHECK(chai.eval<int>("iptr") == 6);
}
class Unique_Ptr_Test_Class
{
public:
Unique_Ptr_Test_Class() = default;
Unique_Ptr_Test_Class(const Unique_Ptr_Test_Class&) = default;
Unique_Ptr_Test_Class(Unique_Ptr_Test_Class &&) = default;
Unique_Ptr_Test_Class &operator=(const Unique_Ptr_Test_Class&) = default;
Unique_Ptr_Test_Class &operator=(Unique_Ptr_Test_Class&&) = default;
virtual ~Unique_Ptr_Test_Class() = default;
int getI() const {return 5;}
};
std::unique_ptr<Unique_Ptr_Test_Class> make_Unique_Ptr_Test_Class()
{
return std::make_unique<Unique_Ptr_Test_Class>();
}
TEST_CASE("Call methods through unique_ptr")
{
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
chai.add(chaiscript::var(std::make_unique<Unique_Ptr_Test_Class>()), "uptr");
chai.add(chaiscript::fun(make_Unique_Ptr_Test_Class), "make_Unique_Ptr_Test_Class");
chai.add(chaiscript::fun(&Unique_Ptr_Test_Class::getI), "getI");
CHECK(chai.eval<int>("uptr.getI()") == 5);
CHECK(chai.eval<int>("var uptr2 = make_Unique_Ptr_Test_Class(); uptr2.getI()") == 5);
}
class Unique_Ptr_Test_Base_Class
{
public:
int getI() const {return 5;}
};
class Unique_Ptr_Test_Derived_Class : public Unique_Ptr_Test_Base_Class
{};
std::unique_ptr<Unique_Ptr_Test_Derived_Class> make_Unique_Ptr_Test_Derived_Class()
{
return std::make_unique<Unique_Ptr_Test_Derived_Class>();
}
TEST_CASE("Call methods on base class through unique_ptr<derived>")
{
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
chai.add(chaiscript::var(std::make_unique<Unique_Ptr_Test_Derived_Class>()), "uptr");
chai.add(chaiscript::fun(make_Unique_Ptr_Test_Derived_Class), "make_Unique_Ptr_Test_Derived_Class");
chai.add(chaiscript::fun(&Unique_Ptr_Test_Base_Class::getI), "getI");
chai.add(chaiscript::base_class<Unique_Ptr_Test_Base_Class, Unique_Ptr_Test_Derived_Class>());
CHECK(chai.eval<int>("uptr.getI()") == 5);
CHECK(chai.eval<int>("var uptr2 = make_Unique_Ptr_Test_Derived_Class(); uptr2.getI()") == 5);
}
class A
{
public:
A() = default;
A(const A&) = default;
A(A &&) = default;
A &operator=(const A&) = default;
A &operator=(A&&) = default;
virtual ~A() = default;
};
class B : public A
{
public:
B() = default;
};
TEST_CASE("Test typed chaiscript functions to perform conversions")
{
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
//-------------------------------------------------------------------------
chai.add(chaiscript::user_type<A>(), "A");
chai.add(chaiscript::user_type<B>(), "B");
chai.add(chaiscript::base_class<A, B>());
chai.add(chaiscript::fun([](const B &)
{
}), "CppFunctWithBArg");
chai.add(chaiscript::fun([]() -> std::shared_ptr<A>
{
return (std::shared_ptr<A>(new B()));
}), "Create");
chai.eval(R"(
var inst = Create() // A*
// it prints "A"
inst.type_name().print()
// Ok it is casted using conversion
CppFunctWithBArg(inst)
// Define a function with B as argument
def ChaiFuncWithBArg(B inst)
{
print("ok")
}
// don't work
ChaiFuncWithBArg(inst)
)");
}
struct Reference_MyClass
{
Reference_MyClass(double& t_x) : x(t_x) {}
double& x;
};
TEST_CASE("Test reference member being registered")
{
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([](Reference_MyClass &r) -> decltype(auto) { return (r.x); }), "x");
chai.add(chaiscript::fun([](const Reference_MyClass &r) -> decltype(auto) { return (r.x); }), "x");
double d;
chai.add(chaiscript::var(Reference_MyClass(d)), "ref");
chai.eval("ref.x = 2.3");
CHECK(d == Approx(2.3));
}
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");
}

View File

@ -0,0 +1,23 @@
// all we care is that this executes, really
add_type_conversion(type("int"), type("bool"), fun(int i) { return i != 0; });
if (0) {
assert_true(false);
}
if (!0) {
assert_true(true);
} else {
assert_true(false);
}
while (0) {
assert_true(false);
}
for (; 0; ) {
assert_true(false);
}

View File

@ -0,0 +1,42 @@
assert_equal(__LINE__, 3)
def f() {
[__LINE__, __CLASS__, __FUNC__]
}
var res = f()
assert_equal(res[0], 6)
assert_equal(res[1], "NOT_IN_CLASS")
assert_equal(res[2], "f")
assert_equal(__CLASS__, "NOT_IN_CLASS")
assert_equal(__FUNC__, "NOT_IN_FUNCTION")
class C
{
def C() {}
def member() { [__LINE__, __CLASS__, __FUNC__]; }
}
var c = C();
var res2 = c.member();
assert_equal(res2[0], 21)
assert_equal(res2[1], "C")
assert_equal(res2[2], "member")
def C::member2() { [__LINE__, __CLASS__, __FUNC__]; }
var res3 = c.member2();
assert_equal(res3[0], 32)
assert_equal(res3[1], "C")
assert_equal(res3[2], "member2")
assert_true(__FILE__.find("execution_context.chai") != -1)

View File

@ -0,0 +1,26 @@
class Test
{
def Test()
{}
def a(Function f)
{
f("test");
// f();
}
def b()
{
var l = fun [this](x) { this.thing(); }
this.a(l)
}
def thing()
{
print("hello world");
}
}
var t = Test()
t.b()

View 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.

View File

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

View File

@ -3,123 +3,282 @@
#include "../static_libs/chaiscript_stdlib.hpp" #include "../static_libs/chaiscript_stdlib.hpp"
#ifdef CHAISCRIPT_MSVC
// ignore errors about negative unsigned integer literals
#pragma warning(push)
#pragma warning(disable : 4146)
#endif
#define TEST_LITERAL(v) test_literal(v, #v) #define TEST_LITERAL(v) test_literal(v, #v)
#define TEST_LITERAL_SIGNED(v) test_literal(v, #v, true)
template<typename T> template<typename T>
bool test_literal(T val, const std::string &str) bool test_literal(T val, const std::string &str, bool use_boxed_number = false)
{ {
std::cout << "Comparing : " << val; std::cout << '(' << str << ") Comparing : C++ '" << val;
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser()); chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
T val2 = chai.eval<T>(str);
std::cout << " " << val2 << '\n'; // Note, after applying the `-` it's possible that chaiscript has internally converted
// between two equivalently sized types (ie, unsigned long and unsigned long long on a 64bit system)
// so we're going to allow some leeway with the signed tests
T val2 = [&](){
if (!use_boxed_number) {
return chai.eval<T>(str);
} else {
return chai.eval<chaiscript::Boxed_Number>(str).get_as_checked<T>();
}
}();
std::cout << "' chai '" << val2 << "'\n";
return val == val2; return val == val2;
} }
int main() int main()
{ {
if( TEST_LITERAL(0xF) if(
&& TEST_LITERAL(0xFF) TEST_LITERAL(0xF)
&& TEST_LITERAL(0xFFF) && TEST_LITERAL(0xFF)
&& TEST_LITERAL(0xFFFF) && TEST_LITERAL(0xFFF)
&& TEST_LITERAL(0xFFFFF) && TEST_LITERAL(0xFFFF)
&& TEST_LITERAL(0xFFFFFF) && TEST_LITERAL(0xFFFFF)
&& TEST_LITERAL(0xFFFFFFF) && TEST_LITERAL(0xFFFFFF)
&& TEST_LITERAL(0xFFFFFFFF) && TEST_LITERAL(0xFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFFFF)
&& TEST_LITERAL(01)
&& TEST_LITERAL(017)
&& TEST_LITERAL(0177)
&& TEST_LITERAL(01777)
&& TEST_LITERAL(017777)
&& TEST_LITERAL(0177777)
&& TEST_LITERAL(01777777)
&& TEST_LITERAL(017777777)
&& TEST_LITERAL(0177777777)
&& TEST_LITERAL(01777777777)
&& TEST_LITERAL(017777777777)
&& TEST_LITERAL(0177777777777)
&& TEST_LITERAL(01777777777777)
&& TEST_LITERAL(017777777777777)
&& TEST_LITERAL(0177777777777777)
&& TEST_LITERAL(01777777777777777)
&& TEST_LITERAL(017777777777777777)
&& TEST_LITERAL(0177777777777777777)
&& TEST_LITERAL(01777777777777777777)
&& TEST_LITERAL(017777777777777777777)
&& TEST_LITERAL(0177777777777777777777)
&& TEST_LITERAL(01777777777777777777777)
&& TEST_LITERAL(1)
&& TEST_LITERAL(17)
&& TEST_LITERAL(177)
&& TEST_LITERAL(1777)
&& TEST_LITERAL(17777)
&& TEST_LITERAL(177777)
&& TEST_LITERAL(1777777)
&& TEST_LITERAL(17777777)
&& TEST_LITERAL(177777777)
&& TEST_LITERAL(1777777777)
&& TEST_LITERAL(17777777777)
&& TEST_LITERAL(177777777777)
&& TEST_LITERAL(1777777777777)
&& TEST_LITERAL(17777777777777)
&& TEST_LITERAL(177777777777777)
&& TEST_LITERAL(1777777777777777)
&& TEST_LITERAL(17777777777777777)
&& TEST_LITERAL(177777777777777777)
&& TEST_LITERAL(1777777777777777777)
&& test_literal(0xF, "0b1111") && TEST_LITERAL(01)
&& test_literal(0xFF, "0b11111111") && TEST_LITERAL(017)
&& test_literal(0xFFF, "0b111111111111") && TEST_LITERAL(0177)
&& test_literal(0xFFFF, "0b1111111111111111") && TEST_LITERAL(01777)
&& test_literal(0xFFFFF, "0b11111111111111111111") && TEST_LITERAL(017777)
&& test_literal(0xFFFFFF, "0b111111111111111111111111") && TEST_LITERAL(0177777)
&& test_literal(0xFFFFFFF, "0b1111111111111111111111111111") && TEST_LITERAL(01777777)
&& test_literal(0xFFFFFFFF, "0b11111111111111111111111111111111") && TEST_LITERAL(017777777)
&& test_literal(0xFFFFFFFFF, "0b111111111111111111111111111111111111") && TEST_LITERAL(0177777777)
&& test_literal(0xFFFFFFFFFF, "0b1111111111111111111111111111111111111111") && TEST_LITERAL(01777777777)
&& test_literal(0xFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111") && TEST_LITERAL(017777777777)
&& test_literal(0xFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111") && TEST_LITERAL(0177777777777)
&& test_literal(0xFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111") && TEST_LITERAL(01777777777777)
&& test_literal(0xFFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111") && TEST_LITERAL(017777777777777)
&& test_literal(0xFFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111") && TEST_LITERAL(0177777777777777)
&& test_literal(0xFFFFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111111111111") && TEST_LITERAL(01777777777777777)
&& TEST_LITERAL(017777777777777777)
&& TEST_LITERAL(0177777777777777777)
&& TEST_LITERAL(01777777777777777777)
&& TEST_LITERAL(017777777777777777777)
&& TEST_LITERAL(0177777777777777777777)
&& TEST_LITERAL(01777777777777777777777)
&& test_literal(0x7, "0b111") && TEST_LITERAL(1)
&& test_literal(0x7F, "0b1111111") && TEST_LITERAL(17)
&& test_literal(0x7FF, "0b11111111111") && TEST_LITERAL(177)
&& test_literal(0x7FFF, "0b111111111111111") && TEST_LITERAL(1777)
&& test_literal(0x7FFFF, "0b1111111111111111111") && TEST_LITERAL(17777)
&& test_literal(0x7FFFFF, "0b11111111111111111111111") && TEST_LITERAL(177777)
&& test_literal(0x7FFFFFF, "0b111111111111111111111111111") && TEST_LITERAL(1777777)
&& test_literal(0x7FFFFFFF, "0b1111111111111111111111111111111") && TEST_LITERAL(17777777)
&& test_literal(0x7FFFFFFFF, "0b11111111111111111111111111111111111") && TEST_LITERAL(177777777)
&& test_literal(0x7FFFFFFFFF, "0b111111111111111111111111111111111111111") && TEST_LITERAL(1777777777)
&& test_literal(0x7FFFFFFFFFF, "0b1111111111111111111111111111111111111111111") && TEST_LITERAL(17777777777)
&& test_literal(0x7FFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111") && TEST_LITERAL(177777777777)
&& test_literal(0x7FFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111") && TEST_LITERAL(1777777777777)
&& test_literal(0x7FFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111") && TEST_LITERAL(17777777777777)
&& test_literal(0x7FFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111111") && TEST_LITERAL(177777777777777)
&& test_literal(0x7FFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111111") && TEST_LITERAL(1777777777777777)
) && TEST_LITERAL(17777777777777777)
&& TEST_LITERAL(177777777777777777)
&& TEST_LITERAL(1777777777777777777)
&& test_literal(0xF, "0b1111")
&& test_literal(0xFF, "0b11111111")
&& test_literal(0xFFF, "0b111111111111")
&& test_literal(0xFFFF, "0b1111111111111111")
&& test_literal(0xFFFFF, "0b11111111111111111111")
&& test_literal(0xFFFFFF, "0b111111111111111111111111")
&& test_literal(0xFFFFFFF, "0b1111111111111111111111111111")
&& test_literal(0xFFFFFFFF, "0b11111111111111111111111111111111")
&& test_literal(0xFFFFFFFFF, "0b111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFF, "0b1111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111111111111")
&& test_literal(0x7, "0b111")
&& test_literal(0x7F, "0b1111111")
&& test_literal(0x7FF, "0b11111111111")
&& test_literal(0x7FFF, "0b111111111111111")
&& test_literal(0x7FFFF, "0b1111111111111111111")
&& test_literal(0x7FFFFF, "0b11111111111111111111111")
&& test_literal(0x7FFFFFF, "0b111111111111111111111111111")
&& test_literal(0x7FFFFFFF, "0b1111111111111111111111111111111")
&& test_literal(0x7FFFFFFFF, "0b11111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFF, "0b111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFF, "0b1111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111111")
&& TEST_LITERAL_SIGNED(-0xF)
&& TEST_LITERAL_SIGNED(-0xFF)
&& TEST_LITERAL_SIGNED(-0xFFF)
&& TEST_LITERAL_SIGNED(-0xFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-01)
&& TEST_LITERAL_SIGNED(-017)
&& TEST_LITERAL_SIGNED(-0177)
&& TEST_LITERAL_SIGNED(-01777)
&& TEST_LITERAL_SIGNED(-017777)
&& TEST_LITERAL_SIGNED(-0177777)
&& TEST_LITERAL_SIGNED(-01777777)
&& TEST_LITERAL_SIGNED(-017777777)
&& TEST_LITERAL_SIGNED(-0177777777)
&& TEST_LITERAL_SIGNED(-01777777777)
&& TEST_LITERAL_SIGNED(-017777777777)
&& TEST_LITERAL_SIGNED(-0177777777777)
&& TEST_LITERAL_SIGNED(-01777777777777)
&& TEST_LITERAL_SIGNED(-017777777777777)
&& TEST_LITERAL_SIGNED(-0177777777777777)
&& TEST_LITERAL_SIGNED(-01777777777777777)
&& TEST_LITERAL_SIGNED(-017777777777777777)
&& TEST_LITERAL_SIGNED(-0177777777777777777)
&& TEST_LITERAL_SIGNED(-01777777777777777777)
&& TEST_LITERAL_SIGNED(-017777777777777777777)
&& TEST_LITERAL_SIGNED(-0177777777777777777777)
&& TEST_LITERAL_SIGNED(-01777777777777777777777)
&& TEST_LITERAL_SIGNED(-1)
&& TEST_LITERAL_SIGNED(-17)
&& TEST_LITERAL_SIGNED(-177)
&& TEST_LITERAL_SIGNED(-1777)
&& TEST_LITERAL_SIGNED(-17777)
&& TEST_LITERAL_SIGNED(-177777)
&& TEST_LITERAL_SIGNED(-1777777)
&& TEST_LITERAL_SIGNED(-17777777)
&& TEST_LITERAL_SIGNED(-177777777)
&& TEST_LITERAL_SIGNED(-1777777777)
&& TEST_LITERAL_SIGNED(-17777777777)
&& TEST_LITERAL_SIGNED(-177777777777)
&& TEST_LITERAL_SIGNED(-1777777777777)
&& TEST_LITERAL_SIGNED(-17777777777777)
&& TEST_LITERAL_SIGNED(-177777777777777)
&& TEST_LITERAL_SIGNED(-1777777777777777)
&& TEST_LITERAL_SIGNED(-17777777777777777)
&& TEST_LITERAL_SIGNED(-177777777777777777)
&& TEST_LITERAL_SIGNED(-1777777777777777777)
// Test 8/16/24/32 bit boundaries for various types
&& TEST_LITERAL(255)
&& TEST_LITERAL(65535)
&& TEST_LITERAL(16777215)
#ifndef CHAISCRIPT_MSVC
// bug in cl.exe causes this to be incorrectly parsed as an unsigned
&& TEST_LITERAL(4294967295)
#endif
&& TEST_LITERAL_SIGNED(-255)
&& TEST_LITERAL_SIGNED(-65535)
&& TEST_LITERAL_SIGNED(-16777215)
#ifndef CHAISCRIPT_MSVC
// bug in cl.exe causes this to be incorrectly parsed as an unsigned
&& TEST_LITERAL_SIGNED(-4294967295)
#endif
&& TEST_LITERAL(255u)
&& TEST_LITERAL(65535u)
&& TEST_LITERAL(16777215u)
&& TEST_LITERAL(4294967295u)
&& TEST_LITERAL_SIGNED(-255u)
&& TEST_LITERAL_SIGNED(-65535u)
&& TEST_LITERAL_SIGNED(-16777215u)
&& TEST_LITERAL_SIGNED(-4294967295u)
&& TEST_LITERAL(255l)
&& TEST_LITERAL(65535l)
&& TEST_LITERAL(16777215l)
#ifndef CHAISCRIPT_MSVC
// bug in cl.exe causes this to be incorrectly parsed as an unsigned
&& TEST_LITERAL(4294967295l)
#endif
&& TEST_LITERAL_SIGNED(-255l)
&& TEST_LITERAL_SIGNED(-65535l)
&& TEST_LITERAL_SIGNED(-16777215l)
#ifndef CHAISCRIPT_MSVC
// bug in cl.exe causes this to be incorrectly parsed as an unsigned
&& TEST_LITERAL_SIGNED(-4294967295l)
#endif
&& TEST_LITERAL(255ul)
&& TEST_LITERAL(65535ul)
&& TEST_LITERAL(16777215ul)
&& TEST_LITERAL(4294967295ul)
&& TEST_LITERAL_SIGNED(-255ul)
&& TEST_LITERAL_SIGNED(-65535ul)
&& TEST_LITERAL_SIGNED(-16777215ul)
&& TEST_LITERAL_SIGNED(-4294967295ul)
&& TEST_LITERAL(255ull)
&& TEST_LITERAL(65535ull)
&& TEST_LITERAL(16777215ull)
&& TEST_LITERAL(4294967295ull)
&& TEST_LITERAL_SIGNED(-255ull)
&& TEST_LITERAL_SIGNED(-65535ull)
&& TEST_LITERAL_SIGNED(-16777215ull)
&& TEST_LITERAL_SIGNED(-4294967295ull)
&& TEST_LITERAL(255ll)
&& TEST_LITERAL(65535ll)
&& TEST_LITERAL(16777215ll)
&& TEST_LITERAL(4294967295ll)
&& TEST_LITERAL_SIGNED(-255ll)
&& TEST_LITERAL_SIGNED(-65535ll)
&& TEST_LITERAL_SIGNED(-16777215ll)
&& TEST_LITERAL_SIGNED(-4294967295ll)
)
{ {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} else { } else {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif

View File

@ -1 +1,2 @@
assert_equal(from_json("100"), 100) assert_equal(from_json("100"), 100)
assert_equal(from_json("-100"), -100)

View File

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

View File

@ -1,2 +1,2 @@
assert_equal(from_json("[1,2,3]"), [1,2,3]) assert_equal(from_json("[1,-2,3]"), [1,-2,3])

View File

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

View File

@ -0,0 +1,12 @@
def numFunc(x)
{
return x + 10;
}
// Note that unary prefix `-` has lower precedence than `.`
// this is why these values are correct, even if counterintuitive
assert_true(-5.numFunc() == -15);
assert_true((-5).numFunc() == 5);

View 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() {}