Merge branch 'develop' into master

This commit is contained in:
Rob Loach 2021-05-24 16:05:30 -04:00 committed by GitHub
commit 439c1a96d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
237 changed files with 26144 additions and 23997 deletions

View File

@ -1,98 +1,33 @@
AccessModifierOffset: -2
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: false
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyNamespace: true
SplitEmptyRecord: true
BreakAfterJavaFieldAnnotations: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakConstructorInitializersBeforeComma: false
BreakStringLiterals: true
ColumnLimit: 0
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: false
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: true
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeCategories:
- Priority: 2
Regex: ^"(llvm|llvm-c|clang|clang-c)/
- Priority: 3
Regex: ^(<|"(gtest|gmock|isl|json)/)
- Priority: 1
Regex: .*
IncludeIsMainRegex: (Test)?$
IndentCaseLabels: false
IndentWidth: 2
IndentWrappedFunctionNames: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
Language: Cpp
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: Inner
ObjCBlockIndentWidth: 7
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
# clang-format: 11
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveBitFields: false
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AlwaysBreakTemplateDeclarations: true
BasedOnStyle: WebKit
BinPackArguments: true
BinPackParameters: true
BreakBeforeBraces: Attach
ColumnLimit: 0
Cpp11BracedListStyle: true
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: false
NamespaceIndentation: All
PenaltyBreakBeforeFirstCallParameter: 200
PenaltyBreakComment: 5
PenaltyBreakFirstLessLess: 50
PenaltyExcessCharacter: 4
PointerAlignment: Right
SortIncludes: true
SpaceAfterTemplateKeyword: false
SpaceBeforeCpp11BracedList: false
SpaceInEmptyBlock: false
Standard: Latest
TabWidth: 2
UseTab: Never

View File

@ -5,10 +5,12 @@ addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-5.0
- sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- g++-4.9
- g++-5
- g++-6
- g++-7
- g++-8
coverity_scan:
project:
name: "ChaiScript/ChaiScript"
@ -22,7 +24,7 @@ matrix:
include:
- os: linux
sudo: false
env: GCC_VER="4.9"
env: GCC_VER="7"
compiler: gcc
# - os: linux
#sudo: false
@ -30,19 +32,20 @@ matrix:
#compiler: gcc
- os: linux
sudo: false
env: GCC_VER="5" CPPCHECK=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
env: GCC_VER="7" CPPCHECK=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
compiler: gcc
- os: linux
sudo: false
env: GCC_VER="6" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
env: GCC_VER="8" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
compiler: gcc
- os: osx
compiler: clang
osx_image: xcode8
- os: osx
compiler: clang
osx_image: xcode8
env: CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
#- os: osx
# compiler: clang
# osx_image: xcode10
# env: CLANG_VER="5.0"
#- os: osx
# compiler: clang
# osx_image: xcode10
# env: CLANG_VER="5.0" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
env:
global:
@ -52,6 +55,7 @@ env:
before_install:
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
#- if [ "${CLANG_VER}" != "" ]; then export CXX="clang++-$CLANG_VER"; fi
- pip install --user cpp-coveralls
script:

View File

@ -1,8 +1,11 @@
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0054 NEW)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
cmake_policy(SET CMP0054 NEW)
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# required since cmake 3.4 at least for libc++
set(CMAKE_ENABLE_EXPORTS ON)
project(chaiscript)
@ -15,7 +18,6 @@ option(BUILD_SAMPLES "Build Samples Folder" FALSE)
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
option(BUILD_IN_CPP17_MODE "Build with C++17 flags" FALSE)
mark_as_advanced(USE_STD_MAKE_SHARED)
@ -49,8 +51,8 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
add_definitions(-fsanitize=memory -fsanitize-memory-track-origins -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins ")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
@ -60,27 +62,26 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if (ENABLE_LTO)
add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
if(ENABLE_LTO)
check_ipo_supported()
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
option(GPROF_OUTPUT "Generate profile data" FALSE)
if (GPROF_OUTPUT)
if(GPROF_OUTPUT)
add_definitions(-pg)
set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE)
if(PROFILE_GENERATE)
add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif()
option(PROFILE_USE "Use profile data" FALSE)
if (PROFILE_USE)
if(PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
@ -98,8 +99,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 6)
set(CPACK_PACKAGE_VERSION_MINOR 1)
set(CPACK_PACKAGE_VERSION_MAJOR 7)
set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
@ -125,7 +126,7 @@ if(NOT MINGW)
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
endif()
if (UNIX AND NOT APPLE)
if(UNIX AND NOT APPLE)
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
endif()
@ -143,36 +144,10 @@ else()
set(READLINE_FLAG)
endif()
if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_LESS 4.9)
set(CPP14_FLAG "-std=c++1y")
else()
if (BUILD_IN_CPP17_MODE)
set(CPP14_FLAG "-std=c++1z")
else()
set(CPP14_FLAG "-std=c++14")
endif()
endif()
else()
if (BUILD_IN_CPP17_MODE)
set(CPP14_FLAG "-std=c++1z")
else()
set(CPP14_FLAG "-std=c++14")
endif()
endif()
if(MSVC)
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
if (BUILD_IN_CPP17_MODE)
add_definitions(/std:c++17)
endif()
if (MSVC_VERSION STREQUAL "1800")
if(MSVC_VERSION STREQUAL "1800")
# VS2013 doesn't have magic statics
add_definitions(/w44640)
else()
@ -180,7 +155,7 @@ if(MSVC)
add_definitions(/w34062)
endif()
add_definitions(/bigobj /permissive-)
add_definitions(/bigobj /permissive- /utf-8)
# Note on MSVC compiler flags.
# The code base selective disables warnings as necessary when the compiler is complaining too much
# about something that is perfectly valid, or there is simply no technical way around it
@ -190,10 +165,10 @@ if(MSVC)
# how to workaround or fix the error. So I'm disabling it globally.
add_definitions(/wd4503)
else()
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP14_FLAG})
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic -Werror=return-type)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template)
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template -Wno-undef -Wno-double-promotion)
else()
add_definitions(-Wnoexcept)
endif()
@ -204,16 +179,12 @@ else()
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" TRUE)
option(USE_LIBCXX "Use clang's libcxx" FALSE)
if(USE_LIBCXX)
add_definitions(-stdlib=libc++)
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG} -stdlib=libc++")
else()
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}")
set(LINKER_FLAGS "${LINKER_FLAGS} -stdlib=libc++")
endif()
elseif(CMAKE_COMPILER_IS_GNUCC)
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}")
endif()
# limitations in MinGW require us to make an optimized build
@ -279,8 +250,8 @@ add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
if(BUILD_SAMPLES)
add_executable(example samples/example.cpp)
target_link_libraries(example ${LIBS})
add_executable(sanity_checks src/sanity_checks.cpp)
target_link_libraries(sanity_checks ${LIBS})
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(memory_leak_test samples/memory_leak_test.cpp)
@ -312,7 +283,7 @@ file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tes
list(SORT PERFORMANCE_TESTS)
if (RUN_FUZZY_TESTS)
if(RUN_FUZZY_TESTS)
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
@ -341,37 +312,6 @@ endif()
if(BUILD_TESTING)
# Add catch tests macro
macro(ADD_CATCH_TESTS executable)
if (MSVC)
file(TO_NATIVE_PATH "${QT_LIBRARY_DIR}" QT_LIB_PATH)
set(NEWPATH "${QT_LIB_PATH};$ENV{PATH}")
else()
set(NEWPATH $ENV{PATH})
endif()
get_target_property(target_files ${executable} SOURCES)
foreach(source ${target_files})
if(NOT "${source}" MATCHES "/moc_.*cxx")
string(REGEX MATCH .*cpp source "${source}")
if(source)
file(READ "${source}" contents)
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
foreach(hit ${found_tests})
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
add_test(compiled.${test_name} "${executable}" ${test_name})
set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
endforeach()
endif()
endif()
endforeach()
endmacro()
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }")
@ -403,7 +343,7 @@ if(BUILD_TESTING)
list(APPEND TESTS unit.${filename})
endforeach()
if (RUN_PERFORMANCE_TESTS)
if(RUN_PERFORMANCE_TESTS)
foreach(filename ${PERFORMANCE_TESTS})
message(STATUS "Adding performance test ${filename}")
@ -460,10 +400,8 @@ if(BUILD_TESTING)
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
endif()
add_executable(multifile_test
unittests/multifile_test_main.cpp
unittests/multifile_test_chai.cpp
@ -472,12 +410,11 @@ if(BUILD_TESTING)
target_link_libraries(multifile_test ${LIBS})
add_test(NAME MultiFile_Test COMMAND multifile_test)
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
endif()
endif()
if(BUILD_LIBFUZZ_TESTER)
add_executable(fuzzer src/libfuzzer_client.cpp src/sha3.cpp)
target_compile_options(fuzzer PRIVATE "-fsanitize=fuzzer,address")
@ -485,7 +422,7 @@ if(BUILD_LIBFUZZ_TESTER)
endif()
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp"
@ -506,6 +443,6 @@ install(DIRECTORY samples DESTINATION share/chaiscript
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
DESTINATION lib/pkgconfig)
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")

View File

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

View File

@ -1,10 +1,9 @@
version: 6.1.x.{build}
image:
- Visual Studio 2017
image:
- Visual Studio 2019
environment:
matrix:
- VS_VERSION: "Visual Studio 14"
- VS_VERSION: "Visual Studio 15"
- VS_VERSION: "Visual Studio 16"
build_script:
- cmd: >-
mkdir build

View File

@ -11,20 +11,18 @@ ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme.
# Initializing ChaiScript
```
chaiscript::ChaiScript chai; // loads stdlib from loadable module on file system
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
chaiscript::ChaiScript chai; // initializes ChaiScript, adding the standard ChaiScript types (map, string, ...)
```
Note that ChaiScript cannot be used as a global / static object unless it is being compiled with `CHAISCRIPT_NO_THREADS`.
# Adding Things To The Engine
## Adding a Function / Method / Member
### General
```
```cpp
chai.add(chaiscript::fun(&function_name), "function_name");
chai.add(chaiscript::fun(&Class::method_name), "method_name");
chai.add(chaiscript::fun(&Class::member_name), "member_name");
@ -32,7 +30,7 @@ chai.add(chaiscript::fun(&Class::member_name), "member_name");
### Bound Member Functions
```
```cpp
chai.add(chaiscript::fun(&Class::method_name, Class_instance_ptr), "method_name");
chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name");
```
@ -41,18 +39,18 @@ chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name"
#### Preferred
```
```cpp
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
```
#### Alternative
```
```cpp
chai.add(chaiscript::fun(std::static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
```
This overload technique is also used when exposing base member using derived type
```
```cpp
struct Base
{
int data;
@ -66,9 +64,9 @@ chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
### Lambda
```
```cpp
chai.add(
chaiscript::fun<std::string (bool)>(
chaiscript::fun<std::function<std::string (bool)>>(
[](bool type) {
if (type) { return "x"; }
else { return "y"; }
@ -77,7 +75,7 @@ chai.add(
### Constructors
```
```cpp
chai.add(chaiscript::constructor<MyType ()>(), "MyType");
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
```
@ -86,7 +84,7 @@ chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
```
```cpp
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
```
@ -109,27 +107,27 @@ add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s);
Invoking a C++ type conversion possible with `static_cast`
```
```cpp
chai.add(chaiscript::type_conversion<T, bool>());
```
Calling a user defined type conversion that takes a lambda
```
```cpp
chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ }));
```
### Class Hierarchies
If you want objects to be convertable between base and derived classes, you must tell ChaiScritp about the relationship.
If you want objects to be convertable between base and derived classes, you must tell ChaiScript about the relationship.
```
```cpp
chai.add(chaiscript::base_class<Base, Derived>());
```
If you have multiple classes in your inheritance graph, you will probably want to tell ChaiScript about all relationships.
```
```cpp
chai.add(chaiscript::base_class<Base, Derived>());
chai.add(chaiscript::base_class<Derived, MoreDerived>());
chai.add(chaiscript::base_class<Base, MoreDerived>());
@ -170,7 +168,8 @@ chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overw
Namespaces will not be populated until `import` is called.
This saves memory and computing costs if a namespace is not imported into every ChaiScript instance.
```
```cpp
chai.register_namespace([](chaiscript::Namespace& math) {
math["pi"] = chaiscript::const_var(3.14159);
math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); },
@ -186,7 +185,7 @@ print(math.pi) // prints 3.14159
# Using STL
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
```
```cpp
typedef std::vector<std::pair<int, std::string>> data_list;
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
@ -204,7 +203,7 @@ chai.eval(R"_(
## General
```
```cpp
chai.eval("print(\"Hello World\")");
chai.eval(R"(print("Hello World"))");
```
@ -215,13 +214,13 @@ Returns values are of the type `Boxed_Value` which is meant to be opaque to the
### Prefered
```
```cpp
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
```
### Alternative
```
```cpp
auto v = chai.eval("5.3 + 2.1");
chai.boxed_cast<double>(v); // extracts double value from boxed_value and applies known conversions
chaiscript::boxed_cast<double>(v); // free function version, does not know about conversions
@ -229,7 +228,7 @@ chaiscript::boxed_cast<double>(v); // free function version, does not know about
### Converting Between Algebraic Types
```
```cpp
chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with any number type
// which is equivalent to, but much more automatic than:
static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
@ -259,7 +258,7 @@ int main()
## Sharing Values
```
```cpp
double &d = chai.eval("var i = 5.2; i"); // d is now a reference to i in the script
std::shared_ptr<double> d = chai.eval("var i = 5.2; i"); // same result but reference counted
@ -269,7 +268,7 @@ chai.eval("print(i)"); // prints 3
## Catching Eval Errors
```
```cpp
try {
chai.eval("2.3 + \"String\"");
} catch (const chaiscript::exception::eval_error &e) {
@ -279,7 +278,7 @@ try {
## Catching Errors Thrown From Script
```
```cpp
try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double e) {
@ -294,19 +293,19 @@ try {
## Sharing Functions
```
```cpp
auto p = chai.eval<std::function<std::string (double)>>("to_string");
p(5); // calls chaiscript's 'to_string' function, returning std::string("5")
```
Note: backtick treats operators as normal functions
```
```cpp
auto p = chai.eval<std::function<int (int, int)>>(`+`);
p(5, 6); // calls chaiscript's '+' function, returning 11
```
```
```cpp
auto p = chai.eval<std::function<std::string (int, double)>>("fun(x,y) { to_string(x) + to_string(y); }");
p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
```
@ -346,7 +345,7 @@ while (some_condition()) { /* do something */ }
```
// ranged for
for (x : [1,2,3]) { print(i); }
for (i : [1, 2, 3]) { print(i); }
```
Each of the loop styles can be broken using the `break` statement. For example:
@ -391,11 +390,23 @@ switch (myvalue) {
## Built in Types
There are a number of build-in types that are part of ChaiScript.
### Vectors and Maps
```
var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
var m = ["a":1, "b":2]; // map of string:value pairs
// Add a value to the vector by value.
v.push_back(123);
// Add an object to the vector by reference.
v.push_back_ref(m);
```
### Numbers
Floating point values default to `double` type and integers default to `int` type. All C++ suffixes
such as `f`, `ll`, `u` as well as scientific notation are supported
@ -566,28 +577,11 @@ If both a 2 parameter and a 3 parameter signature match, the 3 parameter functio
* `__LINE__` Current file line number
* `__FILE__` Full path of current file
* `__CLASS__` Name of current class
* `__FUNC__` Mame of current function
* `__FUNC__` Name of current function
# Built In Functions
## Disabling Built-Ins
When constructing a ChaiScript object, a vector of parameters can be passed in to disable or enable various built-in methods.
Current options:
```
enum class Options
{
Load_Modules,
No_Load_Modules,
External_Scripts,
No_External_Scripts
};
```
## Evaluation
```
@ -603,3 +597,6 @@ Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constr
* `from_json` converts a JSON string into its strongly typed (map, vector, int, double, string) representations
* `to_json` converts a ChaiScript object (either a `Object` or one of map, vector, int, double, string) tree into its JSON string representation
## Extras
ChaiScript itself does not provide a link to the math functions defined in `<cmath>`. You can either add them yourself, or use the [ChaiScript_Extras](https://github.com/ChaiScript/ChaiScript_Extras) helper library. (Which also provides some additional string functions.)

View File

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

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BASIC_HPP_
@ -9,13 +9,13 @@
#include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/function_call.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
#include "language/chaiscript_eval.hpp"
// This file includes all of the basic requirements for ChaiScript,
// to use, you might do something like:
@ -34,6 +34,4 @@ ChaiScript_Basic chai(
// If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp
#endif /* CHAISCRIPT_BASIC_HPP_ */

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_
@ -20,9 +20,10 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
#endif
#include <string_view>
#include <vector>
#if defined( _LIBCPP_VERSION )
#if defined(_LIBCPP_VERSION)
#define CHAISCRIPT_LIBCPP
#endif
@ -48,16 +49,14 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#endif
#endif
#if defined(__llvm__)
#define CHAISCRIPT_CLANG
#endif
#ifdef CHAISCRIPT_HAS_DECLSPEC
#ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
@ -70,176 +69,176 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_DEBUG false
#endif
#include <cmath>
#include <memory>
#include <string>
#include <cmath>
namespace chaiscript {
static const int version_major = 6;
static const int version_minor = 1;
static const int version_patch = 0;
constexpr static const int version_major = 7;
constexpr static const int version_minor = 0;
constexpr static const int version_patch = 0;
static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
static const bool debug_build = CHAISCRIPT_DEBUG;
constexpr static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
constexpr static const bool debug_build = CHAISCRIPT_DEBUG;
template<typename B, typename D, typename ...Arg>
inline std::shared_ptr<B> make_shared(Arg && ... arg)
{
template<typename B, typename D, typename... Arg>
inline std::shared_ptr<B> make_shared(Arg &&...arg) {
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_shared<D>(std::forward<Arg>(arg)...);
#else
return std::shared_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...)));
return std::shared_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
#endif
}
template<typename B, typename D, typename ...Arg>
inline std::unique_ptr<B> make_unique(Arg && ... arg)
{
template<typename B, typename D, typename... Arg>
inline std::unique_ptr<B> make_unique(Arg &&...arg) {
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_unique<D>(std::forward<Arg>(arg)...);
#else
return std::unique_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...)));
return std::unique_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
#endif
}
struct Build_Info {
static int version_major()
{
return chaiscript::version_major;
}
[[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; }
static int version_minor()
{
return chaiscript::version_minor;
}
[[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; }
static int version_patch()
{
return chaiscript::version_patch;
}
[[nodiscard]] constexpr static int version_patch() noexcept { return chaiscript::version_patch; }
static std::string version()
{
[[nodiscard]] static std::string version() {
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
}
static std::string compiler_id()
{
return compiler_name() + '-' + compiler_version();
}
[[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); }
static std::string build_id()
{
return compiler_id() + (debug_build()?"-Debug":"-Release");
}
[[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build() ? "-Debug" : "-Release"); }
static std::string compiler_version()
{
return chaiscript::compiler_version;
}
[[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; }
static std::string compiler_name()
{
return chaiscript::compiler_name;
}
[[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; }
static bool debug_build()
{
return chaiscript::debug_build;
}
[[nodiscard]] constexpr static bool debug_build() noexcept { return chaiscript::debug_build; }
};
template<typename T>
auto parse_num(const char *t_str) -> typename std::enable_if<std::is_integral<T>::value, T>::type
{
T t = 0;
for (char c = *t_str; (c = *t_str) != 0; ++t_str) {
if (c < '0' || c > '9') {
return t;
}
t *= 10;
t += c - '0';
[[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type {
T t = 0;
for (const auto c : t_str) {
if (c < '0' || c > '9') {
return t;
}
return t;
}
template<typename T>
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
{
T t = 0;
T base{};
T decimal_place = 0;
int exponent = 0;
for (char c;; ++t_str) {
c = *t_str;
switch (c)
{
case '.':
decimal_place = 10;
break;
case 'e':
case 'E':
exponent = 1;
decimal_place = 0;
base = t;
t = 0;
break;
case '-':
exponent = -1;
break;
case '+':
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (decimal_place < 10) {
t *= 10;
t += static_cast<T>(c - '0');
}
else {
t += static_cast<T>(c - '0') / decimal_place;
decimal_place *= 10;
}
break;
default:
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
}
}
t *= 10;
t += c - '0';
}
return t;
}
template<typename T>
T parse_num(const std::string &t_str)
{
return parse_num<T>(t_str.c_str());
}
[[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type {
T t = 0;
T base{};
T decimal_place = 0;
int exponent = 0;
enum class Options
{
for (const auto c : t_str) {
switch (c) {
case '.':
decimal_place = 10;
break;
case 'e':
case 'E':
exponent = 1;
decimal_place = 0;
base = t;
t = 0;
break;
case '-':
exponent = -1;
break;
case '+':
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (decimal_place < 10) {
t *= 10;
t += static_cast<T>(c - '0');
} else {
t += static_cast<T>(c - '0') / decimal_place;
decimal_place *= 10;
}
break;
default:
break;
}
}
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
}
struct str_equal {
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs == t_rhs; }
template<typename LHS, typename RHS>
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
}
struct is_transparent {
};
};
struct str_less {
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; }
template<typename LHS, typename RHS>
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
}
struct is_transparent {
};
};
enum class Options {
No_Load_Modules,
Load_Modules,
No_External_Scripts,
External_Scripts
};
static inline std::vector<Options> default_options()
{
template<typename From, typename To>
struct is_nothrow_forward_constructible : std::bool_constant<noexcept(To{std::declval<From>()})> {
};
template<class From, class To>
static inline constexpr bool is_nothrow_forward_constructible_v = is_nothrow_forward_constructible<From, To>::value;
template<typename Container, typename... T>
[[nodiscard]] constexpr auto make_container(T &&...t) {
Container c;
c.reserve(sizeof...(t));
(c.push_back(std::forward<T>(t)), ...);
return c;
}
template<typename... T>
[[nodiscard]] auto make_vector(T &&...t) -> std::vector<std::common_type_t<std::decay_t<T>...>> {
using container_type = std::vector<std::common_type_t<std::decay_t<T>...>>;
return make_container<container_type>(std::forward<T>(t)...);
}
[[nodiscard]] inline std::vector<Options> default_options() {
#ifdef CHAISCRIPT_NO_DYNLOAD
return {Options::No_Load_Modules, Options::External_Scripts};
#else
return {Options::Load_Modules, Options::External_Scripts};
#endif
}
}
} // namespace chaiscript
#endif

View File

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

View File

@ -1,25 +1,24 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_THREADING_HPP_
#define CHAISCRIPT_THREADING_HPP_
#include <unordered_map>
#ifndef CHAISCRIPT_NO_THREADS
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <thread>
#else
#ifndef CHAISCRIPT_NO_THREADS_WARNING
#pragma message ("ChaiScript is compiling without thread safety.")
#pragma message("ChaiScript is compiling without thread safety.")
#endif
#endif
@ -33,141 +32,102 @@
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
/// one thread simultaneously.
namespace chaiscript
{
namespace detail
{
/// If threading is enabled, then this namespace contains std thread classes.
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
namespace threading
{
/// If threading is enabled, then this namespace contains std thread classes.
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
namespace chaiscript::detail::threading {
#ifndef CHAISCRIPT_NO_THREADS
template<typename T>
using unique_lock = std::unique_lock<T>;
template<typename T>
using unique_lock = std::unique_lock<T>;
template<typename T>
using shared_lock = std::unique_lock<T>;
template<typename T>
using shared_lock = std::shared_lock<T>;
template<typename T>
using lock_guard = std::lock_guard<T>;
template<typename T>
using lock_guard = std::lock_guard<T>;
using std::shared_mutex;
using shared_mutex = std::mutex;
using std::mutex;
using std::mutex;
using std::recursive_mutex;
using std::recursive_mutex;
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
template<typename T>
class Thread_Storage {
public:
Thread_Storage() = default;
Thread_Storage(const Thread_Storage &) = delete;
Thread_Storage(Thread_Storage &&) = delete;
Thread_Storage &operator=(const Thread_Storage &) = delete;
Thread_Storage &operator=(Thread_Storage &&) = delete;
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
template<typename T>
class Thread_Storage
{
public:
Thread_Storage() = default;
Thread_Storage(const Thread_Storage &) = delete;
Thread_Storage(Thread_Storage &&) = delete;
Thread_Storage &operator=(const Thread_Storage &) = delete;
Thread_Storage &operator=(Thread_Storage &&) = delete;
~Thread_Storage() { t().erase(this); }
~Thread_Storage()
{
t().erase(this);
}
inline const T *operator->() const noexcept { return &(t()[this]); }
inline const T *operator->() const
{
return &(t()[this]);
}
inline const T &operator*() const noexcept { return t()[this]; }
inline const T &operator*() const
{
return t()[this];
}
inline T *operator->() noexcept { return &(t()[this]); }
inline T *operator->()
{
return &(t()[this]);
}
inline T &operator*() noexcept { return t()[this]; }
inline T &operator*()
{
return t()[this];
}
void *m_key;
void *m_key;
private:
static std::unordered_map<const void*, T> &t()
{
thread_local std::unordered_map<const void *, T> my_t;
return my_t;
}
};
private:
/// todo: is it valid to make this noexcept? The allocation could fail, but if it
/// does there is no possible way to recover
static std::unordered_map<const void *, T> &t() noexcept {
static thread_local std::unordered_map<const void *, T> my_t;
return my_t;
}
};
#else // threading disabled
template<typename T>
class unique_lock
{
public:
explicit unique_lock(T &) {}
void lock() {}
void unlock() {}
};
template<typename T>
class unique_lock {
public:
constexpr explicit unique_lock(T &) noexcept {}
constexpr void lock() noexcept {}
constexpr void unlock() noexcept {}
};
template<typename T>
class shared_lock
{
public:
explicit shared_lock(T &) {}
void lock() {}
void unlock() {}
};
template<typename T>
class shared_lock {
public:
constexpr explicit shared_lock(T &) noexcept {}
constexpr void lock() noexcept {}
constexpr void unlock() noexcept {}
};
template<typename T>
class lock_guard
{
public:
explicit lock_guard(T &) {}
};
template<typename T>
class lock_guard {
public:
constexpr explicit lock_guard(T &) noexcept {}
};
class shared_mutex { };
class shared_mutex {
};
class recursive_mutex {};
class recursive_mutex {
};
template<typename T>
class Thread_Storage {
public:
constexpr explicit Thread_Storage() noexcept {}
template<typename T>
class Thread_Storage
{
public:
explicit Thread_Storage()
{
}
constexpr inline T *operator->() const noexcept { return &obj; }
inline T *operator->() const
{
return &obj;
}
constexpr inline T &operator*() const noexcept { return obj; }
inline T &operator*() const
{
return obj;
}
private:
mutable T obj;
};
private:
mutable T obj;
};
#endif
}
}
}
} // namespace chaiscript::detail::threading
#endif

View File

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

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
@ -15,59 +14,51 @@
#include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "../utility/static_string.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Info;
} // namespace chaiscript
class Type_Info;
} // namespace chaiscript
namespace chaiscript
{
namespace exception
{
namespace chaiscript {
namespace exception {
/// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type
///
/// It is used internally during function dispatch and may be used by the end user.
///
/// \sa chaiscript::boxed_cast
class bad_boxed_cast : public std::bad_cast
{
public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
std::string t_what) noexcept
: from(t_from), to(&t_to), m_what(std::move(t_what))
{
}
class bad_boxed_cast : public std::bad_cast {
public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, utility::Static_String t_what) noexcept
: from(t_from)
, to(&t_to)
, m_what(std::move(t_what)) {
}
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
{
}
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept
: from(t_from)
, to(&t_to)
, m_what("Cannot perform boxed_cast") {
}
explicit bad_boxed_cast(std::string t_what) noexcept
: m_what(std::move(t_what))
{
}
explicit bad_boxed_cast(utility::Static_String t_what) noexcept
: m_what(std::move(t_what)) {
}
bad_boxed_cast(const bad_boxed_cast &) = default;
~bad_boxed_cast() noexcept override = default;
bad_boxed_cast(const bad_boxed_cast &) noexcept = default;
~bad_boxed_cast() noexcept override = default;
/// \brief Description of what error occurred
const char * what() const noexcept override
{
return m_what.c_str();
}
/// \brief Description of what error occurred
const char *what() const noexcept override { return m_what.c_str(); }
Type_Info from; ///< Type_Info contained in the Boxed_Value
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type
Type_Info from; ///< Type_Info contained in the Boxed_Value
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type
private:
std::string m_what;
private:
utility::Static_String m_what;
};
}
}
} // namespace exception
} // namespace chaiscript
#endif

View File

@ -1,85 +1,60 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_
#include <functional>
namespace chaiscript
{
namespace detail
{
namespace chaiscript {
namespace detail {
template<typename T>
constexpr T *get_pointer(T *t) noexcept {
return t;
}
template<typename T>
T* get_pointer(T *t)
{
return t;
}
T *get_pointer(const std::reference_wrapper<T> &t) noexcept {
return &t.get();
}
template<typename T>
T* get_pointer(const std::reference_wrapper<T> &t)
{
return &t.get();
}
template<typename O, typename Ret, typename P1, typename... Param>
constexpr auto bind_first(Ret (*f)(P1, Param...), O &&o) {
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
}
template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(Ret (*f)(P1, Param...), O&& o)
{
return [f, o](Param...param) -> Ret {
return f(std::forward<O>(o), std::forward<Param>(param)...);
};
}
template<typename O, typename Ret, typename Class, typename... Param>
constexpr auto bind_first(Ret (Class::*f)(Param...), O &&o) {
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); };
}
template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(Ret (Class::*f)(Param...), O&& o)
{
return [f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
}
template<typename O, typename Ret, typename Class, typename... Param>
constexpr auto bind_first(Ret (Class::*f)(Param...) const, O &&o) {
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); };
}
template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(Ret (Class::*f)(Param...) const, O&& o)
{
return [f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
template<typename O, typename Ret, typename P1, typename... Param>
auto bind_first(const std::function<Ret(P1, Param...)> &f, O &&o) {
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
}
}
template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
{
return [f, o](Param...param) -> Ret {
return f(o, std::forward<Param>(param)...);
};
}
template<typename F, typename O, typename Ret, typename Class, typename P1, typename ... Param>
auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const)
{
return [fo, o, f](Param ...param) -> Ret {
return (fo.*f)(o, std::forward<Param>(param)...);
};
}
template<typename F, typename O, typename Ret, typename Class, typename P1, typename... Param>
constexpr auto bind_first(const F &fo, O &&o, Ret (Class::*f)(P1, Param...) const) {
return [fo, o = std::forward<O>(o), f](Param... param) -> Ret { return (fo.*f)(o, std::forward<Param>(param)...); };
}
template<typename F, typename O>
auto bind_first(const F &f, O&& o)
{
return bind_first(f, std::forward<O>(o), &F::operator());
}
}
}
constexpr auto bind_first(const F &f, O &&o) {
return bind_first(f, std::forward<O>(o), &F::operator());
}
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -1,398 +1,333 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_
#include "../utility/utility.hpp"
#include "register_function.hpp"
namespace chaiscript
{
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
namespace bootstrap
{
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
void array(const std::string &type, Module& m)
{
typedef typename std::remove_extent<T>::type ReturnType;
m.add(user_type<T>(), type);
m.add(fun(
[](T& t, size_t index)->ReturnType &{
constexpr auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
} else {
return t[index];
}
}
), "[]"
);
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
namespace chaiscript::bootstrap {
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type>
void array(const std::string &type, Module &m) {
using ReturnType = typename std::remove_extent<T>::type;
m.add(fun(
[](const T &t, size_t index)->const ReturnType &{
constexpr auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
} else {
return t[index];
}
}
), "[]"
);
m.add(user_type<T>(), type);
m.add(fun([](T &t, size_t index) -> ReturnType & {
constexpr const auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
+ std::to_string(extent));
} else {
return t[index];
}
}),
"[]");
m.add(fun(
[](const T &) {
constexpr auto extent = std::extent<T>::value;
return extent;
}), "size");
}
m.add(fun([](const T &t, size_t index) -> const ReturnType & {
constexpr const auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
+ std::to_string(extent));
} else {
return t[index];
}
}),
"[]");
/// \brief Adds a copy constructor for the given type to the given Model
/// \param[in] type The name of the type. The copy constructor will be named "type".
/// \param[in,out] m The Module to add the copy constructor to
/// \tparam T The type to add a copy constructor for
/// \returns The passed in Module
template<typename T>
void copy_constructor(const std::string &type, Module& m)
{
m.add(constructor<T (const T &)>(), type);
}
m.add(fun([](const T &) { return std::extent<T>::value; }), "size");
}
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
/// \tparam T Type to create comparison operators for
/// \param[in,out] m module to add comparison operators to
/// \returns the passed in Module.
template<typename T>
void opers_comparison(Module& m)
{
operators::equal<T>(m);
operators::greater_than<T>(m);
operators::greater_than_equal<T>(m);
operators::less_than<T>(m);
operators::less_than_equal<T>(m);
operators::not_equal<T>(m);
}
/// \brief Adds a copy constructor for the given type to the given Model
/// \param[in] type The name of the type. The copy constructor will be named "type".
/// \param[in,out] m The Module to add the copy constructor to
/// \tparam T The type to add a copy constructor for
/// \returns The passed in Module
template<typename T>
void copy_constructor(const std::string &type, Module &m) {
m.add(constructor<T(const T &)>(), type);
}
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
/// \tparam T Type to create comparison operators for
/// \param[in,out] m module to add comparison operators to
/// \returns the passed in Module.
template<typename T>
void opers_comparison(Module &m) {
operators::equal<T>(m);
operators::greater_than<T>(m);
operators::greater_than_equal<T>(m);
operators::less_than<T>(m);
operators::less_than_equal<T>(m);
operators::not_equal<T>(m);
}
/// \brief Adds default and copy constructors for the given type
/// \param[in] type The name of the type to add the constructors for.
/// \param[in,out] m The Module to add the basic constructors to
/// \tparam T Type to generate basic constructors for
/// \returns The passed in Module
/// \sa copy_constructor
/// \sa constructor
template<typename T>
void basic_constructors(const std::string &type, Module &m) {
m.add(constructor<T()>(), type);
copy_constructor<T>(type, m);
}
/// \brief Adds default and copy constructors for the given type
/// \param[in] type The name of the type to add the constructors for.
/// \param[in,out] m The Module to add the basic constructors to
/// \tparam T Type to generate basic constructors for
/// \returns The passed in Module
/// \sa copy_constructor
/// \sa constructor
template<typename T>
void basic_constructors(const std::string &type, Module& m)
{
m.add(constructor<T ()>(), type);
copy_constructor<T>(type, m);
}
/// \brief Adds a constructor for a POD type
/// \tparam T The type to add the constructor for
/// \param[in] type The name of the type
/// \param[in,out] m The Module to add the constructor to
template<typename T>
void construct_pod(const std::string &type, Module &m) {
m.add(fun([](const Boxed_Number &bn) { return bn.get_as<T>(); }), type);
}
/// \brief Adds a constructor for a POD type
/// \tparam T The type to add the constructor for
/// \param[in] type The name of the type
/// \param[in,out] m The Module to add the constructor to
template<typename T>
void construct_pod(const std::string &type, Module& m)
{
m.add(fun([](const Boxed_Number &bn){ return bn.get_as<T>(); }), type);
}
/// Internal function for converting from a string to a value
/// uses ostream operator >> to perform the conversion
template<typename Input>
auto parse_string(const std::string &i)
-> typename std::enable_if<
!std::is_same<Input, wchar_t>::value
&& !std::is_same<Input, char16_t>::value
&& !std::is_same<Input, char32_t>::value,
Input>::type
{
/// Internal function for converting from a string to a value
/// uses ostream operator >> to perform the conversion
template<typename Input>
Input parse_string(const std::string &i) {
if constexpr (!std::is_same<Input, wchar_t>::value && !std::is_same<Input, char16_t>::value && !std::is_same<Input, char32_t>::value) {
std::stringstream ss(i);
Input t;
ss >> t;
return t;
}
template<typename Input>
auto parse_string(const std::string &)
-> typename std::enable_if<
std::is_same<Input, wchar_t>::value
|| std::is_same<Input, char16_t>::value
|| std::is_same<Input, char32_t>::value,
Input>::type
{
} else {
throw std::runtime_error("Parsing of wide characters is not yet supported");
}
}
/// Add all common functions for a POD type. All operators, and
/// common conversions
template<typename T>
void bootstrap_pod_type(const std::string &name, Module &m) {
m.add(user_type<T>(), name);
m.add(constructor<T()>(), name);
construct_pod<T>(name, m);
/// Add all common functions for a POD type. All operators, and
/// common conversions
template<typename T>
void bootstrap_pod_type(const std::string &name, Module& m)
{
m.add(user_type<T>(), name);
m.add(constructor<T()>(), name);
construct_pod<T>(name, m);
m.add(fun(&parse_string<T>), "to_" + name);
m.add(fun([](const T t) { return t; }), "to_" + name);
}
m.add(fun(&parse_string<T>), "to_" + name);
m.add(fun([](const T t){ return t; }), "to_" + name);
/// "clone" function for a shared_ptr type. This is used in the case
/// where you do not want to make a deep copy of an object during cloning
/// but want to instead maintain the shared_ptr. It is needed internally
/// for handling of Proxy_Function object (that is,
/// function variables.
template<typename Type>
auto shared_ptr_clone(const std::shared_ptr<Type> &p) {
return p;
}
/// Specific version of shared_ptr_clone just for Proxy_Functions
template<typename Type>
std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<Type>> &p) {
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
}
/// Assignment function for shared_ptr objects, does not perform a copy of the
/// object pointed to, instead maintains the shared_ptr concept.
/// Similar to shared_ptr_clone. Used for Proxy_Function.
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) {
if (lhs.is_undef() || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get()))) {
lhs.assign(Boxed_Value(rhs));
return lhs;
} else {
throw exception::bad_boxed_cast("type mismatch in pointer assignment");
}
}
/// "clone" function for a shared_ptr type. This is used in the case
/// where you do not want to make a deep copy of an object during cloning
/// but want to instead maintain the shared_ptr. It is needed internally
/// for handling of Proxy_Function object (that is,
/// function variables.
template<typename Type>
auto shared_ptr_clone(const std::shared_ptr<Type> &p)
{
return p;
}
/// Specific version of shared_ptr_clone just for Proxy_Functions
template<typename Type>
std::shared_ptr<typename std::remove_const<Type>::type> shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
{
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
}
/// Assignment function for shared_ptr objects, does not perform a copy of the
/// object pointed to, instead maintains the shared_ptr concept.
/// Similar to shared_ptr_clone. Used for Proxy_Function.
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
{
if (lhs.is_undef()
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
{
lhs.assign(Boxed_Value(rhs));
return lhs;
/// Class consisting of only static functions. All default bootstrapping occurs
/// from this class.
class Bootstrap {
private:
/// Function allowing for assignment of an unknown type to any other value
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) {
if (lhs.is_undef()) {
return (lhs.assign(rhs));
} else {
throw exception::bad_boxed_cast("type mismatch in pointer assignment");
throw exception::bad_boxed_cast("boxed_value has a set type already");
}
}
/// Class consisting of only static functions. All default bootstrapping occurs
/// from this class.
class Bootstrap
{
private:
/// Function allowing for assignment of an unknown type to any other value
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs)
{
if (lhs.is_undef())
{
return (lhs.assign(rhs));
} else {
throw exception::bad_boxed_cast("boxed_value has a set type already");
}
static void print(const std::string &s) noexcept { fwrite(s.c_str(), 1, s.size(), stdout); }
static void println(const std::string &s) noexcept { puts(s.c_str()); }
/// Add all arithmetic operators for PODs
static void opers_arithmetic_pod(Module &m) {
m.add(fun(&Boxed_Number::equals), "==");
m.add(fun(&Boxed_Number::less_than), "<");
m.add(fun(&Boxed_Number::greater_than), ">");
m.add(fun(&Boxed_Number::greater_than_equal), ">=");
m.add(fun(&Boxed_Number::less_than_equal), "<=");
m.add(fun(&Boxed_Number::not_equal), "!=");
m.add(fun(&Boxed_Number::pre_decrement), "--");
m.add(fun(&Boxed_Number::pre_increment), "++");
m.add(fun(&Boxed_Number::sum), "+");
m.add(fun(&Boxed_Number::unary_plus), "+");
m.add(fun(&Boxed_Number::unary_minus), "-");
m.add(fun(&Boxed_Number::difference), "-");
m.add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m.add(fun(&Boxed_Number::assign), "=");
m.add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m.add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m.add(fun(&Boxed_Number::assign_remainder), "%=");
m.add(fun(&Boxed_Number::assign_shift_left), "<<=");
m.add(fun(&Boxed_Number::assign_shift_right), ">>=");
m.add(fun(&Boxed_Number::bitwise_and), "&");
m.add(fun(&Boxed_Number::bitwise_complement), "~");
m.add(fun(&Boxed_Number::bitwise_xor), "^");
m.add(fun(&Boxed_Number::bitwise_or), "|");
m.add(fun(&Boxed_Number::assign_product), "*=");
m.add(fun(&Boxed_Number::assign_quotient), "/=");
m.add(fun(&Boxed_Number::assign_sum), "+=");
m.add(fun(&Boxed_Number::assign_difference), "-=");
m.add(fun(&Boxed_Number::quotient), "/");
m.add(fun(&Boxed_Number::shift_left), "<<");
m.add(fun(&Boxed_Number::product), "*");
m.add(fun(&Boxed_Number::remainder), "%");
m.add(fun(&Boxed_Number::shift_right), ">>");
}
/// Create a bound function object. The first param is the function to bind
/// the remaining parameters are the args to bind into the result
static Boxed_Value bind_function(const Function_Params &params) {
if (params.empty()) {
throw exception::arity_error(0, 1);
}
static void print(const std::string &s)
{
fwrite(s.c_str(), 1, s.size(), stdout);
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) {
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
}
static void println(const std::string &s)
{
puts(s.c_str());
return Boxed_Value(Const_Proxy_Function(
std::make_shared<dispatch::Bound_Function>(std::move(f), std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
}
static bool has_guard(const Const_Proxy_Function &t_pf) noexcept {
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->has_guard();
}
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) {
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_guard()) {
return pf->get_guard();
} else {
throw std::runtime_error("Function does not have a guard");
}
}
template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, const dispatch::Proxy_Function_Base *b) {
auto v = (b->*f)();
std::vector<Boxed_Value> vbv;
for (const auto &o : v) {
vbv.push_back(const_var(o));
}
return vbv;
}
/// Add all arithmetic operators for PODs
static void opers_arithmetic_pod(Module& m)
{
m.add(fun(&Boxed_Number::equals), "==");
m.add(fun(&Boxed_Number::less_than), "<");
m.add(fun(&Boxed_Number::greater_than), ">");
m.add(fun(&Boxed_Number::greater_than_equal), ">=");
m.add(fun(&Boxed_Number::less_than_equal), "<=");
m.add(fun(&Boxed_Number::not_equal), "!=");
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept {
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
return bool(pf);
}
m.add(fun(&Boxed_Number::pre_decrement), "--");
m.add(fun(&Boxed_Number::pre_increment), "++");
m.add(fun(&Boxed_Number::sum), "+");
m.add(fun(&Boxed_Number::unary_plus), "+");
m.add(fun(&Boxed_Number::unary_minus), "-");
m.add(fun(&Boxed_Number::difference), "-");
m.add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m.add(fun(&Boxed_Number::assign), "=");
m.add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m.add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m.add(fun(&Boxed_Number::assign_remainder), "%=");
m.add(fun(&Boxed_Number::assign_shift_left), "<<=");
m.add(fun(&Boxed_Number::assign_shift_right), ">>=");
m.add(fun(&Boxed_Number::bitwise_and), "&");
m.add(fun(&Boxed_Number::bitwise_complement), "~");
m.add(fun(&Boxed_Number::bitwise_xor), "^");
m.add(fun(&Boxed_Number::bitwise_or), "|");
m.add(fun(&Boxed_Number::assign_product), "*=");
m.add(fun(&Boxed_Number::assign_quotient), "/=");
m.add(fun(&Boxed_Number::assign_sum), "+=");
m.add(fun(&Boxed_Number::assign_difference), "-=");
m.add(fun(&Boxed_Number::quotient), "/");
m.add(fun(&Boxed_Number::shift_left), "<<");
m.add(fun(&Boxed_Number::product), "*");
m.add(fun(&Boxed_Number::remainder), "%");
m.add(fun(&Boxed_Number::shift_right), ">>");
}
/// Create a bound function object. The first param is the function to bind
/// the remaining parameters are the args to bind into the result
static Boxed_Value bind_function(const std::vector<Boxed_Value> &params)
{
if (params.empty()) {
throw exception::arity_error(0, 1);
}
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1)
{
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
}
return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(std::move(f),
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
static const chaiscript::AST_Node &get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) {
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf) {
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
template<typename Function>
static auto return_boxed_value_vector(const Function &f) {
return [f](const dispatch::Proxy_Function_Base *b) { return do_return_boxed_value_vector(f, b); };
}
static bool has_guard(const Const_Proxy_Function &t_pf)
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->get_guard();
}
public:
/// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to
/// \returns passed in Module
static void bootstrap(Module &m) {
m.add(user_type<void>(), "void");
m.add(user_type<bool>(), "bool");
m.add(user_type<Boxed_Value>(), "Object");
m.add(user_type<Boxed_Number>(), "Number");
m.add(user_type<Proxy_Function>(), "Function");
m.add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
m.add(user_type<std::exception>(), "exception");
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
{
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_guard())
{
return pf->get_guard();
} else {
throw std::runtime_error("Function does not have a guard");
}
}
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
const dispatch::Proxy_Function_Base *b)
{
auto v = (b->*f)();
std::vector<Boxed_Value> vbv;
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
for (const auto &o: v)
{
vbv.push_back(const_var(o));
}
m.add(fun([](const std::exception &e) { return std::string(e.what()); }), "what");
return vbv;
}
m.add(user_type<std::out_of_range>(), "out_of_range");
m.add(user_type<std::logic_error>(), "logic_error");
m.add(chaiscript::base_class<std::exception, std::logic_error>());
m.add(chaiscript::base_class<std::logic_error, std::out_of_range>());
m.add(chaiscript::base_class<std::exception, std::out_of_range>());
m.add(user_type<std::runtime_error>(), "runtime_error");
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
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);
return bool(pf);
}
m.add(constructor<std::runtime_error(const std::string &)>(), "runtime_error");
static const chaiscript::AST_Node &get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object(const std::string &)>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object()>(), "Dynamic_Object");
m.add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
m.add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
m.add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr");
template<typename Function>
static auto return_boxed_value_vector(const Function &f)
{
return [f](const dispatch::Proxy_Function_Base *b) {
return do_return_boxed_value_vector(f, b);
};
}
m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
"get_attr");
m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)),
"method_missing");
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(
&dispatch::Dynamic_Object::method_missing)),
"method_missing");
public:
/// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to
/// \returns passed in Module
static void bootstrap(Module& m)
{
m.add(user_type<void>(), "void");
m.add(user_type<bool>(), "bool");
m.add(user_type<Boxed_Value>(), "Object");
m.add(user_type<Boxed_Number>(), "Number");
m.add(user_type<Proxy_Function>(), "Function");
m.add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
m.add(user_type<std::exception>(), "exception");
m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
"[]");
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
m.add(fun([](const std::exception &e){ return std::string(e.what()); }), "what");
m.add(user_type<std::out_of_range>(), "out_of_range");
m.add(user_type<std::logic_error>(), "logic_error");
m.add(chaiscript::base_class<std::exception, std::logic_error>());
m.add(chaiscript::base_class<std::logic_error, std::out_of_range>());
m.add(chaiscript::base_class<std::exception, std::out_of_range>());
m.add(user_type<std::runtime_error>(), "runtime_error");
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
m.add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object");
m.add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
m.add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
m.add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
m.eval(R"chaiscript(
def Dynamic_Object::clone() {
auto &new_o = Dynamic_Object(this.get_type_name());
for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
new_o;
m.eval(R"chaiscript(
def Dynamic_Object::clone() {
auto &new_o = Dynamic_Object(this.get_type_name());
for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
new_o;
}
def `=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
{
for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } );
for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } );
}
def `!=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
@ -420,173 +355,157 @@ namespace chaiscript
}
)chaiscript");
m.add(fun(&has_guard), "has_guard");
m.add(fun(&get_guard), "get_guard");
m.add(fun(&has_guard), "has_guard");
m.add(fun(&get_guard), "get_guard");
m.add(fun(&Boxed_Value::is_undef), "is_var_undef");
m.add(fun(&Boxed_Value::is_null), "is_var_null");
m.add(fun(&Boxed_Value::is_const), "is_var_const");
m.add(fun(&Boxed_Value::is_ref), "is_var_reference");
m.add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
m.add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
m.add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
m.add(fun(&Boxed_Value::is_type), "is_type");
m.add(fun(&Boxed_Value::get_attr), "get_var_attr");
m.add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
m.add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
m.add(fun(&Boxed_Value::is_undef), "is_var_undef");
m.add(fun(&Boxed_Value::is_null), "is_var_null");
m.add(fun(&Boxed_Value::is_const), "is_var_const");
m.add(fun(&Boxed_Value::is_ref), "is_var_reference");
m.add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
m.add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
m.add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
m.add(fun(&Boxed_Value::is_type), "is_type");
m.add(fun(&Boxed_Value::get_attr), "get_var_attr");
m.add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
m.add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
m.add(fun(&Boxed_Value::get_type_info), "get_type_info");
m.add(user_type<Type_Info>(), "Type_Info");
m.add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
m.add(fun(&Boxed_Value::get_type_info), "get_type_info");
m.add(user_type<Type_Info>(), "Type_Info");
m.add(constructor<Type_Info(const Type_Info &)>(), "Type_Info");
operators::equal<Type_Info>(m);
operators::equal<Type_Info>(m);
m.add(fun(&Type_Info::is_const), "is_type_const");
m.add(fun(&Type_Info::is_reference), "is_type_reference");
m.add(fun(&Type_Info::is_void), "is_type_void");
m.add(fun(&Type_Info::is_undef), "is_type_undef");
m.add(fun(&Type_Info::is_pointer), "is_type_pointer");
m.add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
m.add(fun(&Type_Info::name), "cpp_name");
m.add(fun(&Type_Info::bare_name), "cpp_bare_name");
m.add(fun(&Type_Info::bare_equal), "bare_equal");
m.add(fun(&Type_Info::is_const), "is_type_const");
m.add(fun(&Type_Info::is_reference), "is_type_reference");
m.add(fun(&Type_Info::is_void), "is_type_void");
m.add(fun(&Type_Info::is_undef), "is_type_undef");
m.add(fun(&Type_Info::is_pointer), "is_type_pointer");
m.add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
m.add(fun(&Type_Info::name), "cpp_name");
m.add(fun(&Type_Info::bare_name), "cpp_bare_name");
m.add(fun(&Type_Info::bare_equal), "bare_equal");
basic_constructors<bool>("bool", m);
operators::assign<bool>(m);
operators::equal<bool>(m);
operators::not_equal<bool>(m);
m.add(fun([](const std::string &s) { return s; }), "to_string");
m.add(fun([](const bool b) { return std::string(b ? "true" : "false"); }), "to_string");
m.add(fun(&unknown_assign), "=");
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
basic_constructors<bool>("bool", m);
operators::assign<bool>(m);
operators::equal<bool>(m);
operators::not_equal<bool>(m);
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
m.add(fun(&Boxed_Number::to_string), "to_string");
m.add(fun([](const std::string &s) { return s; }), "to_string");
m.add(fun([](const bool b) { return std::string(b?"true":"false"); }), "to_string");
m.add(fun(&unknown_assign), "=");
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m);
bootstrap_pod_type<float>("float", m);
bootstrap_pod_type<int>("int", m);
bootstrap_pod_type<long>("long", m);
bootstrap_pod_type<unsigned int>("unsigned_int", m);
bootstrap_pod_type<unsigned long>("unsigned_long", m);
bootstrap_pod_type<long long>("long_long", m);
bootstrap_pod_type<unsigned long long>("unsigned_long_long", m);
bootstrap_pod_type<size_t>("size_t", m);
bootstrap_pod_type<char>("char", m);
bootstrap_pod_type<wchar_t>("wchar_t", m);
bootstrap_pod_type<char16_t>("char16_t", m);
bootstrap_pod_type<char32_t>("char32_t", m);
bootstrap_pod_type<std::int8_t>("int8_t", m);
bootstrap_pod_type<std::int16_t>("int16_t", m);
bootstrap_pod_type<std::int32_t>("int32_t", m);
bootstrap_pod_type<std::int64_t>("int64_t", m);
bootstrap_pod_type<std::uint8_t>("uint8_t", m);
bootstrap_pod_type<std::uint16_t>("uint16_t", m);
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
m.add(fun(&Boxed_Number::to_string), "to_string");
operators::logical_compliment<bool>(m);
opers_arithmetic_pod(m);
bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m);
bootstrap_pod_type<float>("float", m);
bootstrap_pod_type<int>("int", m);
bootstrap_pod_type<long>("long", m);
bootstrap_pod_type<unsigned int>("unsigned_int", m);
bootstrap_pod_type<unsigned long>("unsigned_long", m);
bootstrap_pod_type<long long>("long_long", m);
bootstrap_pod_type<unsigned long long>("unsigned_long_long", m);
bootstrap_pod_type<size_t>("size_t", m);
bootstrap_pod_type<char>("char", m);
bootstrap_pod_type<wchar_t>("wchar_t", m);
bootstrap_pod_type<char16_t>("char16_t", m);
bootstrap_pod_type<char32_t>("char32_t", m);
bootstrap_pod_type<std::int8_t>("int8_t", m);
bootstrap_pod_type<std::int16_t>("int16_t", m);
bootstrap_pod_type<std::int32_t>("int32_t", m);
bootstrap_pod_type<std::int64_t>("int64_t", m);
bootstrap_pod_type<std::uint8_t>("uint8_t", m);
bootstrap_pod_type<std::uint16_t>("uint16_t", m);
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
m.add(fun(&Build_Info::version_major), "version_major");
m.add(fun(&Build_Info::version_minor), "version_minor");
m.add(fun(&Build_Info::version_patch), "version_patch");
m.add(fun(&Build_Info::version), "version");
m.add(fun(&Build_Info::compiler_version), "compiler_version");
m.add(fun(&Build_Info::compiler_name), "compiler_name");
m.add(fun(&Build_Info::compiler_id), "compiler_id");
m.add(fun(&Build_Info::debug_build), "debug_build");
m.add(fun(&print), "print_string");
m.add(fun(&println), "println_string");
operators::logical_compliment<bool>(m);
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
opers_arithmetic_pod(m);
m.add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m.add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
m.add(fun([](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
t_lhs.assign(t_rhs);
}),
"=");
m.add(fun(&Boxed_Value::type_match), "type_match");
m.add(fun(&Build_Info::version_major), "version_major");
m.add(fun(&Build_Info::version_minor), "version_minor");
m.add(fun(&Build_Info::version_patch), "version_patch");
m.add(fun(&Build_Info::version), "version");
m.add(fun(&Build_Info::compiler_version), "compiler_version");
m.add(fun(&Build_Info::compiler_name), "compiler_name");
m.add(fun(&Build_Info::compiler_id), "compiler_id");
m.add(fun(&Build_Info::debug_build), "debug_build");
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
m.add(fun(&print), "print_string");
m.add(fun(&println), "println_string");
m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> >
// >("AST_NodeVector", m);
m.add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m.add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
m.add(fun(
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
t_lhs.assign(t_rhs);
}
), "="
);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
"eval_error",
{},
{{fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
{fun([](const chaiscript::exception::eval_error &t_eval_error) {
std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(),
t_eval_error.call_stack.end(),
std::back_inserter(retval),
&chaiscript::var<const chaiscript::AST_Node_Trace &>);
return retval;
}),
"call_stack"}});
m.add(fun(&Boxed_Value::type_match), "type_match");
chaiscript::utility::add_class<chaiscript::File_Position>(m,
"File_Position",
{constructor<File_Position()>(), constructor<File_Position(int, int)>()},
{{fun(&File_Position::line), "line"},
{fun(&File_Position::column), "column"}});
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
"eval_error",
{ },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
{fun([](const chaiscript::exception::eval_error &t_eval_error) {
std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
std::back_inserter(retval),
&chaiscript::var<const chaiscript::AST_Node_Trace &>);
return retval;
}), "call_stack"} }
);
chaiscript::utility::add_class<chaiscript::File_Position>(m,
"File_Position",
{ constructor<File_Position()>(),
constructor<File_Position(int, int)>() },
{ {fun(&File_Position::line), "line"},
{fun(&File_Position::column), "column"} }
);
chaiscript::utility::add_class<AST_Node>(m,
"AST_Node",
{ },
{ {fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"},
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
const auto children = t_node.get_children();
std::transform(children.begin(), children.end(),
std::back_inserter(retval),
&chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>);
return retval;
}), "children"}
}
);
}
};
}
}
chaiscript::utility::add_class<AST_Node>(m,
"AST_Node",
{},
{{fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"},
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
const auto children = t_node.get_children();
std::transform(children.begin(),
children.end(),
std::back_inserter(retval),
&chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>);
return retval;
}),
"children"}});
}
};
} // namespace chaiscript::bootstrap
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_
@ -19,23 +18,19 @@
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
namespace detail {
namespace exception {
class bad_any_cast;
} // namespace exception
} // namespace detail
} // namespace chaiscript
class Type_Conversions;
}
namespace chaiscript::detail::exception {
class bad_any_cast;
} // namespace chaiscript::detail::exception
namespace chaiscript
{
namespace chaiscript {
/// \brief Function for extracting a value stored in a Boxed_Value object
/// \tparam Type The type to extract from the Boxed_Value
/// \param[in] bv The Boxed_Value to extract a typed value from
/// \returns Type equivalent to the requested type
/// \returns Type equivalent to the requested type
/// \throws exception::bad_boxed_cast If the requested conversion is not possible
///
///
/// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper,
/// and std::function (const and non-const) where possible. boxed_cast is used internally during function
/// dispatch. This means that all of these conversions will be attempted automatically for you during
@ -67,47 +62,41 @@ namespace chaiscript
/// std::function conversion example
/// \code
/// chaiscript::ChaiScript chai;
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
/// std::function<int (int, int)> f = chaiscript::boxed_cast<std::function<int (int, int)> >(bv);
/// int i = f(2,3);
/// assert(i == 5);
/// \endcode
template<typename Type>
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
{
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr) {
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
try {
return(detail::Cast_Helper<Type>::cast(bv, t_conversions));
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
}
}
if (t_conversions && (*t_conversions)->convertable_type<Type>())
{
if (t_conversions && (*t_conversions)->convertable_type<Type>()) {
try {
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
} catch (...) {
try {
// try going the other way
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions));
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv),
t_conversions));
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
}
} else {
// If it's not convertable, just throw the error, don't waste the time on the
// If it's not convertable, just throw the error, don't waste the time on the
// attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
}
}
} // namespace chaiscript
#endif

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
@ -17,21 +16,19 @@
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace chaiscript {
class Type_Conversions_State;
namespace detail
{
namespace detail {
// Cast_Helper_Inner helper classes
template<typename T>
T* throw_if_null(T *t)
{
if (t) { return t; }
throw std::runtime_error("Attempted to dereference null Boxed_Value");
constexpr T *throw_if_null(T *t) {
if (t) {
return t;
}
throw std::runtime_error("Attempted to dereference null Boxed_Value");
}
template<typename T>
static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
@ -51,7 +48,6 @@ namespace chaiscript
}
}
template<typename T>
static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info().bare_equal_type_info(ti)) {
@ -72,252 +68,193 @@ namespace chaiscript
/// Generic Cast_Helper_Inner, for casting to any type
template<typename Result>
struct Cast_Helper_Inner
{
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
}
};
struct Cast_Helper_Inner {
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
}
};
template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
{
};
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> {
};
/// Cast_Helper_Inner for casting to a const * type
template<typename Result>
struct Cast_Helper_Inner<const Result *>
{
static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
}
};
struct Cast_Helper_Inner<const Result *> {
static const Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
}
};
/// Cast_Helper_Inner for casting to a * type
template<typename Result>
struct Cast_Helper_Inner<Result *>
{
static Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
}
};
template<typename Result>
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
{
struct Cast_Helper_Inner<Result *> {
static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
}
};
template<typename Result>
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *>
{
struct Cast_Helper_Inner<Result *const &> : public Cast_Helper_Inner<Result *> {
};
template<typename Result>
struct Cast_Helper_Inner<const Result *const &> : public Cast_Helper_Inner<const Result *> {
};
/// Cast_Helper_Inner for casting to a & type
template<typename Result>
struct Cast_Helper_Inner<const Result &>
{
static const Result & cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
}
};
struct Cast_Helper_Inner<const Result &> {
static const Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
}
};
/// Cast_Helper_Inner for casting to a & type
template<typename Result>
struct Cast_Helper_Inner<Result &>
{
static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
}
};
struct Cast_Helper_Inner<Result &> {
static Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
}
};
/// Cast_Helper_Inner for casting to a && type
template<typename Result>
struct Cast_Helper_Inner<Result &&>
{
static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
}
};
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>>>()));
}
};
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>>>());
}
};
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>>>());
}
};
struct Cast_Helper_Inner<const std::unique_ptr<Result> &> {
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> >
{
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob.get().cast<std::shared_ptr<Result> >();
}
};
struct Cast_Helper_Inner<std::shared_ptr<Result>> {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob.get().cast<std::shared_ptr<Result>>(); }
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<const Result> >
{
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (!ob.get_type_info().is_const())
{
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
} else {
return ob.get().cast<std::shared_ptr<const Result> >();
}
struct Cast_Helper_Inner<std::shared_ptr<const Result>> {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
if (!ob.get_type_info().is_const()) {
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result>>());
} else {
return ob.get().cast<std::shared_ptr<const Result>>();
}
};
}
};
/// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> >
{
};
struct Cast_Helper_Inner<const std::shared_ptr<Result>> : Cast_Helper_Inner<std::shared_ptr<Result>> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result> >
{
};
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result>> {
};
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> &>
{
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
return ob.pointer_sentinel(res);
}
};
struct Cast_Helper_Inner<std::shared_ptr<Result> &> {
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result>>();
return ob.pointer_sentinel(res);
}
};
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
{
};
struct Cast_Helper_Inner<const std::shared_ptr<const Result>> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> >
{
};
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
};
/// Cast_Helper_Inner for casting to a Boxed_Value type
template<>
struct Cast_Helper_Inner<Boxed_Value>
{
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob;
}
};
struct Cast_Helper_Inner<Boxed_Value> {
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob; }
};
/// Cast_Helper_Inner for casting to a Boxed_Value & type
template<>
struct Cast_Helper_Inner<Boxed_Value &>
{
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::ref(const_cast<Boxed_Value &>(ob));
}
};
struct Cast_Helper_Inner<Boxed_Value &> {
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return std::ref(const_cast<Boxed_Value &>(ob));
}
};
/// Cast_Helper_Inner for casting to a const Boxed_Value & type
template<>
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value>
{
};
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> {
};
template<>
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value>
{
};
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value> {
};
/// Cast_Helper_Inner for casting to a std::reference_wrapper type
template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{
};
struct Cast_Helper_Inner<std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{
};
struct Cast_Helper_Inner<const std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &>
{
};
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
{
};
struct Cast_Helper_Inner<std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
{
};
struct Cast_Helper_Inner<const std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &>
{
};
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> &> : Cast_Helper_Inner<const Result &> {
};
/// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
template<typename T>
struct Cast_Helper
{
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{
return(Cast_Helper_Inner<T>::cast(ob, t_conversions));
}
};
}
}
struct Cast_Helper {
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
return (Cast_Helper_Inner<T>::cast(ob, t_conversions));
}
};
} // namespace detail
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
#define CHAISCRIPT_BOXED_VALUE_HPP_
@ -19,357 +18,238 @@
#include "any.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace chaiscript {
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
/// \sa chaiscript::boxed_cast
class Boxed_Value
{
public:
/// used for explicitly creating a "void" object
struct Void_Type
{
};
class Boxed_Value {
public:
/// used for explicitly creating a "void" object
struct Void_Type {
};
private:
/// structure which holds the internal state of a Boxed_Value
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process
struct Data
{
Data(const Type_Info &ti,
chaiscript::detail::Any to,
bool is_ref,
const void *t_void_ptr,
bool t_return_value)
: m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
m_is_ref(is_ref), m_return_value(t_return_value)
{
}
Data &operator=(const Data &rhs)
{
m_type_info = rhs.m_type_info;
m_obj = rhs.m_obj;
m_is_ref = rhs.m_is_ref;
m_data_ptr = rhs.m_data_ptr;
m_const_data_ptr = rhs.m_const_data_ptr;
m_return_value = rhs.m_return_value;
if (rhs.m_attrs)
{
m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
}
return *this;
}
Data(const Data &) = delete;
Data(Data &&) = default;
Data &operator=(Data &&rhs) = default;
Type_Info m_type_info;
chaiscript::detail::Any m_obj;
void *m_data_ptr;
const void *m_const_data_ptr;
std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>> m_attrs;
bool m_is_ref;
bool m_return_value;
};
struct Object_Data
{
static auto get(Boxed_Value::Void_Type, bool t_return_value)
{
return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
chaiscript::detail::Any(),
false,
nullptr,
t_return_value)
;
}
template<typename T>
static auto get(const std::shared_ptr<T> *obj, bool t_return_value)
{
return get(*obj, t_return_value);
}
template<typename T>
static auto get(const std::shared_ptr<T> &obj, bool t_return_value)
{
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj),
false,
obj.get(),
t_return_value
);
}
template<typename T>
static auto get(std::shared_ptr<T> &&obj, bool t_return_value)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
false,
ptr,
t_return_value
);
}
template<typename T>
static auto get(T *t, bool t_return_value)
{
return get(std::ref(*t), t_return_value);
}
template<typename T>
static auto get(const T *t, bool t_return_value)
{
return get(std::cref(*t), t_return_value);
}
template<typename T>
static auto get(std::reference_wrapper<T> obj, bool t_return_value)
{
auto p = &obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
true,
p,
t_return_value
);
}
template<typename T>
static auto get(std::unique_ptr<T> &&obj, bool t_return_value)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
true,
ptr,
t_return_value
);
}
template<typename T>
static auto get(T t, bool t_return_value)
{
auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr,
t_return_value
);
}
static std::shared_ptr<Data> get()
{
return std::make_shared<Data>(
Type_Info(),
chaiscript::detail::Any(),
false,
nullptr,
false
);
}
};
public:
/// Basic Boxed_Value constructor
template<typename T,
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
explicit Boxed_Value(T &&t, bool t_return_value = false)
: m_data(Object_Data::get(std::forward<T>(t), t_return_value))
{
}
/// Unknown-type constructor
Boxed_Value() = default;
Boxed_Value(Boxed_Value&&) = default;
Boxed_Value& operator=(Boxed_Value&&) = default;
Boxed_Value(const Boxed_Value&) = default;
Boxed_Value& operator=(const Boxed_Value&) = default;
void swap(Boxed_Value &rhs)
{
std::swap(m_data, rhs.m_data);
private:
/// structure which holds the internal state of a Boxed_Value
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process
struct Data {
Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value)
: m_type_info(ti)
, m_obj(std::move(to))
, m_data_ptr(ti.is_const() ? nullptr : const_cast<void *>(t_void_ptr))
, m_const_data_ptr(t_void_ptr)
, m_is_ref(is_ref)
, m_return_value(t_return_value) {
}
/// Copy the values stored in rhs.m_data to m_data.
/// m_data pointers are not shared in this case
Boxed_Value assign(const Boxed_Value &rhs)
{
(*m_data) = (*rhs.m_data);
Data &operator=(const Data &rhs) {
m_type_info = rhs.m_type_info;
m_obj = rhs.m_obj;
m_is_ref = rhs.m_is_ref;
m_data_ptr = rhs.m_data_ptr;
m_const_data_ptr = rhs.m_const_data_ptr;
m_return_value = rhs.m_return_value;
if (rhs.m_attrs) {
m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
}
return *this;
}
const Type_Info &get_type_info() const noexcept
{
return m_data->m_type_info;
}
Data(const Data &) = delete;
/// return true if the object is uninitialized
bool is_undef() const noexcept
{
return m_data->m_type_info.is_undef();
}
Data(Data &&) = default;
Data &operator=(Data &&rhs) = default;
bool is_const() const noexcept
{
return m_data->m_type_info.is_const();
}
Type_Info m_type_info;
chaiscript::detail::Any m_obj;
void *m_data_ptr;
const void *m_const_data_ptr;
std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>> m_attrs;
bool m_is_ref;
bool m_return_value;
};
bool is_type(const Type_Info &ti) const noexcept
{
return m_data->m_type_info.bare_equal(ti);
struct Object_Data {
static auto get(Boxed_Value::Void_Type, bool t_return_value) {
return std::make_shared<Data>(detail::Get_Type_Info<void>::get(), chaiscript::detail::Any(), false, nullptr, t_return_value);
}
template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const
{
struct Sentinel {
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
: m_ptr(t_ptr), m_data(data)
{
}
~Sentinel()
{
// save new pointer data
const auto ptr_ = m_ptr.get().get();
m_data.get().m_data_ptr = ptr_;
m_data.get().m_const_data_ptr = ptr_;
}
Sentinel& operator=(Sentinel&&s) = default;
Sentinel(Sentinel &&s) = default;
operator std::shared_ptr<T>&() const
{
return m_ptr.get();
}
Sentinel &operator=(const Sentinel &) = delete;
Sentinel(Sentinel&) = delete;
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
std::reference_wrapper<Data> m_data;
};
return Sentinel(ptr, *(m_data.get()));
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) {
return get(*obj, t_return_value);
}
bool is_null() const noexcept
{
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
template<typename T>
static auto get(const std::shared_ptr<T> &obj, bool t_return_value) {
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(obj), false, obj.get(), t_return_value);
}
const chaiscript::detail::Any & get() const noexcept
{
return m_data->m_obj;
template<typename T>
static auto get(std::shared_ptr<T> &&obj, bool t_return_value) {
auto ptr = obj.get();
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(obj)), false, ptr, t_return_value);
}
bool is_ref() const noexcept
{
return m_data->m_is_ref;
template<typename T>
static auto get(T *t, bool t_return_value) {
return get(std::ref(*t), t_return_value);
}
bool is_return_value() const noexcept
{
return m_data->m_return_value;
template<typename T>
static auto get(const T *t, bool t_return_value) {
return get(std::cref(*t), t_return_value);
}
void reset_return_value() const noexcept
{
m_data->m_return_value = false;
template<typename T>
static auto get(std::reference_wrapper<T> obj, bool t_return_value) {
auto p = &obj.get();
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(obj)), true, p, t_return_value);
}
bool is_pointer() const noexcept
{
return !is_ref();
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);
}
void *get_ptr() const noexcept
{
return m_data->m_data_ptr;
template<typename T>
static auto get(T t, bool t_return_value) {
auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(p)), false, ptr, t_return_value);
}
const void *get_const_ptr() const noexcept
{
return m_data->m_const_data_ptr;
}
static std::shared_ptr<Data> get() { return std::make_shared<Data>(Type_Info(), chaiscript::detail::Any(), false, nullptr, false); }
};
Boxed_Value get_attr(const std::string &t_name)
{
if (!m_data->m_attrs)
{
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
public:
/// Basic Boxed_Value constructor
template<typename T, typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_t<T>>>>
explicit Boxed_Value(T &&t, bool t_return_value = false)
: m_data(Object_Data::get(std::forward<T>(t), t_return_value)) {
}
/// Unknown-type constructor
Boxed_Value() = default;
Boxed_Value(Boxed_Value &&) = default;
Boxed_Value &operator=(Boxed_Value &&) = default;
Boxed_Value(const Boxed_Value &) = default;
Boxed_Value &operator=(const Boxed_Value &) = default;
void swap(Boxed_Value &rhs) noexcept { std::swap(m_data, rhs.m_data); }
/// Copy the values stored in rhs.m_data to m_data.
/// m_data pointers are not shared in this case
Boxed_Value assign(const Boxed_Value &rhs) noexcept {
(*m_data) = (*rhs.m_data);
return *this;
}
const Type_Info &get_type_info() const noexcept { return m_data->m_type_info; }
/// return true if the object is uninitialized
bool is_undef() const noexcept { return m_data->m_type_info.is_undef(); }
bool is_const() const noexcept { return m_data->m_type_info.is_const(); }
bool is_type(const Type_Info &ti) const noexcept { return m_data->m_type_info.bare_equal(ti); }
template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const noexcept {
struct Sentinel {
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
: m_ptr(t_ptr)
, m_data(data) {
}
auto &attr = (*m_data->m_attrs)[t_name];
if (attr) {
return Boxed_Value(attr, Internal_Construction());
} else {
Boxed_Value bv; //default construct a new one
attr = bv.m_data;
return bv;
~Sentinel() {
// save new pointer data
const auto ptr_ = m_ptr.get().get();
m_data.get().m_data_ptr = ptr_;
m_data.get().m_const_data_ptr = ptr_;
}
Sentinel &operator=(Sentinel &&s) = default;
Sentinel(Sentinel &&s) = default;
operator std::shared_ptr<T> &() const noexcept { return m_ptr.get(); }
Sentinel &operator=(const Sentinel &) = delete;
Sentinel(Sentinel &) = delete;
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
std::reference_wrapper<Data> m_data;
};
return Sentinel(ptr, *(m_data.get()));
}
bool is_null() const noexcept { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); }
const chaiscript::detail::Any &get() const noexcept { return m_data->m_obj; }
bool is_ref() const noexcept { return m_data->m_is_ref; }
bool is_return_value() const noexcept { return m_data->m_return_value; }
void reset_return_value() const noexcept { m_data->m_return_value = false; }
bool is_pointer() const noexcept { return !is_ref(); }
void *get_ptr() const noexcept { return m_data->m_data_ptr; }
const void *get_const_ptr() const noexcept { return m_data->m_const_data_ptr; }
Boxed_Value get_attr(const std::string &t_name) {
if (!m_data->m_attrs) {
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
}
Boxed_Value &copy_attrs(const Boxed_Value &t_obj)
{
if (t_obj.m_data->m_attrs)
{
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
}
return *this;
auto &attr = (*m_data->m_attrs)[t_name];
if (attr) {
return Boxed_Value(attr, Internal_Construction());
} else {
Boxed_Value bv; // default construct a new one
attr = bv.m_data;
return bv;
}
}
Boxed_Value &clone_attrs(const Boxed_Value &t_obj)
{
copy_attrs(t_obj);
reset_return_value();
return *this;
Boxed_Value &copy_attrs(const Boxed_Value &t_obj) {
if (t_obj.m_data->m_attrs) {
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
}
return *this;
}
Boxed_Value &clone_attrs(const Boxed_Value &t_obj) {
copy_attrs(t_obj);
reset_return_value();
return *this;
}
/// \returns true if the two Boxed_Values share the same internal type
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept
{
return l.get_type_info() == r.get_type_info();
}
/// \returns true if the two Boxed_Values share the same internal type
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept { return l.get_type_info() == r.get_type_info(); }
private:
// necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction{};
private:
// necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction {
};
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
: m_data(std::move(t_data)) {
}
}
std::shared_ptr<Data> m_data = Object_Data::get();
std::shared_ptr<Data> m_data = Object_Data::get();
};
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or
/// std::reference_type
/// a copy is not made.
/// @param t The value to box
///
@ -384,21 +264,19 @@ namespace chaiscript
///
/// @sa @ref adding_objects
template<typename T>
Boxed_Value var(T &&t)
{
return Boxed_Value(std::forward<T>(t));
}
Boxed_Value var(T &&t) {
return Boxed_Value(std::forward<T>(t));
}
namespace detail {
/// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable
/// \param[in] t Value to copy and make const
/// \returns Immutable Boxed_Value
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
template<typename T>
Boxed_Value const_var_impl(const T &t)
{
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
}
Boxed_Value const_var_impl(const T &t) {
return Boxed_Value(std::make_shared<typename std::add_const<T>::type>(t));
}
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
/// Does not copy the pointed to value.
@ -406,10 +284,9 @@ namespace chaiscript
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
template<typename T>
Boxed_Value const_var_impl(T *t)
{
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
}
Boxed_Value const_var_impl(T *t) {
return Boxed_Value(const_cast<typename std::add_const<T>::type *>(t));
}
/// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
/// Does not copy the pointed to value.
@ -417,10 +294,9 @@ namespace chaiscript
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
template<typename T>
Boxed_Value const_var_impl(const std::shared_ptr<T> &t)
{
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) );
}
Boxed_Value const_var_impl(const std::shared_ptr<T> &t) {
return Boxed_Value(std::const_pointer_cast<typename std::add_const<T>::type>(t));
}
/// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
/// Does not copy the referenced value.
@ -428,11 +304,10 @@ namespace chaiscript
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
template<typename T>
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t)
{
return Boxed_Value( std::cref(t.get()) );
}
}
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t) {
return Boxed_Value(std::cref(t.get()));
}
} // namespace detail
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
/// the value is not copied. If it is an object type, it is copied.
@ -454,14 +329,13 @@ namespace chaiscript
/// chai.add(chaiscript::const_var(Red), "Red");
/// chai.add(chaiscript::const_var(Green), "Green");
/// \endcode
///
///
/// \todo support C++11 strongly typed enums
/// \sa \ref adding_objects
template<typename T>
Boxed_Value const_var(const T &t)
{
return detail::const_var_impl(t);
}
Boxed_Value const_var(const T &t) {
return detail::const_var_impl(t);
}
inline Boxed_Value void_var() {
static const auto v = Boxed_Value(Boxed_Value::Void_Type());
@ -479,7 +353,6 @@ namespace chaiscript
}
}
}
} // namespace chaiscript
#endif

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
@ -18,21 +17,17 @@
#include "boxed_value.hpp"
namespace chaiscript {
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
namespace chaiscript
{
namespace dispatch
{
namespace chaiscript {
namespace dispatch {
struct option_explicit_set : std::runtime_error {
explicit option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
{
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") {
}
option_explicit_set(const option_explicit_set &) = default;
@ -40,92 +35,64 @@ namespace chaiscript
~option_explicit_set() noexcept override = default;
};
class Dynamic_Object
{
public:
explicit Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name)), m_option_explicit(false)
{
class Dynamic_Object {
public:
explicit Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name))
, m_option_explicit(false) {
}
Dynamic_Object() = default;
bool is_explicit() const noexcept { return m_option_explicit; }
void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; }
const std::string &get_type_name() const noexcept { return m_type_name; }
const Boxed_Value &operator[](const std::string &t_attr_name) const { return get_attr(t_attr_name); }
Boxed_Value &operator[](const std::string &t_attr_name) { return get_attr(t_attr_name); }
const Boxed_Value &get_attr(const std::string &t_attr_name) const {
auto a = m_attrs.find(t_attr_name);
if (a != m_attrs.end()) {
return a->second;
} else {
throw std::range_error("Attr not found '" + t_attr_name + "' and cannot be added to const obj");
}
}
bool has_attr(const std::string &t_attr_name) const { return m_attrs.find(t_attr_name) != m_attrs.end(); }
Boxed_Value &get_attr(const std::string &t_attr_name) { return m_attrs[t_attr_name]; }
Boxed_Value &method_missing(const std::string &t_method_name) {
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name);
}
Dynamic_Object() = default;
return get_attr(t_method_name);
}
bool is_explicit() const
{
return m_option_explicit;
const Boxed_Value &method_missing(const std::string &t_method_name) const {
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name);
}
void set_explicit(const bool t_explicit)
{
m_option_explicit = t_explicit;
}
return get_attr(t_method_name);
}
std::string get_type_name() const
{
return m_type_name;
}
std::map<std::string, Boxed_Value> get_attrs() const { return m_attrs; }
const Boxed_Value &operator[](const std::string &t_attr_name) const
{
return get_attr(t_attr_name);
}
private:
const std::string m_type_name = "";
bool m_option_explicit = false;
Boxed_Value &operator[](const std::string &t_attr_name)
{
return get_attr(t_attr_name);
}
const Boxed_Value &get_attr(const std::string &t_attr_name) const
{
auto a = m_attrs.find(t_attr_name);
if (a != m_attrs.end()) {
return a->second;
} else {
throw std::range_error("Attr not found '" + t_attr_name + "' and cannot be added to const obj");
}
}
bool has_attr(const std::string &t_attr_name) const {
return m_attrs.find(t_attr_name) != m_attrs.end();
}
Boxed_Value &get_attr(const std::string &t_attr_name)
{
return m_attrs[t_attr_name];
}
Boxed_Value &method_missing(const std::string &t_method_name)
{
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name);
}
return get_attr(t_method_name);
}
const Boxed_Value &method_missing(const std::string &t_method_name) const
{
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name);
}
return get_attr(t_method_name);
}
std::map<std::string, Boxed_Value> get_attrs() const
{
return m_attrs;
}
private:
const std::string m_type_name = "";
bool m_option_explicit = false;
std::map<std::string, Boxed_Value> m_attrs;
std::map<std::string, Boxed_Value> m_attrs;
};
}
}
} // namespace dispatch
} // namespace chaiscript
#endif

View File

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

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
@ -17,39 +16,28 @@
#include "boxed_cast.hpp"
namespace chaiscript {
class Boxed_Value;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript
{
namespace detail
{
struct Exception_Handler_Base
{
namespace detail {
struct Exception_Handler_Base {
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
virtual ~Exception_Handler_Base() = default;
protected:
template<typename T>
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
protected:
template<typename T>
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) {
try {
T t = t_engine.boxed_cast<T>(bv);
throw t;
} catch (const chaiscript::exception::bad_boxed_cast &) {
}
}
};
template<typename ... T>
struct Exception_Handler_Impl : Exception_Handler_Base
{
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override
{
(void)std::initializer_list<int>{(throw_type<T>(bv, t_engine), 0)...};
}
};
}
template<typename... T>
struct Exception_Handler_Impl : Exception_Handler_Base {
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override { (throw_type<T>(bv, t_engine), ...); }
};
} // namespace detail
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
///
@ -61,7 +49,8 @@ namespace chaiscript
/// chaiscript::ChaiScript chai;
///
/// try {
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const
/// std::exception &>());
/// } catch (const double e) {
/// } catch (int) {
/// } catch (float) {
@ -86,7 +75,7 @@ namespace chaiscript
///
/// Similarly, if you are using the ChaiScript::eval form that unboxes the return value, then chaiscript::exception::bad_boxed_cast
/// should be handled as well.
///
///
/// \code
/// try {
/// chai.eval<int>("1.0", chaiscript::exception_specification<const std::exception &>());
@ -101,17 +90,14 @@ namespace chaiscript
///
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
/// \sa \ref exceptions
typedef std::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
using Exception_Handler = std::shared_ptr<detail::Exception_Handler_Base>;
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
/// \sa \ref exceptions
template<typename ... T>
Exception_Handler exception_specification()
{
template<typename... T>
Exception_Handler exception_specification() {
return std::make_shared<detail::Exception_Handler_Impl<T...>>();
}
}
} // namespace chaiscript
#endif

View File

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

View File

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

View File

@ -0,0 +1,67 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_PARAMS_HPP
#define CHAISCRIPT_FUNCTION_PARAMS_HPP
#include "boxed_value.hpp"
namespace chaiscript {
class Function_Params {
public:
constexpr Function_Params(const Boxed_Value *const t_begin, const Boxed_Value *const t_end)
: m_begin(t_begin)
, m_end(t_end) {
}
explicit Function_Params(const Boxed_Value &bv)
: m_begin(&bv)
, m_end(m_begin + 1) {
}
explicit Function_Params(const std::vector<Boxed_Value> &vec)
: m_begin(vec.empty() ? nullptr : &vec.front())
, m_end(vec.empty() ? nullptr : &vec.front() + vec.size()) {
}
template<size_t Size>
constexpr explicit Function_Params(const std::array<Boxed_Value, Size> &a)
: m_begin(&a.front())
, m_end(&a.front() + Size) {
}
[[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { return m_begin[t_i]; }
[[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { return m_begin; }
[[nodiscard]] constexpr const Boxed_Value &front() const noexcept { return *m_begin; }
[[nodiscard]] constexpr const Boxed_Value *end() const noexcept { return m_end; }
[[nodiscard]] constexpr std::size_t size() const noexcept { return std::size_t(m_end - m_begin); }
[[nodiscard]] std::vector<Boxed_Value> to_vector() const { return std::vector<Boxed_Value>{m_begin, m_end}; }
[[nodiscard]] constexpr bool empty() const noexcept { return m_begin == m_end; }
private:
const Boxed_Value *m_begin = nullptr;
const Boxed_Value *m_end = nullptr;
};
// Constructor specialization for array of size 0
template<>
constexpr Function_Params::Function_Params(const std::array<Boxed_Value, size_t{0}> & /* a */)
: m_begin(nullptr)
, m_end(nullptr) {
}
} // namespace chaiscript
#endif

View File

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

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
#define CHAISCRIPT_HANDLE_RETURN_HPP_
@ -19,238 +18,178 @@
#include "boxed_value.hpp"
namespace chaiscript {
class Boxed_Number;
} // namespace chaiscript
class Boxed_Number;
} // namespace chaiscript
namespace chaiscript
{
namespace dispatch
{
template<class T, class U> class Proxy_Function_Callable_Impl;
template<class T> class Assignable_Proxy_Function_Impl;
namespace chaiscript {
namespace dispatch {
template<class T, class U>
class Proxy_Function_Callable_Impl;
template<class T>
class Assignable_Proxy_Function_Impl;
namespace detail
{
namespace detail {
/// Used internally for handling a return value from a Proxy_Function call
template<typename Ret>
struct Handle_Return
{
template<typename T,
typename = typename std::enable_if<std::is_pod<typename std::decay<T>::type>::value>::type>
static Boxed_Value handle(T r)
{
return Boxed_Value(std::move(r), true);
}
struct Handle_Return {
template<typename T, typename = typename std::enable_if_t<std::is_trivial_v<typename std::decay_t<T>>>>
static Boxed_Value handle(T r) {
return Boxed_Value(std::move(r), true);
}
template<typename T,
typename = typename std::enable_if<!std::is_pod<typename std::decay<T>::type>::value>::type>
static Boxed_Value handle(T &&r)
{
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
}
};
template<typename T, typename = typename std::enable_if_t<!(std::is_trivial_v<typename std::decay_t<T>>)>>
static Boxed_Value handle(T &&r) {
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
}
};
template<typename Ret>
struct Handle_Return<const std::function<Ret> &>
{
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
);
}
};
struct Handle_Return<const std::function<Ret> &> {
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
}
};
template<typename Ret>
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &>
{
};
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &> {
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>>>
{
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
);
}
};
struct Handle_Return<const std::shared_ptr<std::function<Ret>>> {
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f), f));
}
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>>
{
};
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>>
{
};
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
};
template<typename Ret>
struct Handle_Return<std::function<Ret> &>
{
static Boxed_Value handle(std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(f),
std::shared_ptr<std::function<Ret>>())
);
}
struct Handle_Return<std::function<Ret> &> {
static Boxed_Value handle(std::function<Ret> &f) {
return Boxed_Value(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(
std::ref(f), std::shared_ptr<std::function<Ret>>()));
}
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
);
}
};
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
}
};
template<typename Ret>
struct Handle_Return<Ret *&>
{
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
};
struct Handle_Return<Ret *&> {
static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
struct Handle_Return<const Ret *&>
{
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
};
struct Handle_Return<const Ret *&> {
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
struct Handle_Return<Ret *>
{
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
};
struct Handle_Return<Ret *> {
static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
struct Handle_Return<const Ret *>
{
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
};
struct Handle_Return<const Ret *> {
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &>
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
};
struct Handle_Return<std::shared_ptr<Ret> &> {
static Boxed_Value handle(const std::shared_ptr<Ret> &r) { return Boxed_Value(r, true); }
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &>
{
};
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> {
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &>
{
};
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &> {
};
template<typename Ret>
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &>
{
static Boxed_Value handle(std::unique_ptr<Ret> &&r)
{
return Boxed_Value(std::move(r), true);
}
};
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &> {
static Boxed_Value handle(std::unique_ptr<Ret> &&r) { return Boxed_Value(std::move(r), true); }
};
template<typename Ret, bool Ptr>
struct Handle_Return_Ref {
template<typename T>
static Boxed_Value handle(T &&r) {
return Boxed_Value(std::cref(r), true);
}
};
template<typename Ret>
struct Handle_Return<const Ret &>
{
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r), true);
}
};
struct Handle_Return_Ref<Ret, true> {
template<typename T>
static Boxed_Value handle(T &&r) {
return Boxed_Value(typename std::remove_reference<decltype(r)>::type{r}, true);
}
};
template<typename Ret>
struct Handle_Return<const Ret>
{
static Boxed_Value handle(Ret r)
{
return Boxed_Value(std::move(r));
}
};
struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> {
};
template<typename Ret>
struct Handle_Return<Ret &>
{
static Boxed_Value handle(Ret &r)
{
return Boxed_Value(std::ref(r));
}
};
struct Handle_Return<const Ret> {
static Boxed_Value handle(Ret r) { return Boxed_Value(std::move(r)); }
};
template<typename Ret>
struct Handle_Return<Ret &> {
static Boxed_Value handle(Ret &r) { return Boxed_Value(std::ref(r)); }
};
template<>
struct Handle_Return<Boxed_Value>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
struct Handle_Return<Boxed_Value> {
static Boxed_Value handle(const Boxed_Value &r) noexcept { return r; }
};
template<>
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value>
{
};
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> {
};
template<>
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value>
{
};
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> {
};
template<>
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value>
{
};
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value> {
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
};
struct Handle_Return<Boxed_Number> {
static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; }
};
template<>
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number>
{
};
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number> {
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<void>
{
static Boxed_Value handle()
{
return void_var();
}
};
}
}
}
struct Handle_Return<void> {
static Boxed_Value handle() { return void_var(); }
};
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
#endif

View File

@ -1,224 +1,184 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_OPERATORS_HPP_
#define CHAISCRIPT_OPERATORS_HPP_
#include "../chaiscript_defines.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "register_function.hpp"
namespace chaiscript
{
namespace bootstrap
{
namespace operators
{
template<typename T>
void assign(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "=");
}
template<typename T>
void assign_bitwise_and(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&=");
}
template<typename T>
void assign_xor(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^=");
}
template<typename T>
void assign_bitwise_or(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|=");
}
template<typename T>
void assign_difference(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-=");
}
template<typename T>
void assign_left_shift(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<=");
}
template<typename T>
void assign_product(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*=");
}
template<typename T>
void assign_quotient(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/=");
}
template<typename T>
void assign_remainder(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%=");
}
template<typename T>
void assign_right_shift(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>=");
}
template<typename T>
void assign_sum(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+=");
}
template<typename T>
void prefix_decrement(Module& m)
{
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--");
}
template<typename T>
void prefix_increment(Module& m)
{
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++");
}
template<typename T>
void equal(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "==");
}
template<typename T>
void greater_than(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">");
}
template<typename T>
void greater_than_equal(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">=");
}
template<typename T>
void less_than(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<");
}
template<typename T>
void less_than_equal(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<=");
}
template<typename T>
void logical_compliment(Module& m)
{
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!");
}
template<typename T>
void not_equal(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!=");
}
template<typename T>
void addition(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+");
}
template<typename T>
void unary_plus(Module& m)
{
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+");
}
template<typename T>
void subtraction(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-");
}
template<typename T>
void unary_minus(Module& m)
{
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-");
}
template<typename T>
void bitwise_and(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&");
}
template<typename T>
void bitwise_compliment(Module& m)
{
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~");
}
template<typename T>
void bitwise_xor(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^");
}
template<typename T>
void bitwise_or(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|");
}
template<typename T>
void division(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/");
}
template<typename T>
void left_shift(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<");
}
template<typename T>
void multiplication(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*");
}
template<typename T>
void remainder(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%");
}
template<typename T>
void right_shift(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>");
}
}
namespace chaiscript::bootstrap::operators {
template<typename T>
void assign(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs = rhs; }), "=");
}
}
template<typename T>
void assign_bitwise_and(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs &= rhs; }), "&=");
}
template<typename T>
void assign_xor(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs ^= rhs; }), "^=");
}
template<typename T>
void assign_bitwise_or(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs |= rhs; }), "|=");
}
template<typename T>
void assign_difference(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs -= rhs; }), "-=");
}
template<typename T>
void assign_left_shift(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "<<=");
}
template<typename T>
void assign_product(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "*=");
}
template<typename T>
void assign_quotient(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs /= rhs; }), "/=");
}
template<typename T>
void assign_remainder(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs %= rhs; }), "%=");
}
template<typename T>
void assign_right_shift(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs >>= rhs; }), ">>=");
}
template<typename T>
void assign_sum(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs += rhs; }), "+=");
}
template<typename T>
void prefix_decrement(Module &m) {
m.add(chaiscript::fun([](T &lhs) -> T & { return --lhs; }), "--");
}
template<typename T>
void prefix_increment(Module &m) {
m.add(chaiscript::fun([](T &lhs) -> T & { return ++lhs; }), "++");
}
template<typename T>
void equal(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs == rhs; }), "==");
}
template<typename T>
void greater_than(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs > rhs; }), ">");
}
template<typename T>
void greater_than_equal(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >= rhs; }), ">=");
}
template<typename T>
void less_than(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs < rhs; }), "<");
}
template<typename T>
void less_than_equal(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs <= rhs; }), "<=");
}
template<typename T>
void logical_compliment(Module &m) {
m.add(chaiscript::fun([](const T &lhs) { return !lhs; }), "!");
}
template<typename T>
void not_equal(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs != rhs; }), "!=");
}
template<typename T>
void addition(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs + rhs; }), "+");
}
template<typename T>
void unary_plus(Module &m) {
m.add(chaiscript::fun([](const T &lhs) { return +lhs; }), "+");
}
template<typename T>
void subtraction(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs - rhs; }), "-");
}
template<typename T>
void unary_minus(Module &m) {
m.add(chaiscript::fun([](const T &lhs) { return -lhs; }), "-");
}
template<typename T>
void bitwise_and(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs & rhs; }), "&");
}
template<typename T>
void bitwise_compliment(Module &m) {
m.add(chaiscript::fun([](const T &lhs) { return ~lhs; }), "~");
}
template<typename T>
void bitwise_xor(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs ^ rhs; }), "^");
}
template<typename T>
void bitwise_or(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs | rhs; }), "|");
}
template<typename T>
void division(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs / rhs; }), "/");
}
template<typename T>
void left_shift(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs << rhs; }), "<<");
}
template<typename T>
void multiplication(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs * rhs; }), "*");
}
template<typename T>
void remainder(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs % rhs; }), "%");
}
template<typename T>
void right_shift(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >> rhs; }), ">>");
}
} // namespace chaiscript::bootstrap::operators
#endif

View File

@ -1,41 +1,41 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include "proxy_functions.hpp"
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
namespace chaiscript::dispatch::detail {
template<typename Class, typename... Params>
Proxy_Function build_constructor_(Class (*)(Params...)) {
if constexpr (!std::is_copy_constructible_v<Class>) {
auto call = [](auto &&...param) { return std::make_shared<Class>(std::forward<decltype(param)>(param)...); };
template<typename Class, typename ... Params >
Proxy_Function build_constructor_(Class (*)(Params...))
{
auto call = dispatch::detail::Constructor<Class, Params...>();
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base,
dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class>(Params...), decltype(call)>>(call));
} else if constexpr (true) {
auto call = [](auto &&...param) { return Class(std::forward<decltype(param)>(param)...); };
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
}
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Class(Params...), decltype(call)>>(
call));
}
}
} // namespace chaiscript::dispatch::detail
namespace chaiscript {
/// \brief Generates a constructor function for use with ChaiScript
///
///
/// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
///
///
/// Example:
/// \code
/// chaiscript::ChaiScript chai;
@ -44,13 +44,10 @@ namespace chaiscript
/// chai.add(constructor<MyClass (int, float)>(), "MyClass");
/// \endcode
template<typename T>
Proxy_Function constructor()
{
T *f = nullptr;
return (dispatch::detail::build_constructor_(f));
}
}
Proxy_Function constructor() {
T *f = nullptr;
return (dispatch::detail::build_constructor_(f));
}
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,49 +1,45 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#include <array>
#include <functional>
#include <stdexcept>
#include <vector>
#include <array>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_value.hpp"
#include "function_params.hpp"
#include "handle_return.hpp"
#include "type_info.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Type_Conversions_State;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
class Type_Conversions_State;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript
{
namespace exception
{
namespace chaiscript {
namespace exception {
/**
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error
{
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error {
arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"),
got(t_got), expected(t_expected)
{
: std::range_error("Function dispatch arity mismatch")
, got(t_got)
, expected(t_expected) {
}
arity_error(const arity_error &) = default;
@ -53,87 +49,63 @@ namespace chaiscript
int got;
int expected;
};
}
} // namespace exception
namespace dispatch
{
namespace detail
{
namespace dispatch {
namespace detail {
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret, typename ... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
{
/// \note somehow this is responsible for a large part of the code generation
return { user_type<Ret>(), user_type<Params>()... };
}
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret, typename... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) {
/// \note somehow this is responsible for a large part of the code generation
return {user_type<Ret>(), user_type<Params>()...};
}
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
try {
std::vector<Boxed_Value>::size_type i = 0;
(void)i;
(void)params; (void)t_conversions;
// this is ok because the order of evaluation of initializer lists is well defined
(void)std::initializer_list<int>{(boxed_cast<Params>(params[i++], &t_conversions), 0)...};
return true;
} catch (const exception::bad_boxed_cast &) {
return false;
}
}
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &,
std::index_sequence<I...>, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
(void)params; (void)t_conversions;
return f(boxed_cast<Params>(params[I], &t_conversions)...);
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret, typename... Params>
bool compare_types_cast(Ret (*)(Params...), const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) noexcept {
try {
std::vector<Boxed_Value>::size_type i = 0;
(boxed_cast<Params>(params[i++], &t_conversions), ...);
return true;
} catch (const exception::bad_boxed_cast &) {
return false;
}
}
template<typename Callable, typename Ret, typename... Params, size_t... I>
Ret call_func(Ret (*)(Params...),
std::index_sequence<I...>,
const Callable &f,
[[maybe_unused]] const chaiscript::Function_Params &params,
[[maybe_unused]] const Type_Conversions_State &t_conversions) {
return f(boxed_cast<Params>(params[I], &t_conversions)...);
}
/// Used by Proxy_Function_Impl to perform typesafe execution of a function.
/// The function attempts to unbox each parameter to the expected type.
/// if any unboxing fails the execution of the function fails and
/// the bad_boxed_cast is passed up to the caller.
template<typename Callable, typename Ret, typename ... Params>
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
template<typename Callable, typename Ret, typename... Params>
Boxed_Value
call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) {
if constexpr (std::is_same_v<Ret, void>) {
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
return Handle_Return<void>::handle();
} else {
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
}
}
template<typename Callable, typename ... Params>
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<void (Params...)> &sig, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4702)
#endif
// MSVC is reporting that this is unreachable code - and it's wrong.
return Handle_Return<void>::handle();
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
}
}
}
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
#endif

View File

@ -1,23 +1,61 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
#include <type_traits>
#include "bind_first.hpp"
#include "function_signature.hpp"
#include "proxy_functions.hpp"
namespace chaiscript
{
namespace chaiscript {
namespace dispatch::detail {
template<typename Obj, typename Param1, typename... Rest>
Param1 get_first_param(Function_Params<Param1, Rest...>, Obj &&obj) {
return static_cast<Param1>(std::forward<Obj>(obj));
}
template<typename Func, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject, bool Is_Object, typename Ret, typename... Param>
auto make_callable_impl(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) {
if constexpr (Is_MemberObject) {
// we now that the Param pack will have only one element, so we are safe expanding it here
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<Ret, std::decay_t<Param>...>>(
std::forward<Func>(func)));
} else if constexpr (Is_Member) {
// TODO some kind of bug is preventing forwarding of this noexcept for the lambda
auto call = [func = std::forward<Func>(func)](auto &&obj, auto &&...param) /* noexcept(Is_Noexcept) */ -> decltype(auto) {
return ((get_first_param(Function_Params<Param...>{}, obj).*func)(std::forward<decltype(param)>(param)...));
};
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), decltype(call)>>(
std::move(call)));
} else {
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), std::decay_t<Func>>>(
std::forward<Func>(func)));
}
}
// this version peels off the function object itself from the function signature, when used
// on a callable object
template<typename Func, typename Ret, typename Object, typename... Param, bool Is_Noexcept>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Object, Param...>, Is_Noexcept, false, false, true>) {
return make_callable_impl(std::forward<Func>(func), Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, false, false, true>{});
}
template<typename Func, typename Ret, typename... Param, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) {
return make_callable_impl(std::forward<Func>(func), fs);
}
} // namespace dispatch::detail
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
/// \param[in] t Function / member to expose
@ -31,95 +69,19 @@ namespace chaiscript
/// void memberfunction();
/// int memberdata;
/// };
///
///
/// chaiscript::ChaiScript chai;
/// chai.add(fun(&myfunction), "myfunction");
/// chai.add(fun(&MyClass::memberfunction), "memberfunction");
/// chai.add(fun(&MyClass::memberdata), "memberdata");
/// \endcode
///
///
/// \sa \ref adding_functions
template<typename T>
Proxy_Function fun(const T &t)
{
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
Proxy_Function fun(T &&t) {
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t));
}
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
}
template<typename Ret, typename ... Param>
Proxy_Function fun(Ret (*func)(Param...))
{
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...) const)
{
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...))
{
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
}
template<typename T, typename Class /*, typename = typename std::enable_if<std::is_member_object_pointer<T>::value>::type*/>
Proxy_Function fun(T Class::* m /*, typename std::enable_if<std::is_member_object_pointer<T>::value>::type* = 0*/ )
{
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<T, Class>>(m));
}
// only compile this bit if noexcept is part of the type system
//
#if (defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510) || (defined(_NOEXCEPT_TYPES_SUPPORTED) && _MSC_VER >= 1912)
template<typename Ret, typename ... Param>
Proxy_Function fun(Ret (*func)(Param...) noexcept)
{
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...) const noexcept)
{
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...) noexcept)
{
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
}
#endif
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
/// \param[in] t Function / member to expose
/// \param[in] q Value to bind to first parameter
@ -130,23 +92,19 @@ namespace chaiscript
/// {
/// void memberfunction(int);
/// };
///
///
/// MyClass obj;
/// chaiscript::ChaiScript chai;
/// // Add function taking only one argument, an int, and permanently bound to "obj"
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
/// \endcode
///
///
/// \sa \ref adding_functions
template<typename T, typename Q>
Proxy_Function fun(T &&t, const Q &q)
{
return fun(detail::bind_first(std::forward<T>(t), q));
}
}
Proxy_Function fun(T &&t, const Q &q) {
return fun(detail::bind_first(std::forward<T>(t), q));
}
} // namespace chaiscript
#endif

View File

@ -2,19 +2,19 @@
#define SHORT_ALLOC_H
// The MIT License (MIT)
//
//
// Copyright (c) 2015 Howard Hinnant
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -23,137 +23,115 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <cstddef>
#include <cassert>
#include <cstddef>
template <std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
class arena
{
alignas(alignment) char buf_[N];
char* ptr_;
template<std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
class arena {
alignas(alignment) char buf_[N];
char *ptr_;
public:
~arena() {ptr_ = nullptr;}
arena() noexcept : ptr_(buf_) {}
arena(const arena&) = delete;
arena& operator=(const arena&) = delete;
~arena() { ptr_ = nullptr; }
arena() noexcept
: ptr_(buf_) {
}
arena(const arena &) = delete;
arena &operator=(const arena &) = delete;
template <std::size_t ReqAlign> char* allocate(std::size_t n);
void deallocate(char* p, std::size_t n) noexcept;
template<std::size_t ReqAlign>
char *allocate(std::size_t n);
void deallocate(char *p, std::size_t n) noexcept;
static constexpr std::size_t size() noexcept {return N;}
std::size_t used() const noexcept {return static_cast<std::size_t>(ptr_ - buf_);}
void reset() noexcept {ptr_ = buf_;}
static constexpr std::size_t size() noexcept { return N; }
std::size_t used() const noexcept { return static_cast<std::size_t>(ptr_ - buf_); }
void reset() noexcept { ptr_ = buf_; }
private:
static
std::size_t
align_up(std::size_t n) noexcept
{return (n + (alignment-1)) & ~(alignment-1);}
static std::size_t align_up(std::size_t n) noexcept { return (n + (alignment - 1)) & ~(alignment - 1); }
bool
pointer_in_buffer(char* p) noexcept
{return buf_ <= p && p <= buf_ + N;}
bool pointer_in_buffer(char *p) noexcept { return buf_ <= p && p <= buf_ + N; }
};
template <std::size_t N, std::size_t alignment>
template <std::size_t ReqAlign>
char*
arena<N, alignment>::allocate(std::size_t n)
{
static_assert(ReqAlign <= alignment, "alignment is too small for this arena");
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
auto const aligned_n = align_up(n);
if (static_cast<decltype(aligned_n)>(buf_ + N - ptr_) >= aligned_n)
{
char* r = ptr_;
ptr_ += aligned_n;
return r;
}
template<std::size_t N, std::size_t alignment>
template<std::size_t ReqAlign>
char *arena<N, alignment>::allocate(std::size_t n) {
static_assert(ReqAlign <= alignment, "alignment is too small for this arena");
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
auto const aligned_n = align_up(n);
if (static_cast<decltype(aligned_n)>(buf_ + N - ptr_) >= aligned_n) {
char *r = ptr_;
ptr_ += aligned_n;
return r;
}
static_assert(alignment <= alignof(std::max_align_t), "you've chosen an "
"alignment that is larger than alignof(std::max_align_t), and "
"cannot be guaranteed by normal operator new");
return static_cast<char*>(::operator new(n));
static_assert(alignment <= alignof(std::max_align_t),
"you've chosen an "
"alignment that is larger than alignof(std::max_align_t), and "
"cannot be guaranteed by normal operator new");
return static_cast<char *>(::operator new(n));
}
template <std::size_t N, std::size_t alignment>
void
arena<N, alignment>::deallocate(char* p, std::size_t n) noexcept
{
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
if (pointer_in_buffer(p))
{
n = align_up(n);
if (p + n == ptr_) {
ptr_ = p;
}
}
else {
::operator delete(p);
template<std::size_t N, std::size_t alignment>
void arena<N, alignment>::deallocate(char *p, std::size_t n) noexcept {
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
if (pointer_in_buffer(p)) {
n = align_up(n);
if (p + n == ptr_) {
ptr_ = p;
}
} else {
::operator delete(p);
}
}
template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
class short_alloc
{
template<class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
class short_alloc {
public:
using value_type = T;
static auto constexpr alignment = Align;
static auto constexpr size = N;
using arena_type = arena<size, alignment>;
using value_type = T;
static auto constexpr alignment = Align;
static auto constexpr size = N;
using arena_type = arena<size, alignment>;
private:
arena_type& a_;
arena_type &a_;
public:
short_alloc(const short_alloc&) = default;
short_alloc& operator=(const short_alloc&) = delete;
short_alloc(const short_alloc &) = default;
short_alloc &operator=(const short_alloc &) = delete;
explicit short_alloc(arena_type& a) noexcept : a_(a)
{
static_assert(size % alignment == 0,
"size N needs to be a multiple of alignment Align");
}
template <class U>
explicit short_alloc(const short_alloc<U, N, alignment>& a) noexcept
: a_(a.a_) {}
explicit short_alloc(arena_type &a) noexcept
: a_(a) {
static_assert(size % alignment == 0, "size N needs to be a multiple of alignment Align");
}
template<class U>
explicit short_alloc(const short_alloc<U, N, alignment> &a) noexcept
: a_(a.a_) {
}
template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;};
template<class _Up>
struct rebind {
using other = short_alloc<_Up, N, alignment>;
};
T* allocate(std::size_t n)
{
return reinterpret_cast<T*>(a_.template allocate<alignof(T)>(n*sizeof(T)));
}
void deallocate(T* p, std::size_t n) noexcept
{
a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
}
T *allocate(std::size_t n) { return reinterpret_cast<T *>(a_.template allocate<alignof(T)>(n * sizeof(T))); }
void deallocate(T *p, std::size_t n) noexcept { a_.deallocate(reinterpret_cast<char *>(p), n * sizeof(T)); }
template <class T1, std::size_t N1, std::size_t A1,
class U, std::size_t M, std::size_t A2>
friend
bool
operator==(const short_alloc<T1, N1, A1>& x, const short_alloc<U, M, A2>& y) noexcept;
template<class T1, std::size_t N1, std::size_t A1, class U, std::size_t M, std::size_t A2>
friend bool operator==(const short_alloc<T1, N1, A1> &x, const short_alloc<U, M, A2> &y) noexcept;
template <class U, std::size_t M, std::size_t A> friend class short_alloc;
template<class U, std::size_t M, std::size_t A>
friend class short_alloc;
};
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline
bool
operator==(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
{
return N == M && A1 == A2 && &x.a_ == &y.a_;
template<class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline bool operator==(const short_alloc<T, N, A1> &x, const short_alloc<U, M, A2> &y) noexcept {
return N == M && A1 == A2 && &x.a_ == &y.a_;
}
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline
bool
operator!=(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
{
return !(x == y);
template<class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline bool operator!=(const short_alloc<T, N, A1> &x, const short_alloc<U, M, A2> &y) noexcept {
return !(x == y);
}
#endif // SHORT_ALLOC_HPP
#endif // SHORT_ALLOC_HPP

File diff suppressed because it is too large Load Diff

View File

@ -1,244 +1,210 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
#define CHAISCRIPT_TYPE_INFO_HPP_
#include <memory>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <string>
namespace chaiscript
{
namespace detail
{
namespace chaiscript {
namespace detail {
template<typename T>
struct Bare_Type
{
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
};
}
struct Bare_Type {
using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type;
};
} // namespace detail
/// \brief Compile time deduced information about a type
class Type_Info
{
public:
constexpr Type_Info(const bool t_is_const, const bool t_is_reference, const bool t_is_pointer, const bool t_is_void,
const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag)
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag)
+ (static_cast<unsigned int>(t_is_void) << is_void_flag)
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag))
{
class Type_Info {
public:
constexpr Type_Info(const bool t_is_const,
const bool t_is_reference,
const bool t_is_pointer,
const bool t_is_void,
const bool t_is_arithmetic,
const std::type_info *t_ti,
const std::type_info *t_bare_ti) noexcept
: m_type_info(t_ti)
, m_bare_type_info(t_bare_ti)
, m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag) + (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag) + (static_cast<unsigned int>(t_is_void) << is_void_flag)
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag)) {
}
constexpr Type_Info() noexcept = default;
bool operator<(const Type_Info &ti) const noexcept { return m_type_info->before(*ti.m_type_info); }
constexpr bool operator!=(const Type_Info &ti) const noexcept { return !(operator==(ti)); }
constexpr bool operator!=(const std::type_info &ti) const noexcept { return !(operator==(ti)); }
constexpr bool operator==(const Type_Info &ti) const noexcept {
return ti.m_type_info == m_type_info || *ti.m_type_info == *m_type_info;
}
constexpr bool operator==(const std::type_info &ti) const noexcept { return !is_undef() && (*m_type_info) == ti; }
constexpr bool bare_equal(const Type_Info &ti) const noexcept {
return ti.m_bare_type_info == m_bare_type_info || *ti.m_bare_type_info == *m_bare_type_info;
}
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept { return !is_undef() && (*m_bare_type_info) == ti; }
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; }
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; }
constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; }
constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; }
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; }
const char *name() const noexcept {
if (!is_undef()) {
return m_type_info->name();
} else {
return "";
}
}
constexpr Type_Info() = default;
bool operator<(const Type_Info &ti) const noexcept
{
return m_type_info->before(*ti.m_type_info);
const char *bare_name() const noexcept {
if (!is_undef()) {
return m_bare_type_info->name();
} else {
return "";
}
}
constexpr bool operator!=(const Type_Info &ti) const noexcept
{
return !(operator==(ti));
}
constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; }
constexpr bool operator!=(const std::type_info &ti) const noexcept
{
return !(operator==(ti));
}
private:
struct Unknown_Type {
};
constexpr bool operator==(const Type_Info &ti) const noexcept
{
return ti.m_type_info == m_type_info
|| *ti.m_type_info == *m_type_info;
}
constexpr bool operator==(const std::type_info &ti) const noexcept
{
return !is_undef() && (*m_type_info) == ti;
}
constexpr bool bare_equal(const Type_Info &ti) const noexcept
{
return ti.m_bare_type_info == m_bare_type_info
|| *ti.m_bare_type_info == *m_bare_type_info;
}
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept
{
return !is_undef() && (*m_bare_type_info) == ti;
}
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; }
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; }
constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; }
constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; }
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; }
std::string name() const
{
if (!is_undef())
{
return m_type_info->name();
} else {
return "";
}
}
std::string bare_name() const
{
if (!is_undef())
{
return m_bare_type_info->name();
} else {
return "";
}
}
constexpr const std::type_info *bare_type_info() const
{
return m_bare_type_info;
}
private:
struct Unknown_Type {};
const std::type_info *m_type_info = &typeid(Unknown_Type);
const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
static const int is_const_flag = 0;
static const int is_reference_flag = 1;
static const int is_pointer_flag = 2;
static const int is_void_flag = 3;
static const int is_arithmetic_flag = 4;
static const int is_undef_flag = 5;
unsigned int m_flags = (1 << is_undef_flag);
const std::type_info *m_type_info = &typeid(Unknown_Type);
const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
static const int is_const_flag = 0;
static const int is_reference_flag = 1;
static const int is_pointer_flag = 2;
static const int is_void_flag = 3;
static const int is_arithmetic_flag = 4;
static const int is_undef_flag = 5;
unsigned int m_flags = (1 << is_undef_flag);
};
namespace detail
{
namespace detail {
/// Helper used to create a Type_Info object
template<typename T>
struct Get_Type_Info
{
static constexpr Type_Info get()
{
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(T),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info {
constexpr static Type_Info get() noexcept {
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
std::is_reference<T>::value,
std::is_pointer<T>::value,
std::is_void<T>::value,
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(T),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::shared_ptr<T> >
{
// typedef T type;
static constexpr Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::shared_ptr<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info<std::shared_ptr<T>> {
constexpr static Type_Info get() noexcept {
return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::shared_ptr<T>),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>>
{
};
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>> {
};
template<typename T>
struct Get_Type_Info<const std::shared_ptr<T> &>
{
static constexpr Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info<const std::shared_ptr<T> &> {
constexpr static Type_Info get() noexcept {
return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> >
{
static constexpr Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::reference_wrapper<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info<std::reference_wrapper<T>> {
constexpr static Type_Info get() noexcept {
return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::reference_wrapper<T>),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &>
{
static constexpr Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info<const std::reference_wrapper<T> &> {
constexpr static Type_Info get() noexcept {
return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
}
} // namespace detail
/// \brief Creates a Type_Info object representing the type passed in
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
/// \return Type_Info for T
///
///
/// \b Example:
/// \code
/// int i;
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
/// \endcode
template<typename T>
constexpr Type_Info user_type(const T &/*t*/)
{
constexpr Type_Info user_type(const T & /*t*/) noexcept {
return detail::Get_Type_Info<T>::get();
}
/// \brief Creates a Type_Info object representing the templated type
/// \tparam T Type of object to get a Type_Info for
/// \return Type_Info for T
///
///
/// \b Example:
/// \code
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
/// \endcode
template<typename T>
constexpr Type_Info user_type()
{
constexpr Type_Info user_type() noexcept {
return detail::Get_Type_Info<T>::get();
}
}
} // namespace chaiscript
#endif

View File

@ -1,108 +1,167 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_
#include "../utility/fnv1a.hpp"
#include "../utility/hash.hpp"
#include <string>
namespace chaiscript
{
namespace chaiscript {
struct Operators {
enum class Opers
{
boolean_flag,
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
non_const_flag,
assign, pre_increment, pre_decrement, assign_product, assign_sum,
assign_quotient, assign_difference,
non_const_int_flag,
assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right,
assign_remainder, assign_bitwise_xor,
const_int_flag,
shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement,
const_flag,
sum, quotient, product, difference, unary_plus, unary_minus,
enum class Opers {
equals,
less_than,
greater_than,
less_than_equal,
greater_than_equal,
not_equal,
assign,
pre_increment,
pre_decrement,
assign_product,
assign_sum,
assign_quotient,
assign_difference,
assign_bitwise_and,
assign_bitwise_or,
assign_shift_left,
assign_shift_right,
assign_remainder,
assign_bitwise_xor,
shift_left,
shift_right,
remainder,
bitwise_and,
bitwise_or,
bitwise_xor,
bitwise_complement,
sum,
quotient,
product,
difference,
unary_plus,
unary_minus,
invalid
};
static const char *to_string(Opers t_oper) {
static const char *opers[] = {
"",
"==", "<", ">", "<=", ">=", "!=",
"",
"=", "++", "--", "*=", "+=",
"/=", "-=",
"",
"&=", "|=", "<<=", ">>=",
"%=", "^=",
"",
"<<", ">>", "%", "&", "|", "^", "~",
"",
"+", "/", "*", "-", "+", "-",
""
};
constexpr static const char *to_string(Opers t_oper) noexcept {
constexpr const char *opers[]
= {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""};
return opers[static_cast<int>(t_oper)];
}
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
{
constexpr static Opers to_operator(std::string_view t_str, bool t_is_unary = false) noexcept {
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
const auto op_hash = utility::fnv1a_32(t_str.c_str());
const auto op_hash = utility::hash(t_str);
switch (op_hash) {
case utility::fnv1a_32("=="): { return Opers::equals; }
case utility::fnv1a_32("<"): { return Opers::less_than; }
case utility::fnv1a_32(">"): { return Opers::greater_than; }
case utility::fnv1a_32("<="): { return Opers::less_than_equal; }
case utility::fnv1a_32(">="): { return Opers::greater_than_equal; }
case utility::fnv1a_32("!="): { return Opers::not_equal; }
case utility::fnv1a_32("="): { return Opers::assign; }
case utility::fnv1a_32("++"): { return Opers::pre_increment; }
case utility::fnv1a_32("--"): { return Opers::pre_decrement; }
case utility::fnv1a_32("*="): { return Opers::assign_product; }
case utility::fnv1a_32("+="): { return Opers::assign_sum; }
case utility::fnv1a_32("-="): { return Opers::assign_difference; }
case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; }
case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; }
case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; }
case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; }
case utility::fnv1a_32("%="): { return Opers::assign_remainder; }
case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; }
case utility::fnv1a_32("<<"): { return Opers::shift_left; }
case utility::fnv1a_32(">>"): { return Opers::shift_right; }
case utility::fnv1a_32("%"): { return Opers::remainder; }
case utility::fnv1a_32("&"): { return Opers::bitwise_and; }
case utility::fnv1a_32("|"): { return Opers::bitwise_or; }
case utility::fnv1a_32("^"): { return Opers::bitwise_xor; }
case utility::fnv1a_32("~"): { return Opers::bitwise_complement; }
case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; }
case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; }
case utility::fnv1a_32("/"): { return Opers::quotient; }
case utility::fnv1a_32("*"): { return Opers::product; }
default: { return Opers::invalid; }
case utility::hash("=="): {
return Opers::equals;
}
case utility::hash("<"): {
return Opers::less_than;
}
case utility::hash(">"): {
return Opers::greater_than;
}
case utility::hash("<="): {
return Opers::less_than_equal;
}
case utility::hash(">="): {
return Opers::greater_than_equal;
}
case utility::hash("!="): {
return Opers::not_equal;
}
case utility::hash("="): {
return Opers::assign;
}
case utility::hash("++"): {
return Opers::pre_increment;
}
case utility::hash("--"): {
return Opers::pre_decrement;
}
case utility::hash("*="): {
return Opers::assign_product;
}
case utility::hash("+="): {
return Opers::assign_sum;
}
case utility::hash("-="): {
return Opers::assign_difference;
}
case utility::hash("&="): {
return Opers::assign_bitwise_and;
}
case utility::hash("|="): {
return Opers::assign_bitwise_or;
}
case utility::hash("<<="): {
return Opers::assign_shift_left;
}
case utility::hash(">>="): {
return Opers::assign_shift_right;
}
case utility::hash("%="): {
return Opers::assign_remainder;
}
case utility::hash("^="): {
return Opers::assign_bitwise_xor;
}
case utility::hash("<<"): {
return Opers::shift_left;
}
case utility::hash(">>"): {
return Opers::shift_right;
}
case utility::hash("%"): {
return Opers::remainder;
}
case utility::hash("&"): {
return Opers::bitwise_and;
}
case utility::hash("|"): {
return Opers::bitwise_or;
}
case utility::hash("^"): {
return Opers::bitwise_xor;
}
case utility::hash("~"): {
return Opers::bitwise_complement;
}
case utility::hash("+"): {
return t_is_unary ? Opers::unary_plus : Opers::sum;
}
case utility::hash("-"): {
return t_is_unary ? Opers::unary_minus : Opers::difference;
}
case utility::hash("/"): {
return Opers::quotient;
}
case utility::hash("*"): {
return Opers::product;
}
default: {
return Opers::invalid;
}
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
};
}
} // namespace chaiscript
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,17 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ENGINE_HPP_
#define CHAISCRIPT_ENGINE_HPP_
#include <cassert>
#include <cstring>
#include <exception>
#include <fstream>
#include <functional>
@ -21,15 +21,15 @@
#include <set>
#include <stdexcept>
#include <vector>
#include <cstring>
#include "../chaiscript_defines.hpp"
#include "../chaiscript_threading.hpp"
#include "../dispatchkit/boxed_cast_helper.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "chaiscript_common.hpp"
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
@ -50,23 +50,18 @@
#include "chaiscript_unknown.hpp"
#endif
#include "../dispatchkit/exception_specification.hpp"
namespace chaiscript
{
/// Namespace alias to provide cleaner and more explicit syntax to users.
using Namespace = dispatch::Dynamic_Object;
namespace chaiscript {
/// Namespace alias to provide cleaner and more explicit syntax to users.
using Namespace = dispatch::Dynamic_Object;
namespace detail
{
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
namespace detail {
using Loadable_Module_Ptr = std::shared_ptr<Loadable_Module>;
}
/// \brief The main object that the ChaiScript user will use.
class ChaiScript_Basic {
mutable chaiscript::detail::threading::shared_mutex m_mutex;
mutable chaiscript::detail::threading::recursive_mutex m_use_mutex;
@ -81,26 +76,21 @@ namespace chaiscript
chaiscript::detail::Dispatch_Engine m_engine;
std::map<std::string, std::function<Namespace&()>> m_namespace_generators;
std::map<std::string, std::function<Namespace &()>> m_namespace_generators;
/// Evaluates the given string in by parsing it and running the results through the evaluator
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
{
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) {
try {
const auto p = m_parser->parse(t_input, t_filename);
return p->eval(chaiscript::detail::Dispatch_State(m_engine));
}
catch (chaiscript::eval::detail::Return_Value &rv) {
} catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval;
}
}
/// Evaluates the given file and looks in the 'use' paths
const Boxed_Value internal_eval_file(const std::string &t_filename) {
for (const auto &path : m_use_paths)
{
Boxed_Value internal_eval_file(const std::string &t_filename) {
for (const auto &path : m_use_paths) {
try {
const auto appendedpath = path + t_filename;
return do_eval(load_file(appendedpath), appendedpath, true);
@ -113,13 +103,10 @@ namespace chaiscript
// failed to load by any name
throw exception::file_not_found_error(t_filename);
}
/// Evaluates the given string, used during eval() inside of a script
const Boxed_Value internal_eval(const std::string &t_e) {
Boxed_Value internal_eval(const std::string &t_e) {
try {
return do_eval(t_e, "__EVAL__", true);
} catch (const exception::eval_error &t_ee) {
@ -128,107 +115,94 @@ namespace chaiscript
}
/// Returns the current evaluation m_engine
chaiscript::detail::Dispatch_Engine &get_eval_engine() {
return m_engine;
}
chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { return m_engine; }
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) {
if (t_lib)
{
if (t_lib) {
add(t_lib);
}
m_engine.add(fun([this](){ m_engine.dump_system(); }), "dump_system");
m_engine.add(fun([this](const Boxed_Value &t_bv){ m_engine.dump_object(t_bv); }), "dump_object");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type){ return m_engine.is_type(t_bv, t_type); }), "is_type");
m_engine.add(fun([this](const Boxed_Value &t_bv){ return m_engine.type_name(t_bv); }), "type_name");
m_engine.add(fun([this](const std::string &t_f){ return m_engine.function_exists(t_f); }), "function_exists");
m_engine.add(fun([this](){ return m_engine.get_function_objects(); }), "get_functions");
m_engine.add(fun([this](){ return m_engine.get_scripting_objects(); }), "get_objects");
m_engine.add(fun([this]() { m_engine.dump_system(); }), "dump_system");
m_engine.add(fun([this](const Boxed_Value &t_bv) { m_engine.dump_object(t_bv); }), "dump_object");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type) { return m_engine.is_type(t_bv, t_type); }), "is_type");
m_engine.add(fun([this](const Boxed_Value &t_bv) { return m_engine.type_name(t_bv); }), "type_name");
m_engine.add(fun([this](const std::string &t_f) { return m_engine.function_exists(t_f); }), "function_exists");
m_engine.add(fun([this]() { return m_engine.get_function_objects(); }), "get_functions");
m_engine.add(fun([this]() { return m_engine.get_scripting_objects(); }), "get_objects");
m_engine.add(
dispatch::make_dynamic_proxy_function(
[this](const std::vector<Boxed_Value> &t_params) {
return m_engine.call_exists(t_params);
})
, "call_exists");
m_engine.add(dispatch::make_dynamic_proxy_function([this](const Function_Params &t_params) { return m_engine.call_exists(t_params); }),
"call_exists");
m_engine.add(fun([this](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves());
return t_fun(Function_Params{t_params}, s);
}),
"call");
m_engine.add(fun(
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves());
return t_fun(t_params, s);
}), "call");
m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name");
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type");
m_engine.add(fun([this](const std::string &t_type_name){ return m_engine.get_type(t_type_name, true); }), "type");
m_engine.add(fun(
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
}
), "add_type_conversion");
m_engine.add(fun([this](const Type_Info &t_ti) { return m_engine.get_type_name(t_ti); }), "name");
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw) { return m_engine.get_type(t_type_name, t_throw); }), "type");
m_engine.add(fun([this](const std::string &t_type_name) { return m_engine.get_type(t_type_name, true); }), "type");
m_engine.add(fun([this](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value(const Boxed_Value &)> &t_func) {
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
}),
"add_type_conversion");
if (std::find(t_opts.begin(), t_opts.end(), Options::No_Load_Modules) == t_opts.end()
&& std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end())
{
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return load_module(t_module, t_file); }), "load_module");
m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module");
&& std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end()) {
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file) { load_module(t_module, t_file); }), "load_module");
m_engine.add(fun([this](const std::string &t_module) { return load_module(t_module); }), "load_module");
}
if (std::find(t_opts.begin(), t_opts.end(), Options::No_External_Scripts) == t_opts.end()
&& std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end())
{
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use");
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
&& std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end()) {
m_engine.add(fun([this](const std::string &t_file) { return use(t_file); }), "use");
m_engine.add(fun([this](const std::string &t_file) { return internal_eval_file(t_file); }), "eval_file");
}
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
m_engine.add(fun([this](const AST_Node &t_ast){ return eval(t_ast); }), "eval");
m_engine.add(fun([this](const std::string &t_str) { return internal_eval(t_str); }), "eval");
m_engine.add(fun([this](const AST_Node &t_ast) { return eval(t_ast); }), "eval");
m_engine.add(fun([this](const std::string &t_str, const bool t_dump){ return parse(t_str, t_dump); }), "parse");
m_engine.add(fun([this](const std::string &t_str){ return parse(t_str); }), "parse");
m_engine.add(fun([this](const std::string &t_str, const bool t_dump) { return parse(t_str, t_dump); }), "parse");
m_engine.add(fun([this](const std::string &t_str) { return parse(t_str); }), "parse");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name) { add_global_const(t_bv, t_name); }), "add_global_const");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name) { add_global(t_bv, t_name); }), "add_global");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name) { set_global(t_bv, t_name); }), "set_global");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([](Namespace& /*space*/) {}, t_namespace_name); import(t_namespace_name); }), "namespace");
m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import");
// why this unused parameter to Namespace?
m_engine.add(fun([this](const std::string &t_namespace_name) {
register_namespace([](Namespace & /*space*/) noexcept {}, t_namespace_name);
import(t_namespace_name);
}),
"namespace");
m_engine.add(fun([this](const std::string &t_namespace_name) { import(t_namespace_name); }), "import");
}
/// Skip BOM at the beginning of file
static bool skip_bom(std::ifstream &infile) {
size_t bytes_needed = 3;
char buffer[3];
size_t bytes_needed = 3;
char buffer[3];
memset(buffer, '\0', bytes_needed);
memset(buffer, '\0', bytes_needed);
infile.read(buffer, static_cast<std::streamsize>(bytes_needed));
infile.read(buffer, static_cast<std::streamsize>(bytes_needed));
if ((buffer[0] == '\xef')
&& (buffer[1] == '\xbb')
&& (buffer[2] == '\xbf')) {
if ((buffer[0] == '\xef') && (buffer[1] == '\xbb') && (buffer[2] == '\xbf')) {
infile.seekg(3);
return true;
}
infile.seekg(3);
return true;
}
infile.seekg(0);
infile.seekg(0);
return false;
return false;
}
/// Helper function for loading a file
static std::string load_file(const std::string &t_filename) {
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary );
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
if (!infile.is_open()) {
throw chaiscript::exception::file_not_found_error(t_filename);
@ -240,12 +214,11 @@ namespace chaiscript
assert(size >= 0);
if (skip_bom(infile)) {
size-=3; // decrement the BOM size from file size, otherwise we'll get parsing errors
assert(size >= 0); //and check if there's more text
size -= 3; // decrement the BOM size from file size, otherwise we'll get parsing errors
assert(size >= 0); // and check if there's more text
}
if (size == std::streampos(0))
{
if (size == std::streampos(0)) {
return std::string();
} else {
std::vector<char> v(static_cast<size_t>(size));
@ -254,14 +227,15 @@ namespace chaiscript
}
}
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths)
{
if (paths.empty()) { return {""}; }
else { return paths; }
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths) {
if (paths.empty()) {
return {""};
} else {
return paths;
}
}
public:
/// \brief Constructor for ChaiScript
/// \param[in] t_lib Standard library to apply to this ChaiScript instance
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
@ -271,42 +245,38 @@ namespace chaiscript
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths))),
m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths))),
m_parser(std::move(parser)),
m_engine(*m_parser)
{
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths)))
, m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths)))
, m_parser(std::move(parser))
, m_engine(*m_parser) {
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
// If on Unix, add the path of the current executable to the module search path
// as windows would do
union cast_union
{
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&);
union cast_union {
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string &);
void *out_ptr;
};
Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) );
Dl_info rInfo;
memset(&rInfo, 0, sizeof(rInfo));
cast_union u;
u.in_ptr = &ChaiScript_Basic::use;
if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) {
if ((dladdr(static_cast<void *>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr)) {
std::string dllpath(rInfo.dli_fname);
const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos)
{
if (lastslash != std::string::npos) {
dllpath.erase(lastslash);
}
// Let's see if this is a link that we should expand
std::vector<char> buf(2048);
const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size())
{
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size()) {
dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen));
}
m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
m_module_paths.insert(m_module_paths.begin(), dllpath + "/");
}
#endif
build_eval_system(t_lib, t_opts);
@ -314,48 +284,45 @@ namespace chaiscript
#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)
{
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 {
// attempt to load the stdlib
load_module("chaiscript_stdlib-" + Build_Info::version());
} catch (const exception::load_module_error &t_err) {
std::cout << "An error occured while trying to load the chaiscript standard library.\n"
<< "\n"
<< "You must either provide a standard library, or compile it in.\n"
<< "For an example of compiling the standard library in,\n"
<< "see: https://gist.github.com/lefticus/9456197\n"
<< "Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n"
<< "\n"
<< "\n"
std::cout << "An error occurred while trying to load the chaiscript standard library.\n"
"\n"
"You must either provide a standard library, or compile it in.\n"
"For an example of compiling the standard library in,\n"
"see: https://gist.github.com/lefticus/9456197\n"
"Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n"
"\n\n"
<< t_err.what();
throw;
}
}
#else // CHAISCRIPT_NO_DYNLOAD
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
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;
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
= delete;
#endif
parser::ChaiScript_Parser_Base &get_parser()
{
parser::ChaiScript_Parser_Base &get_parser() noexcept {
return *m_parser;
}
const Boxed_Value eval(const AST_Node &t_ast)
{
const Boxed_Value eval(const AST_Node &t_ast) {
try {
return t_ast.eval(chaiscript::detail::Dispatch_State(m_engine));
} catch (const exception::eval_error &t_ee) {
@ -363,8 +330,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
}
}
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false)
{
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false) {
auto ast = m_parser->parse(t_input, "PARSE");
if (t_debug_print) {
m_parser->debug_print(*ast);
@ -372,38 +338,28 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
return ast;
}
std::string get_type_name(const Type_Info &ti) const
{
return m_engine.get_type_name(ti);
}
std::string get_type_name(const Type_Info &ti) const { return m_engine.get_type_name(ti); }
template<typename T>
std::string get_type_name() const
{
std::string get_type_name() const {
return get_type_name(user_type<T>());
}
/// \brief Loads and parses a file. If the file is already, it is not reloaded
/// The use paths specified at ChaiScript construction time are searched for the
/// requested file.
/// \brief Loads and parses a file. If the file is already open, it is not
/// reloaded. The use paths specified at ChaiScript construction time are
/// searched for the requested file.
///
/// \param[in] t_filename Filename to load and evaluate
Boxed_Value use(const std::string &t_filename)
{
for (const auto &path : m_use_paths)
{
Boxed_Value use(const std::string &t_filename) {
for (const auto &path : m_use_paths) {
const auto appendedpath = path + t_filename;
try {
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
Boxed_Value retval;
if (m_used_files.count(appendedpath) == 0)
{
if (m_used_files.count(appendedpath) == 0) {
l2.unlock();
retval = eval_file(appendedpath);
l2.lock();
@ -429,8 +385,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \param[in] t_name Name of the value to add
/// \throw chaiscript::exception::global_non_const If t_bv is not a constant object
/// \sa Boxed_Value::is_const
ChaiScript_Basic &add_global_const(const Boxed_Value &t_bv, const std::string &t_name)
{
ChaiScript_Basic &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) {
Name_Validator::validate_object_name(t_name);
m_engine.add_global_const(t_bv, t_name);
return *this;
@ -441,15 +396,13 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \param[in] t_name Name of the value to add
/// \warning The user is responsible for making sure the object is thread-safe if necessary
/// ChaiScript is thread-safe but provides no threading locking mechanism to the script
ChaiScript_Basic &add_global(const Boxed_Value &t_bv, const std::string &t_name)
{
ChaiScript_Basic &add_global(const Boxed_Value &t_bv, const std::string &t_name) {
Name_Validator::validate_object_name(t_name);
m_engine.add_global(t_bv, t_name);
return *this;
}
ChaiScript_Basic &set_global(const Boxed_Value &t_bv, const std::string &t_name)
{
ChaiScript_Basic &set_global(const Boxed_Value &t_bv, const std::string &t_name) {
Name_Validator::validate_object_name(t_name);
m_engine.set_global(t_bv, t_name);
return *this;
@ -460,8 +413,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// are left out due to performance considerations involved in tracking the state
/// \sa ChaiScript::get_state
/// \sa ChaiScript::set_state
struct State
{
struct State {
std::set<std::string> used_files;
chaiscript::detail::Dispatch_Engine::State engine_state;
std::set<std::string> active_loaded_modules;
@ -480,8 +432,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// chaiscript::ChaiScript chai;
/// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state
/// \endcode
State get_state() const
{
State get_state() const {
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@ -506,8 +457,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// chai.add(chaiscript::fun(&somefunction), "somefunction");
/// chai.set_state(s); // restore initial state, which does not have the recently added "somefunction"
/// \endcode
void set_state(const State &t_state)
{
void set_state(const State &t_state) {
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@ -517,26 +467,20 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
}
/// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const
{
return m_engine.get_locals();
}
std::map<std::string, Boxed_Value> get_locals() const { return m_engine.get_locals(); }
/// \brief Sets all of the locals for the current thread state.
///
/// \param[in] t_locals The map<name, value> set of variables to replace the current state with
///
/// Any existing locals are removed and the given set of variables is added
void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
{
m_engine.set_locals(t_locals);
}
void set_locals(const std::map<std::string, Boxed_Value> &t_locals) { m_engine.set_locals(t_locals); }
/// \brief Adds a type, function or object to ChaiScript. Objects are added to the local thread state.
/// \param[in] t_t Item to add
/// \param[in] t_name Name of item to add
/// \returns Reference to current ChaiScript object
///
///
/// \b Examples:
/// \code
/// chaiscript::ChaiScript chai;
@ -548,8 +492,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
///
/// \sa \ref adding_items
template<typename T>
ChaiScript_Basic &add(const T &t_t, const std::string &t_name)
{
ChaiScript_Basic &add(const T &t_t, const std::string &t_name) {
Name_Validator::validate_object_name(t_name);
m_engine.add(t_t, t_name);
return *this;
@ -557,15 +500,14 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \brief Add a new conversion for upcasting to a base class
/// \sa chaiscript::base_class
/// \param[in] d Base class / parent class
/// \param[in] d Base class / parent class
///
/// \b Example:
/// \code
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode
ChaiScript_Basic &add(const Type_Conversion &d)
{
ChaiScript_Basic &add(const Type_Conversion &d) {
m_engine.add(d);
return *this;
}
@ -573,8 +515,7 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \brief Adds all elements of a module to ChaiScript runtime
/// \param[in] t_p The module to add.
/// \sa chaiscript::Module
ChaiScript_Basic &add(const ModulePtr &t_p)
{
ChaiScript_Basic &add(const ModulePtr &t_p) {
t_p->apply(*this, this->get_eval_engine());
return *this;
}
@ -587,21 +528,18 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|".bundle"|"").
///
/// Once the file is located, the system looks for the symbol "create_chaiscript_module_\<t_module_name\>".
/// If no file can be found matching the search criteria and containing the appropriate entry point
/// If no file can be found matching the search criteria and containing the appropriate entry point
/// (the symbol mentioned above), an exception is thrown.
///
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
std::string load_module(const std::string &t_module_name)
{
std::string load_module(const std::string &t_module_name) {
#ifdef CHAISCRIPT_NO_DYNLOAD
(void)t_module_name; // -Wunused-parameter
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
#else
std::vector<exception::load_module_error> errors;
std::string version_stripped_name = t_module_name;
size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
if (version_pos != std::string::npos)
{
if (version_pos != std::string::npos) {
version_stripped_name.erase(version_pos);
}
@ -609,12 +547,9 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
std::vector<std::string> postfixes{".dll", ".so", ".bundle", ""};
for (auto & elem : m_module_paths)
{
for (auto & prefix : prefixes)
{
for (auto & postfix : postfixes)
{
for (auto &elem : m_module_paths) {
for (auto &prefix : prefixes) {
for (auto &postfix : postfixes) {
try {
const auto name = elem + prefix + t_module_name + postfix;
// std::cerr << "trying location: " << name << '\n';
@ -640,12 +575,10 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \param[in] t_filename Ignore normal filename search process and use specific filename
///
/// \sa ChaiScript::load_module(const std::string &t_module_name)
void load_module(const std::string &t_module_name, const std::string &t_filename)
{
void load_module(const std::string &t_module_name, const std::string &t_filename) {
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
if (m_loaded_modules.count(t_module_name) == 0)
{
if (m_loaded_modules.count(t_module_name) == 0) {
detail::Loadable_Module_Ptr lm(new detail::Loadable_Module(t_module_name, t_filename));
m_loaded_modules[t_module_name] = lm;
m_active_loaded_modules.insert(t_module_name);
@ -653,20 +586,18 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
} else if (m_active_loaded_modules.count(t_module_name) == 0) {
m_active_loaded_modules.insert(t_module_name);
add(m_loaded_modules[t_module_name]->m_moduleptr);
}
}
}
/// \brief Evaluates a string. Equivalent to ChaiScript::eval.
///
/// \param[in] t_script Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
///
/// \return result of the script execution
///
///
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler())
{
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler()) {
return eval(t_script, t_handler);
}
@ -679,23 +610,20 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// in special cases where you are loading a file internally instead of using eval_file
///
/// \return result of the script execution
///
///
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
/// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// to the requested type.
template<typename T>
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename = "__EVAL__") {
return m_engine.boxed_cast<T>(eval(t_input, t_handler, t_filename));
}
/// \brief casts an object while applying any Dynamic_Conversion available
template<typename Type>
decltype(auto) boxed_cast(const Boxed_Value &bv) const
{
return(m_engine.boxed_cast<Type>(bv));
}
decltype(auto) boxed_cast(const Boxed_Value &bv) const {
return (m_engine.boxed_cast<Type>(bv));
}
/// \brief Evaluates a string.
///
@ -705,10 +633,10 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// in special cases where you are loading a file internally instead of using eval_file
///
/// \return result of the script execution
///
///
/// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{
Boxed_Value
eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename = "__EVAL__") {
try {
return do_eval(t_input, t_filename);
} catch (Boxed_Value &bv) {
@ -744,39 +672,35 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
/// \brief Imports a namespace object into the global scope of this ChaiScript instance.
/// \param[in] t_namespace_name Name of the namespace to import.
/// \throw std::runtime_error In the case that the namespace name was never registered.
void import(const std::string& t_namespace_name)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
void import(const std::string &t_namespace_name) {
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
if (m_engine.get_scripting_objects().count(t_namespace_name)) {
throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined");
}
else if (m_namespace_generators.count(t_namespace_name)) {
m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name);
}
else {
throw std::runtime_error("No registered namespace: " + t_namespace_name);
}
if (m_engine.get_scripting_objects().count(t_namespace_name)) {
throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined");
} else if (m_namespace_generators.count(t_namespace_name)) {
m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name);
} else {
throw std::runtime_error("No registered namespace: " + t_namespace_name);
}
}
/// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never used.
/// \param[in] t_namespace_generator Namespace generator function.
/// \param[in] t_namespace_name Name of the Namespace function being registered.
/// \throw std::runtime_error In the case that the namespace name was already registered.
void register_namespace(const std::function<void(Namespace&)>& t_namespace_generator, const std::string& t_namespace_name)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
/// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never
/// used. \param[in] t_namespace_generator Namespace generator function. \param[in] t_namespace_name Name of the Namespace function
/// being registered. \throw std::runtime_error In the case that the namespace name was already registered.
void register_namespace(const std::function<void(Namespace &)> &t_namespace_generator, const std::string &t_namespace_name) {
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
if (!m_namespace_generators.count(t_namespace_name)) {
// contain the namespace object memory within the m_namespace_generators map
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace& { t_namespace_generator(space); return space; }));
}
else {
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
}
if (!m_namespace_generators.count(t_namespace_name)) {
// contain the namespace object memory within the m_namespace_generators map
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace & {
t_namespace_generator(space);
return space;
}));
} else {
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
}
}
};
}
} // namespace chaiscript
#endif /* CHAISCRIPT_ENGINE_HPP_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
@ -9,76 +9,68 @@
#include "chaiscript_eval.hpp"
namespace chaiscript {
namespace optimizer {
template<typename ... T>
struct Optimizer : T...
{
template<typename... T>
struct Optimizer : T... {
Optimizer() = default;
explicit Optimizer(T ... t)
: T(std::move(t))...
{
explicit Optimizer(T... t)
: T(std::move(t))... {
}
template<typename Tracer>
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
(void)std::initializer_list<int>{ (p = static_cast<T&>(*this).optimize(std::move(p)), 0)... };
((p = static_cast<T &>(*this).optimize(std::move(p))), ...);
return p;
}
};
template<typename T>
eval::AST_Node_Impl<T> &child_at(eval::AST_Node_Impl<T> &node, const size_t offset) {
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
return *(dynamic_cast<eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
} else {
return *node.children[offset];
}
eval::AST_Node_Impl<T> &child_at(eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
return *(dynamic_cast<eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
} else {
return *node.children[offset];
}
}
template<typename T>
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) {
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
return *(dynamic_cast<const eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
} else {
return *node.children[offset];
}
/*
if (node->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset];
} else {
return node->children[offset];
}
*/
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
return *(dynamic_cast<const eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
} else {
return *node.children[offset];
}
/*
if (node->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset];
} else {
return node->children[offset];
}
*/
}
template<typename T>
auto child_count(const eval::AST_Node_Impl<T> &node) {
if (node.identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(node).m_original_node->children.size();
} else {
return node.children.size();
}
auto child_count(const eval::AST_Node_Impl<T> &node) noexcept {
if (node.identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T> &>(node).m_original_node->children.size();
} else {
return node.children.size();
}
}
template<typename T, typename Callable>
auto make_compiled_node(eval::AST_Node_Impl_Ptr<T> original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable)
{
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(std::move(original_node), std::move(children), std::move(callable));
}
auto make_compiled_node(eval::AST_Node_Impl_Ptr<T> original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable) {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(std::move(original_node),
std::move(children),
std::move(callable));
}
struct Return {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> p)
{
if ( (p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda)
&& !p->children.empty())
{
auto optimize(eval::AST_Node_Impl_Ptr<T> p) {
if ((p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda) && !p->children.empty()) {
auto &last_child = p->children.back();
if (last_child->identifier == AST_Node_Type::Block) {
auto &block_last_child = last_child->children.back();
@ -95,9 +87,9 @@ namespace chaiscript {
};
template<typename T>
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node)
{
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl || node.identifier == AST_Node_Type::Reference) {
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node) noexcept {
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl
|| node.identifier == AST_Node_Type::Reference) {
return true;
}
@ -105,10 +97,8 @@ namespace chaiscript {
for (size_t i = 0; i < num; ++i) {
const auto &child = child_at(node, i);
if (child.identifier != AST_Node_Type::Block
&& child.identifier != AST_Node_Type::For
&& child.identifier != AST_Node_Type::Ranged_For
&& contains_var_decl_in_scope(child)) {
if (child.identifier != AST_Node_Type::Block && child.identifier != AST_Node_Type::For
&& child.identifier != AST_Node_Type::Ranged_For && contains_var_decl_in_scope(child)) {
return true;
}
}
@ -119,15 +109,14 @@ namespace chaiscript {
struct Block {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if (node->identifier == AST_Node_Type::Block)
{
if (!contains_var_decl_in_scope(*node))
{
if (node->identifier == AST_Node_Type::Block) {
if (!contains_var_decl_in_scope(*node)) {
if (node->children.size() == 1) {
return std::move(node->children[0]);
} else {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text, node->location,
std::move(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));
}
}
}
@ -138,105 +127,91 @@ namespace chaiscript {
struct Dead_Code {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if (node->identifier == AST_Node_Type::Block)
{
std::vector<size_t> keepers;
const auto num_children = node->children.size();
keepers.reserve(num_children);
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if (node->identifier == AST_Node_Type::Block) {
std::vector<size_t> keepers;
const auto num_children = node->children.size();
keepers.reserve(num_children);
for (size_t i = 0; i < num_children; ++i) {
const auto &child = *node->children[i];
if ( (child.identifier != AST_Node_Type::Id
&& child.identifier != AST_Node_Type::Constant
&& child.identifier != AST_Node_Type::Noop)
|| i == num_children - 1) {
keepers.push_back(i);
}
for (size_t i = 0; i < num_children; ++i) {
const auto &child = *node->children[i];
if ((child.identifier != AST_Node_Type::Id && child.identifier != AST_Node_Type::Constant
&& child.identifier != AST_Node_Type::Noop)
|| i == num_children - 1) {
keepers.push_back(i);
}
if (keepers.size() == num_children) {
return node;
} else {
const auto new_children = [&](){
std::vector<eval::AST_Node_Impl_Ptr<T>> retval;
for (const auto x : keepers)
{
retval.push_back(std::move(node->children[x]));
}
return retval;
};
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Block_AST_Node<T>>(node->text, node->location, new_children());
}
} else {
return node;
}
if (keepers.size() == num_children) {
return node;
} else {
const auto new_children = [&]() {
std::vector<eval::AST_Node_Impl_Ptr<T>> retval;
for (const auto x : keepers) {
retval.push_back(std::move(node->children[x]));
}
return retval;
};
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Block_AST_Node<T>>(node->text, node->location, new_children());
}
} else {
return node;
}
}
};
struct Unused_Return {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if ((node->identifier == AST_Node_Type::Block
|| node->identifier == AST_Node_Type::Scopeless_Block)
&& !node->children.empty())
{
for (size_t i = 0; i < node->children.size()-1; ++i) {
auto child = node->children[i].get();
if (child->identifier == AST_Node_Type::Fun_Call) {
node->children[i] = chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(child->text, child->location,
std::move(child->children));
}
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if ((node->identifier == AST_Node_Type::Block || node->identifier == AST_Node_Type::Scopeless_Block) && !node->children.empty()) {
for (size_t i = 0; i < node->children.size() - 1; ++i) {
auto child = node->children[i].get();
if (child->identifier == AST_Node_Type::Fun_Call) {
node->children[i]
= chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(child->text,
child->location,
std::move(child->children));
}
} else if ((node->identifier == AST_Node_Type::For
|| node->identifier == AST_Node_Type::While)
&& child_count(*node) > 0) {
auto &child = child_at(*node, child_count(*node) - 1);
if (child.identifier == AST_Node_Type::Block
|| child.identifier == AST_Node_Type::Scopeless_Block)
{
auto num_sub_children = child_count(child);
for (size_t i = 0; i < num_sub_children; ++i) {
auto &sub_child = child_at(child, i);
if (sub_child.identifier == AST_Node_Type::Fun_Call) {
child.children[i] = chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(sub_child.text, sub_child.location, std::move(sub_child.children));
}
}
} else if ((node->identifier == AST_Node_Type::For || node->identifier == AST_Node_Type::While) && child_count(*node) > 0) {
auto &child = child_at(*node, child_count(*node) - 1);
if (child.identifier == AST_Node_Type::Block || child.identifier == AST_Node_Type::Scopeless_Block) {
auto num_sub_children = child_count(child);
for (size_t i = 0; i < num_sub_children; ++i) {
auto &sub_child = child_at(child, i);
if (sub_child.identifier == AST_Node_Type::Fun_Call) {
child.children[i] = chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(
sub_child.text, sub_child.location, std::move(sub_child.children));
}
}
}
return node;
}
return node;
}
};
struct Assign_Decl {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if ((node->identifier == AST_Node_Type::Equation)
&& node->text == "="
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Var_Decl
)
{
if ((node->identifier == AST_Node_Type::Equation) && node->text == "=" && node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Var_Decl) {
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
new_children.push_back(std::move(node->children[0]->children[0]));
new_children.push_back(std::move(node->children[1]));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Assign_Decl_AST_Node<T>>(node->text,
node->location, std::move(new_children) );
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Assign_Decl_AST_Node<T>>(node->text,
node->location,
std::move(new_children));
}
return node;
}
};
struct If {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if ((node->identifier == AST_Node_Type::If)
&& node->children.size() >= 2
&& node->children[0]->identifier == AST_Node_Type::Constant)
{
if ((node->identifier == AST_Node_Type::If) && node->children.size() >= 2 && node->children[0]->identifier == AST_Node_Type::Constant) {
const auto condition = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[0].get())->m_value;
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
if (boxed_cast<bool>(condition)) {
@ -254,25 +229,21 @@ namespace chaiscript {
struct Partial_Fold {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
// Fold right side
if (node->identifier == AST_Node_Type::Binary
&& node->children.size() == 2
&& node->children[0]->identifier != AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
if (node->identifier == AST_Node_Type::Binary && node->children.size() == 2
&& node->children[0]->identifier != AST_Node_Type::Constant && node->children[1]->identifier == AST_Node_Type::Constant) {
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper);
if (parsed != Operators::Opers::invalid) {
const auto rhs = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[1].get())->m_value;
if (rhs.get_type_info().is_arithmetic()) {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(node->text, node->location,
std::move(node->children), rhs);
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(
node->text, node->location, std::move(node->children), rhs);
}
}
} catch (const std::exception &) {
//failure to fold, that's OK
// failure to fold, that's OK
}
}
@ -283,11 +254,7 @@ namespace chaiscript {
struct Constant_Fold {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if (node->identifier == AST_Node_Type::Prefix
&& node->children.size() == 1
&& node->children[0]->identifier == AST_Node_Type::Constant)
{
if (node->identifier == AST_Node_Type::Prefix && node->children.size() == 1 && node->children[0]->identifier == AST_Node_Type::Constant) {
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper, true);
@ -295,39 +262,43 @@ namespace chaiscript {
const auto match = oper + node->children[0]->text;
if (parsed != Operators::Opers::invalid && parsed != Operators::Opers::bitwise_and && lhs.get_type_info().is_arithmetic()) {
const auto val = Boxed_Number::do_oper(parsed, lhs);
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
const auto val = Boxed_Number::do_oper(parsed, lhs);
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
std::move(val));
} else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(!boxed_cast<bool>(lhs)));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
Boxed_Value(!boxed_cast<bool>(lhs)));
}
} catch (const std::exception &) {
//failure to fold, that's OK
// failure to fold, that's OK
}
} else if ((node->identifier == AST_Node_Type::Logical_And || node->identifier == AST_Node_Type::Logical_Or)
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
&& node->children.size() == 2 && node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant) {
try {
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
const auto rhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]).m_value;
if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && rhs.get_type_info().bare_equal_type_info(typeid(bool))) {
const auto match = node->children[0]->text + " " + node->text + " " + node->children[1]->text;
const auto val = [lhs_val = boxed_cast<bool>(lhs), rhs_val = boxed_cast<bool>(rhs), id = node->identifier] {
if (id == AST_Node_Type::Logical_And) { return Boxed_Value(lhs_val && rhs_val); }
else { return Boxed_Value(lhs_val || rhs_val); }
if (id == AST_Node_Type::Logical_And) {
return Boxed_Value(lhs_val && rhs_val);
} else {
return Boxed_Value(lhs_val || rhs_val);
}
}();
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
std::move(val));
}
} catch (const std::exception &) {
//failure to fold, that's OK
// failure to fold, that's OK
}
} else if (node->identifier == AST_Node_Type::Binary
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
} else if (node->identifier == AST_Node_Type::Binary && node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Constant && node->children[1]->identifier == AST_Node_Type::Constant) {
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper);
@ -335,28 +306,28 @@ namespace chaiscript {
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
const auto rhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]).m_value;
if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) {
const auto val = Boxed_Number::do_oper(parsed, lhs, rhs);
const auto val = Boxed_Number::do_oper(parsed, lhs, rhs);
const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
std::move(val));
}
}
} catch (const std::exception &) {
//failure to fold, that's OK
// failure to fold, that's OK
}
} else if (node->identifier == AST_Node_Type::Fun_Call
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Id
&& node->children[1]->identifier == AST_Node_Type::Arg_List
&& node->children[1]->children.size() == 1
&& node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
} else if (node->identifier == AST_Node_Type::Fun_Call && node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Id && node->children[1]->identifier == AST_Node_Type::Arg_List
&& node->children[1]->children.size() == 1 && node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
const auto arg = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]->children[0]).m_value;
if (arg.get_type_info().is_arithmetic()) {
const auto &fun_name = node->children[0]->text;
const auto make_constant = [&node, &fun_name](auto val){
const auto make_constant = [&node, &fun_name](auto val) {
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")";
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, const_var(val));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
const_var(val));
};
if (fun_name == "double") {
@ -370,10 +341,7 @@ namespace chaiscript {
} else if (fun_name == "size_t") {
return make_constant(Boxed_Number(arg).get_as<size_t>());
}
}
}
return node;
@ -383,7 +351,6 @@ namespace chaiscript {
struct For_Loop {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> for_node) {
if (for_node->identifier != AST_Node_Type::For) {
return for_node;
}
@ -392,66 +359,55 @@ namespace chaiscript {
const auto &binary_node = child_at(*for_node, 1);
const auto &prefix_node = child_at(*for_node, 2);
if (child_count(*for_node) == 4
&& eq_node.identifier == AST_Node_Type::Assign_Decl
&& child_count(eq_node) == 2
&& child_at(eq_node, 0).identifier == AST_Node_Type::Id
&& child_at(eq_node, 1).identifier == AST_Node_Type::Constant
&& binary_node.identifier == AST_Node_Type::Binary
&& binary_node.text == "<"
&& child_count(binary_node) == 2
&& child_at(binary_node, 0).identifier == AST_Node_Type::Id
&& child_at(binary_node, 0).text == child_at(eq_node,0).text
&& child_at(binary_node, 1).identifier == AST_Node_Type::Constant
&& prefix_node.identifier == AST_Node_Type::Prefix
&& prefix_node.text == "++"
&& child_count(prefix_node) == 1
&& child_at(prefix_node, 0).identifier == AST_Node_Type::Id
&& child_at(prefix_node, 0).text == child_at(eq_node,0).text)
{
if (child_count(*for_node) == 4 && eq_node.identifier == AST_Node_Type::Assign_Decl && child_count(eq_node) == 2
&& child_at(eq_node, 0).identifier == AST_Node_Type::Id && child_at(eq_node, 1).identifier == AST_Node_Type::Constant
&& binary_node.identifier == AST_Node_Type::Binary && binary_node.text == "<" && child_count(binary_node) == 2
&& child_at(binary_node, 0).identifier == AST_Node_Type::Id && child_at(binary_node, 0).text == child_at(eq_node, 0).text
&& child_at(binary_node, 1).identifier == AST_Node_Type::Constant && prefix_node.identifier == AST_Node_Type::Prefix
&& prefix_node.text == "++" && child_count(prefix_node) == 1 && child_at(prefix_node, 0).identifier == AST_Node_Type::Id
&& child_at(prefix_node, 0).text == child_at(eq_node, 0).text) {
const Boxed_Value &begin = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(eq_node, 1)).m_value;
const Boxed_Value &end = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(binary_node, 1)).m_value;
const std::string &id = child_at(prefix_node, 0).text;
if (begin.get_type_info().bare_equal(user_type<int>())
&& end.get_type_info().bare_equal(user_type<int>())) {
if (begin.get_type_info().bare_equal(user_type<int>()) && end.get_type_info().bare_equal(user_type<int>())) {
const auto start_int = boxed_cast<int>(begin);
const auto end_int = boxed_cast<int>(end);
// note that we are moving the last element out, then popping the empty shared_ptr
// note that we are moving the last element out, then popping the empty shared_ptr
// from the vector
std::vector<eval::AST_Node_Impl_Ptr<T>> body_vector;
auto body_child = std::move(for_node->children[3]);
for_node->children.pop_back();
body_vector.emplace_back(std::move(body_child));
return make_compiled_node(std::move(for_node), std::move(body_vector),
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children, const chaiscript::detail::Dispatch_State &t_ss) {
assert(children.size() == 1);
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
int i = start_int;
t_ss.add_object(id, var(&i));
return make_compiled_node(std::move(for_node),
std::move(body_vector),
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children,
const chaiscript::detail::Dispatch_State &t_ss) {
assert(children.size() == 1);
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
try {
for (; i < end_int; ++i) {
try {
// Body of Loop
children[0]->eval(t_ss);
} catch (eval::detail::Continue_Loop &) {
// we got a continue exception, which means all of the remaining
// loop implementation is skipped and we just need to continue to
// the next iteration step
}
}
} catch (eval::detail::Break_Loop &) {
// loop broken
}
int i = start_int;
t_ss.add_object(id, var(&i));
return void_var();
}
);
try {
for (; i < end_int; ++i) {
try {
// Body of Loop
children[0]->eval(t_ss);
} catch (eval::detail::Continue_Loop &) {
// we got a continue exception, which means all of the remaining
// loop implementation is skipped and we just need to continue to
// the next iteration step
}
}
} catch (eval::detail::Break_Loop &) {
// loop broken
}
return void_var();
});
} else {
return for_node;
}
@ -461,11 +417,17 @@ namespace chaiscript {
}
};
typedef Optimizer<optimizer::Partial_Fold, optimizer::Unused_Return, optimizer::Constant_Fold,
optimizer::If, optimizer::Return, optimizer::Dead_Code, optimizer::Block, optimizer::For_Loop, optimizer::Assign_Decl> Optimizer_Default;
}
}
using Optimizer_Default = Optimizer<optimizer::Partial_Fold,
optimizer::Unused_Return,
optimizer::Constant_Fold,
optimizer::If,
optimizer::Return,
optimizer::Dead_Code,
optimizer::Block,
optimizer::For_Loop,
optimizer::Assign_Decl>;
} // namespace optimizer
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,68 +1,53 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_POSIX_HPP_
#define CHAISCRIPT_POSIX_HPP_
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
struct DLModule
{
explicit DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{
if (m_data == nullptr)
{
throw chaiscript::exception::load_module_error(dlerror());
}
namespace chaiscript::detail {
struct Loadable_Module {
struct DLModule {
explicit DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW)) {
if (m_data == nullptr) {
throw chaiscript::exception::load_module_error(dlerror());
}
DLModule(DLModule &&) = default;
DLModule &operator=(DLModule &&) = default;
DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete;
~DLModule()
{
dlclose(m_data);
}
void *m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(dlerror());
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
}
}
#endif
DLModule(DLModule &&) = default;
DLModule &operator=(DLModule &&) = default;
DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete;
~DLModule() { dlclose(m_data); }
void *m_data;
};
template<typename T>
struct DLSym {
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str()))) {
if (!m_symbol) {
throw chaiscript::exception::load_module_error(dlerror());
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename)
, m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name)
, m_moduleptr(m_func.m_symbol()) {
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
} // namespace chaiscript::detail
#endif

View File

@ -1,43 +1,44 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and 2009-2017, Jason Turner (jason@emptycrate.com)
// and 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_
#define CHAISCRIPT_PRELUDE_HPP_
namespace chaiscript {
struct ChaiScript_Prelude {
static std::string chaiscript_prelude() { return R"chaiscript(
struct ChaiScript_Prelude {
static std::string chaiscript_prelude() {
return R"chaiscript(
def lt(l, r) {
if (call_exists(`<`, l, r)) {
l < r
} else {
type_name(l) < type_name(r)
}
def lt(l, r) {
if (call_exists(`<`, l, r)) {
l < r
} else {
type_name(l) < type_name(r)
}
}
def gt(l, r) {
if (call_exists(`>`, l, r)) {
l > r
} else {
type_name(l) > type_name(r)
}
def gt(l, r) {
if (call_exists(`>`, l, r)) {
l > r
} else {
type_name(l) > type_name(r)
}
}
def eq(l, r) {
if (call_exists(`==`, l, r)) {
l == r
} else {
false
}
def eq(l, r) {
if (call_exists(`==`, l, r)) {
l == r
} else {
false
}
}
def new(x) {
eval(type_name(x))();
def new(x) {
eval(type_name(x))();
}
def clone(double x) {
@ -64,85 +65,85 @@ def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)),
# to_string for Pair()
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
"<" + x.first.to_string() + ", " + x.second.to_string() + ">";
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
"<" + x.first.to_string() + ", " + x.second.to_string() + ">";
}
# to_string for containers
def to_string(x) : call_exists(range, x) && !x.is_type("string"){
"[" + x.join(", ") + "]";
def to_string(x) : call_exists(range, x) && !x.is_type("string"){
"[" + x.join(", ") + "]";
}
# Prints to console with no carriage return
def puts(x) {
print_string(x.to_string());
def puts(x) {
print_string(x.to_string());
}
# Prints to console with carriage return
def print(x) {
println_string(x.to_string());
def print(x) {
println_string(x.to_string());
}
# Returns the maximum value of two numbers
def max(a, b) {
if (a>b) {
a
} else {
b
}
}
if (a>b) {
a
} else {
b
}
}
# Returns the minimum value of two numbers
def min(a, b)
{
if (a<b)
{
a
} else {
b
}
def min(a, b)
{
if (a<b)
{
a
} else {
b
}
}
# Returns true if the value is odd
def odd(x) {
if (x % 2 == 1)
{
true
} else {
false
}
def odd(x) {
if (x % 2 == 1)
{
true
} else {
false
}
}
# Returns true if the value is even
def even(x)
{
if (x % 2 == 0)
{
true
} else {
false
}
}
def even(x)
{
if (x % 2 == 0)
{
true
} else {
false
}
}
# Inserts the third value at the position of the second value into the container of the first
# while making a clone.
def insert_at(container, pos, x)
{
container.insert_ref_at(pos, clone(x));
}
# while making a clone.
def insert_at(container, pos, x)
{
container.insert_ref_at(pos, clone(x));
}
# Returns the reverse of the given container
def reverse(container) {
auto retval := new(container);
auto r := range(container);
while (!r.empty()) {
retval.push_back(r.back());
r.pop_back();
}
retval;
auto retval := new(container);
auto r := range(container);
while (!r.empty()) {
retval.push_back(r.back());
r.pop_back();
}
retval;
}
@ -153,86 +154,86 @@ def range(r) : call_exists(range_internal, r)
ri;
}
# Return a range from a range
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
# Return a range from a range
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{
clone(r);
}
# The retro attribute that contains the underlying range
attr retro::m_range;
# The retro attribute that contains the underlying range
attr retro::m_range;
# Creates a retro from a retro by returning the original range
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
{
clone(r.m_range)
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
{
clone(r.m_range)
}
# Creates a retro range from a range
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{
this.m_range = r;
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{
this.m_range = r;
}
# Returns the first value of a retro
def retro::front()
{
back(this.m_range)
def retro::front()
{
back(this.m_range)
}
# Returns the last value of a retro
def retro::back()
{
front(this.m_range)
}
# Moves the back iterator of a retro towards the front by one
def retro::pop_back()
def retro::back()
{
pop_front(this.m_range)
front(this.m_range)
}
# Moves the front iterator of a retro towards the back by one
def retro::pop_front()
{
pop_back(this.m_range)
}
# Moves the back iterator of a retro towards the front by one
def retro::pop_back()
{
pop_front(this.m_range)
}
# returns true if the retro is out of elements
def retro::empty()
{
empty(this.m_range);
}
# Moves the front iterator of a retro towards the back by one
def retro::pop_front()
{
pop_back(this.m_range)
}
# returns true if the retro is out of elements
def retro::empty()
{
empty(this.m_range);
}
# Performs the second value function over the container first value
def for_each(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
func(t_range.front());
t_range.pop_front();
}
}
def for_each(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
func(t_range.front());
t_range.pop_front();
}
}
def any_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
def any_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (func(t_range.front())) {
return true;
}
t_range.pop_front();
t_range.pop_front();
}
false;
}
def all_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
def all_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (!func(t_range.front())) {
return false;
}
t_range.pop_front();
t_range.pop_front();
}
true;
@ -242,321 +243,320 @@ def back_inserter(container) {
bind(push_back, container, _);
}
def contains(container, item, compare_func) : call_exists(range, container) {
auto t_range := range(container);
while (!t_range.empty()) {
if ( compare_func(t_range.front(), item) ) {
return true;
}
def contains(container, item, compare_func) : call_exists(range, container) {
auto t_range := range(container);
while (!t_range.empty()) {
if ( compare_func(t_range.front(), item) ) {
return true;
}
t_range.pop_front();
}
false;
}
t_range.pop_front();
}
false;
}
def contains(container, item) {
contains(container, item, eq)
}
def contains(container, item) {
contains(container, item, eq)
}
def map(container, func, inserter) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
inserter(func(range.front()));
range.pop_front();
}
}
def map(container, func, inserter) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
inserter(func(range.front()));
range.pop_front();
}
}
# Performs the second value function over the container first value. Creates a new container with the results
def map(container, func) {
auto retval := new(container);
def map(container, func) {
auto retval := new(container);
map(container, func, back_inserter(retval));
retval;
}
# Performs the second value function over the container first value. Starts with initial and continues with each element.
def foldl(container, func, initial) : call_exists(range, container){
auto retval = initial;
auto range := range(container);
while (!range.empty()) {
retval = (func(range.front(), retval));
range.pop_front();
}
retval;
def foldl(container, func, initial) : call_exists(range, container){
auto retval = initial;
auto range := range(container);
while (!range.empty()) {
retval = (func(range.front(), retval));
range.pop_front();
}
retval;
}
# Returns the sum of the elements of the given value
def sum(container) {
foldl(container, `+`, 0.0)
}
def sum(container) {
foldl(container, `+`, 0.0)
}
# Returns the product of the elements of the given value
def product(container) {
foldl(container, `*`, 1.0)
}
def product(container) {
foldl(container, `*`, 1.0)
}
# Returns a new container with the elements of the first value concatenated with the elements of the second value
def concat(x, y) : call_exists(clone, x) {
auto retval = x;
auto inserter := back_inserter(retval);
auto range := range(y);
while (!range.empty()) {
inserter(range.front());
range.pop_front();
}
retval;
def concat(x, y) : call_exists(clone, x) {
auto retval = x;
auto inserter := back_inserter(retval);
auto range := range(y);
while (!range.empty()) {
inserter(range.front());
range.pop_front();
}
retval;
}
def take(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
inserter(r.front());
r.pop_front();
--i;
}
def take(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
inserter(r.front());
r.pop_front();
--i;
}
}
# Returns a new container with the given number of elements taken from the container
def take(container, num) {
auto retval := new(container);
take(container, num, back_inserter(retval));
retval;
}
def take_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty()) && f(r.front())) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given elements match the second value function
def take_while(container, f) {
auto retval := new(container);
take_while(container, f, back_inserter(retval));
auto retval := new(container);
take(container, num, back_inserter(retval));
retval;
}
def drop(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
r.pop_front();
--i;
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
def take_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty()) && f(r.front())) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given number of elements dropped from the given container
# Returns a new container with the given elements match the second value function
def take_while(container, f) {
auto retval := new(container);
take_while(container, f, back_inserter(retval));
retval;
}
def drop(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
r.pop_front();
--i;
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given number of elements dropped from the given container
def drop(container, num) {
auto retval := new(container);
drop(container, num, back_inserter(retval));
retval;
auto retval := new(container);
drop(container, num, back_inserter(retval));
retval;
}
def drop_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty())&& f(r.front())) {
r.pop_front();
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
def drop_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty())&& f(r.front())) {
r.pop_front();
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given elements dropped that match the second value function
def drop_while(container, f) {
auto retval := new(container);
drop_while(container, f, back_inserter(retval));
retval;
auto retval := new(container);
drop_while(container, f, back_inserter(retval));
retval;
}
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
auto r := range(container);
auto retval = r.front();
r.pop_front();
retval = func(retval, r.front());
r.pop_front();
while (!r.empty()) {
retval = func(retval, r.front());
r.pop_front();
}
retval;
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
auto r := range(container);
auto retval = r.front();
r.pop_front();
retval = func(retval, r.front());
r.pop_front();
while (!r.empty()) {
retval = func(retval, r.front());
r.pop_front();
}
retval;
}
# Returns a string of the elements in container delimited by the second value string
def join(container, delim) {
auto retval = "";
auto range := range(container);
if (!range.empty()) {
retval += to_string(range.front());
range.pop_front();
while (!range.empty()) {
retval += delim;
retval += to_string(range.front());
range.pop_front();
}
}
retval;
def join(container, delim) {
auto retval = "";
auto range := range(container);
if (!range.empty()) {
retval += to_string(range.front());
range.pop_front();
while (!range.empty()) {
retval += delim;
retval += to_string(range.front());
range.pop_front();
}
}
retval;
}
def filter(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while (!r.empty()) {
if (f(r.front())) {
inserter(r.front());
}
r.pop_front();
}
}
def filter(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while (!r.empty()) {
if (f(r.front())) {
inserter(r.front());
}
r.pop_front();
}
}
# Returns a new Vector which match the second value function
def filter(container, f) {
auto retval := new(container);
def filter(container, f) {
auto retval := new(container);
filter(container, f, back_inserter(retval));
retval;
}
def generate_range(x, y, inserter) {
auto i = x;
while (i <= y) {
inserter(i);
++i;
}
def generate_range(x, y, inserter) {
auto i = x;
while (i <= y) {
inserter(i);
++i;
}
}
# Returns a new Vector which represents the range from the first value to the second value
def generate_range(x, y) {
auto retval := Vector();
generate_range(x,y,back_inserter(retval));
retval;
def generate_range(x, y) {
auto retval := Vector();
generate_range(x,y,back_inserter(retval));
retval;
}
# Returns a new Vector with the first value to the second value as its elements
def collate(x, y) {
return [x, y];
def collate(x, y) {
return [x, y];
}
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
auto r_x := range(x);
auto r_y := range(y);
while (!r_x.empty() && !r_y.empty()) {
inserter(f(r_x.front(), r_y.front()));
r_x.pop_front();
r_y.pop_front();
}
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
auto r_x := range(x);
auto r_y := range(y);
while (!r_x.empty() && !r_y.empty()) {
inserter(f(r_x.front(), r_y.front()));
r_x.pop_front();
r_y.pop_front();
}
}
# Returns a new Vector which joins matching elements of the second and third value with the first value function
def zip_with(f, x, y) {
auto retval := Vector();
zip_with(f,x,y,back_inserter(retval));
def zip_with(f, x, y) {
auto retval := Vector();
zip_with(f,x,y,back_inserter(retval));
retval;
}
# Returns a new Vector which joins matching elements of the first and second
def zip(x, y) {
zip_with(collate, x, y);
def zip(x, y) {
zip_with(collate, x, y);
}
# Returns the position of the second value string in the first value string
def string::find(string substr) {
find(this, substr, size_t(0));
def string::find(string substr) {
find(this, substr, size_t(0));
}
# Returns the position of last match of the second value string in the first value string
def string::rfind(string substr) {
rfind(this, substr, size_t(-1));
def string::rfind(string substr) {
rfind(this, substr, size_t(-1));
}
# Returns the position of the first match of elements in the second value string in the first value string
def string::find_first_of(string list) {
find_first_of(this, list, size_t(0));
}
def string::find_first_of(string list) {
find_first_of(this, list, size_t(0));
}
# Returns the position of the last match of elements in the second value string in the first value string
def string::find_last_of(string list) {
find_last_of(this, list, size_t(-1));
}
find_last_of(this, list, size_t(-1));
}
# Returns the position of the first non-matching element in the second value string in the first value string
def string::find_first_not_of(string list) {
find_first_not_of(this, list, size_t(0));
}
def string::find_first_not_of(string list) {
find_first_not_of(this, list, size_t(0));
}
# Returns the position of the last non-matching element in the second value string in the first value string
def string::find_last_not_of(string list) {
find_last_not_of(this, list, size_t(-1));
}
def string::ltrim() {
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
}
def string::rtrim() {
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
}
def string::trim() {
ltrim(rtrim(this));
def string::find_last_not_of(string list) {
find_last_not_of(this, list, size_t(-1));
}
def find(container, value, Function compare_func) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
if (compare_func(range.front(), value)) {
return range;
} else {
range.pop_front();
}
}
range;
}
def string::ltrim() {
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
}
def find(container, value) {
find(container, value, eq)
}
def string::rtrim() {
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
}
def string::trim() {
ltrim(rtrim(this));
}
def find(container, value, Function compare_func) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
if (compare_func(range.front(), value)) {
return range;
} else {
range.pop_front();
}
}
range;
}
def find(container, value) {
find(container, value, eq)
}
)chaiscript";
}
};
}
}
};
} // namespace chaiscript
#endif /* CHAISCRIPT_PRELUDE_HPP_ */

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,21 +1,16 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UNKNOWN_HPP_
#define CHAISCRIPT_UNKNOWN_HPP_
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
Loadable_Module(const std::string &, const std::string &)
{
namespace chaiscript {
namespace detail {
struct Loadable_Module {
Loadable_Module(const std::string &, const std::string &) {
#ifdef CHAISCRIPT_NO_DYNLOAD
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
#else
@ -25,7 +20,6 @@ namespace chaiscript
ModulePtr m_moduleptr;
};
}
}
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_WINDOWS_HPP_
@ -17,42 +17,33 @@
#include <windows.h>
#endif
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
namespace chaiscript {
namespace detail {
struct Loadable_Module {
template<typename T>
static std::wstring to_wstring(const T &t_str)
{
return std::wstring(t_str.begin(), t_str.end());
}
static std::wstring to_wstring(const T &t_str) {
return std::wstring(t_str.begin(), t_str.end());
}
template<typename T>
static std::string to_string(const T &t_str)
{
return std::string(t_str.begin(), t_str.end());
}
static std::string to_string(const T &t_str) {
return std::string(t_str.begin(), t_str.end());
}
#if defined(_UNICODE) || defined(UNICODE)
template<typename T>
static std::wstring to_proper_string(const T &t_str)
{
return to_wstring(t_str);
}
template<typename T>
static std::wstring to_proper_string(const T &t_str) {
return to_wstring(t_str);
}
#else
template<typename T>
static std::string to_proper_string(const T &t_str)
{
return to_string(t_str);
}
static std::string to_proper_string(const T &t_str) {
return to_string(t_str);
}
#endif
static std::string get_error_message(DWORD t_err)
{
typedef LPTSTR StringType;
static std::string get_error_message(DWORD t_err) {
using StringType = LPTSTR;
#if defined(_UNICODE) || defined(UNICODE)
std::wstring retval = L"Unknown Error";
@ -61,16 +52,15 @@ namespace chaiscript
#endif
StringType lpMsgBuf = nullptr;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<StringType>(&lpMsgBuf),
0, nullptr ) != 0 && lpMsgBuf)
{
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<StringType>(&lpMsgBuf),
0,
nullptr)
!= 0
&& lpMsgBuf) {
retval = lpMsgBuf;
LocalFree(lpMsgBuf);
}
@ -78,13 +68,10 @@ namespace chaiscript
return to_string(retval);
}
struct DLModule
{
struct DLModule {
explicit DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
{
if (!m_data)
{
: m_data(LoadLibrary(to_proper_string(t_filename).c_str())) {
if (!m_data) {
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
@ -94,40 +81,33 @@ namespace chaiscript
DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete;
~DLModule()
{
FreeLibrary(m_data);
}
~DLModule() { FreeLibrary(m_data); }
HMODULE m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
struct DLSym {
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) {
if (!m_symbol) {
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
T m_symbol;
};
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
: m_dlmodule(t_filename)
, m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name)
, m_moduleptr(m_func.m_symbol()) {
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
}
}
#endif
} // namespace detail
} // namespace chaiscript
#endif

View File

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

View File

@ -0,0 +1,94 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include "../chaiscript_defines.hpp"
#include <cstdint>
namespace chaiscript {
namespace utility {
namespace fnv1a {
template<typename Itr>
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
std::uint32_t h = 0x811c9dc5;
while (begin != end) {
h = (h ^ (*begin)) * 0x01000193;
++begin;
}
return h;
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str) - 1);
}
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
return hash(sv.begin(), sv.end());
}
static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end());
}
} // namespace fnv1a
namespace jenkins_one_at_a_time {
template<typename Itr>
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
std::uint32_t hash = 0;
while (begin != end) {
hash += std::uint32_t(*begin);
hash += hash << 10;
hash ^= hash >> 6;
++begin;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;
}
template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str) - 1);
}
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
return hash(sv.begin(), sv.end());
}
static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end());
}
} // namespace jenkins_one_at_a_time
using fnv1a::hash;
} // namespace utility
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -0,0 +1,49 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_STACK_VECTOR_HPP_
#define CHAISCRIPT_STACK_VECTOR_HPP_
#include <cstdint>
#include <string>
#include <type_traits>
template<typename T, std::size_t MaxSize>
struct Stack_Vector {
constexpr static auto aligned_size = sizeof(T) + (sizeof(T) & std::alignment_of_v<T>) > 0 ? std::alignment_of_v<T> : 0;
alignas(std::alignment_of_v<T>) char data[aligned_size * MaxSize];
[[nodiscard]] T &operator[](const std::size_t idx) noexcept { return *reinterpret_cast<T *>(&data + aligned_size * idx); }
[[nodiscard]] const T &operator[](const std::size_t idx) const noexcept {
return *reinterpret_cast<const T *>(&data + aligned_size * idx);
}
template<typename... Param>
T &emplace_back(Param &&...param) {
auto *p = new (&(*this)[m_size++]) T(std::forward<Param>(param)...);
return *p;
};
auto size() const noexcept { return m_size; };
void pop_back() noexcept(std::is_nothrow_destructible_v<T>) { (*this)[--m_size].~T(); }
~Stack_Vector() noexcept(std::is_nothrow_destructible_v<T>) {
auto loc = m_size - 1;
for (std::size_t pos = 0; pos < m_size; ++pos) {
(*this)[loc--].~T();
}
}
std::size_t m_size{0};
};
#endif CHAISCRIPT_STACK_VECTOR_HPP_

View File

@ -1,37 +1,54 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
namespace chaiscript
{
namespace utility
{
namespace chaiscript::utility {
struct Static_String {
template<size_t N>
constexpr Static_String(const char (&str)[N]) noexcept
: m_size(N - 1)
, data(&str[0]) {
}
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 noexcept { return m_size; }
constexpr const char *c_str() const noexcept { return data; }
constexpr auto begin() const noexcept { return data; }
constexpr auto end() const noexcept { return data + m_size; }
constexpr bool operator==(std::string_view other) const noexcept {
// return std::string_view(data, m_size) == other;
auto b1 = begin();
const auto e1 = end();
auto b2 = other.begin();
const auto e2 = other.end();
if (e1 - b1 != e2 - b2) {
return false;
}
while (b1 != e1) {
if (*b1 != *b2) {
return false;
}
constexpr size_t size() const {
return m_size;
++b1;
++b2;
}
return true;
}
constexpr const char *c_str() const {
return data;
}
bool operator==(const std::string &t_str) const noexcept { return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str)); }
const size_t m_size;
const char *data = nullptr;
};
}
}
const size_t m_size;
const char *data = nullptr;
};
} // namespace chaiscript::utility
#endif

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
@ -16,108 +15,90 @@
#include <utility>
#include <vector>
#include "../language/chaiscript_common.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../dispatchkit/operators.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../language/chaiscript_common.hpp"
namespace chaiscript::utility {
/// Single step command for registering a class with ChaiScript
///
/// \param[in,out] t_module Model to add class to
/// \param[in] t_class_name Name of the class being registered
/// \param[in] t_constructors Vector of constructors to add
/// \param[in] t_funcs Vector of methods to add
///
/// \example Adding a basic class to ChaiScript in one step
///
/// \code
/// chaiscript::utility::add_class<test>(*m,
/// "test",
/// { constructor<test ()>(),
/// constructor<test (const test &)>() },
/// { {fun(&test::function), "function"},
/// {fun(&test::function2), "function2"},
/// {fun(&test::function3), "function3"},
/// {fun(static_cast<std::string(test::*)(double)>(&test::function_overload)), "function_overload" },
/// {fun(static_cast<std::string(test::*)(int)>(&test::function_overload)), "function_overload" },
/// {fun(static_cast<test & (test::*)(const test &)>(&test::operator=)), "=" }
/// }
/// );
///
template<typename Class, typename ModuleType>
void add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<chaiscript::Proxy_Function> &t_constructors,
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs) {
t_module.add(chaiscript::user_type<Class>(), t_class_name);
namespace chaiscript
{
namespace utility
{
for (const chaiscript::Proxy_Function &ctor : t_constructors) {
t_module.add(ctor, t_class_name);
}
/// Single step command for registering a class with ChaiScript
///
/// \param[in,out] t_module Model to add class to
/// \param[in] t_class_name Name of the class being registered
/// \param[in] t_constructors Vector of constructors to add
/// \param[in] t_funcs Vector of methods to add
///
/// \example Adding a basic class to ChaiScript in one step
///
/// \code
/// chaiscript::utility::add_class<test>(*m,
/// "test",
/// { constructor<test ()>(),
/// constructor<test (const test &)>() },
/// { {fun(&test::function), "function"},
/// {fun(&test::function2), "function2"},
/// {fun(&test::function3), "function3"},
/// {fun(static_cast<std::string(test::*)(double)>(&test::function_overload)), "function_overload" },
/// {fun(static_cast<std::string(test::*)(int)>(&test::function_overload)), "function_overload" },
/// {fun(static_cast<test & (test::*)(const test &)>(&test::operator=)), "=" }
/// }
/// );
///
template<typename Class, typename ModuleType>
void add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<chaiscript::Proxy_Function> &t_constructors,
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs)
{
t_module.add(chaiscript::user_type<Class>(), t_class_name);
for(const chaiscript::Proxy_Function &ctor: t_constructors)
{
t_module.add(ctor, t_class_name);
}
for(const auto &fun: t_funcs)
{
t_module.add(fun.first, fun.second);
}
}
template<typename Enum, typename ModuleType>
typename std::enable_if<std::is_enum<Enum>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants
)
{
t_module.add(chaiscript::user_type<Enum>(), t_class_name);
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name);
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<Enum>(t_module);
not_equal<Enum>(t_module);
assign<Enum>(t_module);
t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "==");
t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "==");
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
}
}
template<typename EnumClass, typename ModuleType>
typename std::enable_if<std::is_enum<EnumClass>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<EnumClass, std::string>> &t_constants
)
{
t_module.add(chaiscript::user_type<EnumClass>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass(const EnumClass &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<EnumClass>(t_module);
not_equal<EnumClass>(t_module);
assign<EnumClass>(t_module);
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second);
}
}
for (const auto &fun : t_funcs) {
t_module.add(fun.first, fun.second);
}
}
}
template<typename Enum, typename ModuleType>
typename std::enable_if<std::is_enum<Enum>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants) {
t_module.add(chaiscript::user_type<Enum>(), t_class_name);
t_module.add(chaiscript::constructor<Enum()>(), t_class_name);
t_module.add(chaiscript::constructor<Enum(const Enum &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<Enum>(t_module);
not_equal<Enum>(t_module);
assign<Enum>(t_module);
t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "==");
t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "==");
for (const auto &constant : t_constants) {
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
}
}
template<typename EnumClass, typename ModuleType>
typename std::enable_if<std::is_enum<EnumClass>::value, void>::type
add_class(ModuleType &t_module, const std::string &t_class_name, const std::vector<std::pair<EnumClass, std::string>> &t_constants) {
t_module.add(chaiscript::user_type<EnumClass>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass(const EnumClass &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<EnumClass>(t_module);
not_equal<EnumClass>(t_module);
assign<EnumClass>(t_module);
for (const auto &constant : t_constants) {
t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second);
}
}
} // namespace chaiscript::utility
#endif

View File

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

View File

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

View File

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

View File

@ -29,7 +29,7 @@ Introduction
ChaiScript is one of the only embedded scripting language designed from the
ground up to directly target C++ and take advantage of modern C++ development
techniques, working with the developer like he expects it to work. Being a
techniques, working with the developer how they would expect it to work. Being a
native C++ application, it has some advantages over existing embedded scripting
languages:
@ -48,6 +48,19 @@ templates. It has been tested with gcc 4.9 and clang 3.6 (with libcxx).
For more information see the build
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
Installation using vcpkg
========================
You can download and install ChaiScript using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install chaiscript
The ChaiScript port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
Usage
=====

View File

@ -1,6 +1,13 @@
Notes:
=======
Current Version: 6.1.0
Current Version: 6.1.1
### Changes since 6.1.0
* Handle the returning of `&` to `*` types. This specifically comes up with `std::vector<int *>` and similar containers
* Update CMake to use `LIBDIR` instead of `lib` #502 by @guoyunhe
* Add documentation for installing ChaiScript with vcpkg #500 by @grdowns
* Fix warning for implicit 'this' lambda capture in C++20 #495 by @Josh-Thompson
### Changes since 6.0.0
@ -14,7 +21,6 @@ Current Version: 6.1.0
* Support for C++17 compilers!
* Support for UTF8 BOM #439 @AlekMosingiewicz @MarioLiebisch
### Changes since 5.8.6
*6.0.0 is a massive rework compared to 5.x. It now requires a C++14 enabled compiler*

View File

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

View File

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

View File

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

View File

@ -3,12 +3,10 @@
#include <chaiscript/chaiscript.hpp>
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#include <readline/readline.h>
#endif
std::string get_next_command() {
#ifdef READLINE_AVAILABLE
char *input_raw;
@ -23,42 +21,32 @@ std::string get_next_command() {
#endif
}
void function(void)
{
void function(void) {
// do nothing
}
class test
{
class test {
chaiscript::ChaiScript chai;
chaiscript::ChaiScript::State backupState = chai.get_state();
public:
void ResetState()
{
public:
void ResetState() {
chai.set_state(backupState);
chai.add(chaiscript::fun(&function),"Whatever()");
chai.add(chaiscript::fun(&function), "Whatever()");
}
void RunFile(std::string sFile)
{
void RunFile(std::string sFile) {
try {
chaiscript::Boxed_Value val = chai.eval_file(sFile);
}
catch (std::exception &e) {
} catch (std::exception &e) {
std::cout << e.what() << '\n';
}
}
};
int main(int /*argc*/, char * /*argv*/[]) {
test myChai;
std::string command = "";
//
@ -70,12 +58,11 @@ int main(int /*argc*/, char * /*argv*/[]) {
// scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as
// low as in case 1 scenario3 :
while(command != "quit")
{
for(int i = 1; i < 200; i++)
while (command != "quit") {
for (int i = 1; i < 200; i++)
myChai.ResetState();
if(command == "runfile")
if (command == "runfile")
myChai.RunFile("Test.chai");
command = get_next_command();

View File

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

View File

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

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <iostream>
#include <list>
#include <regex>
@ -16,49 +15,45 @@
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <chaiscript/chaiscript.hpp>
#include "../static_libs/chaiscript_parser.hpp"
#include "../static_libs/chaiscript_stdlib.hpp"
#include <chaiscript/chaiscript.hpp>
#include "sha3.h"
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#include <readline/readline.h>
#else
char *mystrdup (const char *s) {
char *mystrdup(const char *s) {
size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char*>(malloc (len+1));
if (d == nullptr) { return nullptr; } // No memory
char *d = static_cast<char *>(malloc(len + 1));
if (d == nullptr) {
return nullptr;
} // No memory
#ifdef CHAISCRIPT_MSVC
strcpy_s(d, len+1, s); // Copy the characters
strcpy_s(d, len + 1, s); // Copy the characters
#else
strncpy(d,s,len); // Copy the characters
strncpy(d, s, len); // Copy the characters
#endif
d[len] = '\0';
return d; // Return the new string
return d; // Return the new string
}
char* readline(const char* p)
{
char *readline(const char *p) {
std::string retval;
std::cout << p ;
std::cout << p;
std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
}
void add_history(const char* /*unused*/){}
void using_history(){}
void add_history(const char * /*unused*/) {}
void using_history() {}
#endif
void *cast_module_symbol(std::vector<std::string> (*t_path)())
{
union cast_union
{
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
union cast_union {
std::vector<std::string> (*in_ptr)();
void *out_ptr;
};
@ -68,26 +63,23 @@ void *cast_module_symbol(std::vector<std::string> (*t_path)())
return c.out_ptr;
}
std::vector<std::string> default_search_paths()
{
std::vector<std::string> default_search_paths() {
std::vector<std::string> paths;
#ifndef CHAISCRIPT_NO_DYNLOAD
#ifdef CHAISCRIPT_WINDOWS // force no unicode
#ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096];
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
int size = GetModuleFileNameA(nullptr, path, sizeof(path) - 1);
std::string exepath(path, size);
size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos)
{
if (lastslash != std::string::npos) {
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
if (secondtolastslash != std::string::npos) {
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
}
#else
@ -97,32 +89,26 @@ std::vector<std::string> default_search_paths()
std::vector<char> buf(2048);
ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0)
{
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0) {
exepath = std::string(&buf.front(), static_cast<size_t>(size));
}
if (exepath.empty())
{
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
{
if (exepath.empty()) {
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) {
exepath = std::string(&buf.front(), static_cast<size_t>(size));
}
}
if (exepath.empty())
{
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
{
if (exepath.empty()) {
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) {
exepath = std::string(&buf.front(), static_cast<size_t>(size));
}
}
if (exepath.empty())
{
if (exepath.empty()) {
Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) );
if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) {
memset(&rInfo, 0, sizeof(rInfo));
if (dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr) {
return paths;
}
@ -132,13 +118,11 @@ std::vector<std::string> default_search_paths()
size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash+1));
if (lastslash != std::string::npos) {
paths.push_back(exepath.substr(0, lastslash + 1));
}
if (secondtolastslash != std::string::npos)
{
if (secondtolastslash != std::string::npos) {
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
}
#endif
@ -148,25 +132,24 @@ std::vector<std::string> default_search_paths()
}
void help(int n) {
if ( n >= 0 ) {
if (n >= 0) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
std::cout << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system\n";
std::cout << " dump_object(x) - dumps information about the given symbol\n";
} else {
std::cout << "usage : chai [option]+\n";
std::cout << "option:" << '\n';
std::cout << " -h | --help" << '\n';
std::cout << " -i | --interactive" << '\n';
std::cout << " -c | --command cmd" << '\n';
std::cout << " -v | --version" << '\n';
std::cout << " - --stdin" << '\n';
std::cout << " filepath" << '\n';
std::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)
{
bool throws_exception(const std::function<void()> &f) {
try {
f();
} catch (...) {
@ -176,8 +159,7 @@ bool throws_exception(const std::function<void ()> &f)
return false;
}
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
{
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) {
try {
f();
} catch (const chaiscript::exception::eval_error &e) {
@ -189,21 +171,19 @@ chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f
std::string get_next_command() {
std::string retval("quit");
if ( ! std::cin.eof() ) {
if (!std::cin.eof()) {
char *input_raw = readline("eval> ");
if ( input_raw != nullptr ) {
if (input_raw != nullptr) {
add_history(input_raw);
std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos)
{
if (pos != std::string::npos) {
val.erase(0, pos);
}
pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(pos+1, std::string::npos);
if (pos != std::string::npos) {
val.erase(pos + 1, std::string::npos);
}
retval = val;
@ -211,11 +191,7 @@ std::string get_next_command() {
::free(input_raw);
}
}
if( retval == "quit"
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") {
retval += "(0)";
}
return retval;
@ -227,8 +203,7 @@ void myexit(int return_val) {
exit(return_val);
}
void interactive(chaiscript::ChaiScript_Basic& chai)
{
void interactive(chaiscript::ChaiScript_Basic &chai) {
using_history();
for (;;) {
@ -237,30 +212,27 @@ void interactive(chaiscript::ChaiScript_Basic& chai)
// evaluate input
chaiscript::Boxed_Value val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user
// Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try {
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
}
catch (...) {} //If we can't, do nothing
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) {
} catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what();
if ( !ee.call_stack.empty() ) {
if (!ee.call_stack.empty()) {
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
}
std::cout << '\n';
}
catch (const std::exception &e) {
} catch (const std::exception &e) {
std::cout << e.what();
std::cout << '\n';
}
}
}
double now()
{
double now() {
using namespace std::chrono;
auto now = high_resolution_clock::now();
return duration_cast<duration<double>>(now.time_since_epoch()).count();
@ -269,7 +241,7 @@ double now()
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
chaiscript::ChaiScript chai;
chai.eval( R"chaiscript(
chai.eval(R"chaiscript(
def assert_equal(x, y)
{
if (x == y)
@ -339,7 +311,8 @@ def assert_throws(desc, x)
std::ofstream ofs("BOXED_VALUE/" + sha);
ofs << input;
} catch (const chaiscript::exception::load_module_error &e) {
std::cout << "Unhandled module load error\n" << e.what() << '\n';
std::cout << "Unhandled module load error\n"
<< e.what() << '\n';
} catch (const std::exception &) {
std::ofstream ofs("STD_EXCEPTION/" + sha);
ofs << input;
@ -350,5 +323,3 @@ def assert_throws(desc, x)
return 0;
}

View File

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

View File

@ -4,62 +4,52 @@
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <iostream>
// NOT TO BE USED AS A SOURCE OF BEST PRACTICES
// FOR CHAISCRIPT
#include <ctime>
#include <iostream>
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp>
void log(const std::string &msg)
{
void log(const std::string &msg) {
std::cout << "[" << time(nullptr) << "] " << msg << '\n';
}
void log(const std::string &module, const std::string &msg)
{
void log(const std::string &module, const std::string &msg) {
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n';
}
void bound_log(const std::string &msg)
{
void bound_log(const std::string &msg) {
log(msg);
}
void hello_world(const chaiscript::Boxed_Value & /*o*/)
{
void hello_world(const chaiscript::Boxed_Value & /*o*/) {
std::cout << "Hello World\n";
}
void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
{
void hello_constructor(const chaiscript::Boxed_Value & /*o*/) {
std::cout << "Hello Constructor\n";
}
struct System {
std::map<std::string, std::function<std::string(const std::string &)>> m_callbacks;
struct System
{
std::map<std::string, std::function<std::string (const std::string &) > > m_callbacks;
void add_callback(const std::string &t_name,
const std::function<std::string (const std::string &)> &t_func)
{
void add_callback(const std::string &t_name, const std::function<std::string(const std::string &)> &t_func) {
m_callbacks[t_name] = t_func;
}
void do_callbacks(const std::string &inp)
{
void do_callbacks(const std::string &inp) {
log("Running Callbacks: " + inp);
for (auto & m_callback : m_callbacks)
{
for (auto &m_callback : m_callbacks) {
log("Callback: " + m_callback.first, m_callback.second(inp));
}
}
};
void take_shared_ptr(const std::shared_ptr<const std::string> &p)
{
void take_shared_ptr(const std::shared_ptr<const std::string> &p) {
std::cout << *p << '\n';
}
@ -67,27 +57,26 @@ int main(int /*argc*/, char * /*argv*/[]) {
using namespace chaiscript;
ChaiScript chai;
//Create a new system object and share it with the chaiscript engine
// Create a new system object and share it with the chaiscript engine
System system;
chai.add_global(var(&system), "system");
//Add a bound callback method
// Add a bound callback method
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
//Register the two methods of the System structure.
// Register the two methods of the System structure.
chai.add(fun(&System::add_callback), "add_callback");
chai.add(fun(&System::do_callbacks), "do_callbacks");
chai.add(fun(&take_shared_ptr), "take_shared_ptr");
// Let's use chaiscript to add a new lambda callback to our system.
// Let's use chaiscript to add a new lambda callback to our system.
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
// in the "add_callback" function of struct System the chaiscript function is converted into a
// in the "add_callback" function of struct System the chaiscript function is converted into a
// std::function, so it can be handled and called easily and type-safely
chai.eval(R"(system.add_callback("#1", fun(x) { "Callback1 " + x });)");
// Because we are sharing the "system" object with the chaiscript engine we have equal
// access to it both from within chaiscript and from C++ code
system.do_callbacks("TestString");
@ -106,29 +95,26 @@ int main(int /*argc*/, char * /*argv*/[]) {
// A shortcut to using eval is just to use the chai operator()
chai(R"(log("Test Module", "Test Message");)");
//Finally, it is possible to register a lambda as a system function, in this
//way, we can, for instance add a bound member function to the system
chai.add(fun([&system](){ return system.do_callbacks("Bound Test"); }), "do_callbacks");
// Finally, it is possible to register a lambda as a system function, in this
// way, we can, for instance add a bound member function to the system
chai.add(fun([&system]() { return system.do_callbacks("Bound Test"); }), "do_callbacks");
//Call bound version of do_callbacks
// Call bound version of do_callbacks
chai("do_callbacks()");
std::function<void ()> caller = chai.eval<std::function<void ()> >(
R"(fun() { system.do_callbacks("From Functor"); })"
);
std::function<void()> caller = chai.eval<std::function<void()>>(R"(fun() { system.do_callbacks("From Functor"); })");
caller();
//If we would like a type-safe return value from all call, we can use
//the templated version of eval:
// If we would like a type-safe return value from all call, we can use
// the templated version of eval:
int i = chai.eval<int>("5+5");
std::cout << "5+5: " << i << '\n';
//Add a new variable
// Add a new variable
chai("var scripti = 15");
//We can even get a handle to the variables in the system
// We can even get a handle to the variables in the system
int &scripti = chai.eval<int &>("scripti");
std::cout << "scripti: " << scripti << '\n';
@ -136,10 +122,10 @@ int main(int /*argc*/, char * /*argv*/[]) {
std::cout << "scripti (updated): " << scripti << '\n';
chai(R"(print("Scripti from chai: " + to_string(scripti)))");
//To do: Add examples of handling Boxed_Values directly when needed
// To do: Add examples of handling Boxed_Values directly when needed
//Creating a functor on the stack and using it immediately
int x = chai.eval<std::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
// Creating a functor on the stack and using it immediately
int x = chai.eval<std::function<int(int, int)>>("fun (x, y) { return x + y; }")(5, 6);
std::stringstream ss;
ss << x;
@ -153,25 +139,23 @@ int main(int /*argc*/, char * /*argv*/[]) {
chai("def getvar() { return constvar; }");
chai("print( getvar() )");
//Ability to create our own container types when needed. std::vector and std::map are
//mostly supported currently
chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
// Ability to create our own container types when needed. std::vector and std::map are
// mostly supported currently
// chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
// Test ability to register a function that excepts a shared_ptr version of a type
chai(R"(take_shared_ptr("Hello World as a shared_ptr");)");
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
//Dynamic objects test
// Dynamic objects test
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr");
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func,
// "TestType", "attr", std::placeholders::_1))), "attr");
chai.eval("var x = TestType()");
// chai.eval("x.attr = \"hi\"");
// chai.eval("print(x.attr)");
// chai.eval("x.attr = \"hi\"");
// chai.eval("print(x.attr)");
chai.eval("x.hello_world()");
}

View File

@ -11,52 +11,35 @@
#include <endian.h>
#endif
/// same as reset()
SHA3::SHA3(Bits bits)
: m_blockSize(200 - 2 * (bits / 8)),
m_bits(bits)
{
: m_blockSize(200 - 2 * (bits / 8))
, m_bits(bits) {
reset();
}
/// restart
void SHA3::reset()
{
void SHA3::reset() {
for (size_t i = 0; i < StateSize; i++)
m_hash[i] = 0;
m_numBytes = 0;
m_numBytes = 0;
m_bufferSize = 0;
}
/// constants and local helper functions
namespace
{
namespace {
const unsigned int Rounds = 24;
const uint64_t XorMasks[Rounds] =
{
0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
};
const uint64_t XorMasks[Rounds]
= {0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL};
/// rotate left and wrap around to the right
inline uint64_t rotateLeft(uint64_t x, uint8_t numBits)
{
inline uint64_t rotateLeft(uint64_t x, uint8_t numBits) {
return (x << numBits) | (x >> (64 - numBits));
}
/// convert litte vs big endian
inline uint64_t swap(uint64_t x)
{
inline uint64_t swap(uint64_t x) {
#if defined(__GNUC__) || defined(__clang__)
return __builtin_bswap64(x);
#endif
@ -64,55 +47,43 @@ namespace
return _byteswap_uint64(x);
#endif
return (x >> 56) |
((x >> 40) & 0x000000000000FF00ULL) |
((x >> 24) & 0x0000000000FF0000ULL) |
((x >> 8) & 0x00000000FF000000ULL) |
((x << 8) & 0x000000FF00000000ULL) |
((x << 24) & 0x0000FF0000000000ULL) |
((x << 40) & 0x00FF000000000000ULL) |
(x << 56);
return (x >> 56) | ((x >> 40) & 0x000000000000FF00ULL) | ((x >> 24) & 0x0000000000FF0000ULL) | ((x >> 8) & 0x00000000FF000000ULL)
| ((x << 8) & 0x000000FF00000000ULL) | ((x << 24) & 0x0000FF0000000000ULL) | ((x << 40) & 0x00FF000000000000ULL) | (x << 56);
}
/// return x % 5 for 0 <= x <= 9
unsigned int mod5(unsigned int x)
{
unsigned int mod5(unsigned int x) {
if (x < 5)
return x;
return x - 5;
}
}
} // namespace
/// process a full block
void SHA3::processBlock(const void* data)
{
void SHA3::processBlock(const void *data) {
#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
#define LITTLEENDIAN(x) swap(x)
#else
#define LITTLEENDIAN(x) (x)
#endif
const uint64_t* data64 = (const uint64_t*) data;
const uint64_t *data64 = (const uint64_t *)data;
// mix data into state
for (unsigned int i = 0; i < m_blockSize / 8; i++)
m_hash[i] ^= LITTLEENDIAN(data64[i]);
// re-compute state
for (unsigned int round = 0; round < Rounds; round++)
{
for (unsigned int round = 0; round < Rounds; round++) {
// Theta
uint64_t coefficients[5];
for (unsigned int i = 0; i < 5; i++)
coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20];
for (unsigned int i = 0; i < 5; i++)
{
for (unsigned int i = 0; i < 5; i++) {
uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1);
m_hash[i ] ^= one;
m_hash[i + 5] ^= one;
m_hash[i] ^= one;
m_hash[i + 5] ^= one;
m_hash[i + 10] ^= one;
m_hash[i + 15] ^= one;
m_hash[i + 20] ^= one;
@ -123,43 +94,88 @@ void SHA3::processBlock(const void* data)
// Rho Pi
uint64_t last = m_hash[1];
one = m_hash[10]; m_hash[10] = rotateLeft(last, 1); last = one;
one = m_hash[ 7]; m_hash[ 7] = rotateLeft(last, 3); last = one;
one = m_hash[11]; m_hash[11] = rotateLeft(last, 6); last = one;
one = m_hash[17]; m_hash[17] = rotateLeft(last, 10); last = one;
one = m_hash[18]; m_hash[18] = rotateLeft(last, 15); last = one;
one = m_hash[ 3]; m_hash[ 3] = rotateLeft(last, 21); last = one;
one = m_hash[ 5]; m_hash[ 5] = rotateLeft(last, 28); last = one;
one = m_hash[16]; m_hash[16] = rotateLeft(last, 36); last = one;
one = m_hash[ 8]; m_hash[ 8] = rotateLeft(last, 45); last = one;
one = m_hash[21]; m_hash[21] = rotateLeft(last, 55); last = one;
one = m_hash[24]; m_hash[24] = rotateLeft(last, 2); last = one;
one = m_hash[ 4]; m_hash[ 4] = rotateLeft(last, 14); last = one;
one = m_hash[15]; m_hash[15] = rotateLeft(last, 27); last = one;
one = m_hash[23]; m_hash[23] = rotateLeft(last, 41); last = one;
one = m_hash[19]; m_hash[19] = rotateLeft(last, 56); last = one;
one = m_hash[13]; m_hash[13] = rotateLeft(last, 8); last = one;
one = m_hash[12]; m_hash[12] = rotateLeft(last, 25); last = one;
one = m_hash[ 2]; m_hash[ 2] = rotateLeft(last, 43); last = one;
one = m_hash[20]; m_hash[20] = rotateLeft(last, 62); last = one;
one = m_hash[14]; m_hash[14] = rotateLeft(last, 18); last = one;
one = m_hash[22]; m_hash[22] = rotateLeft(last, 39); last = one;
one = m_hash[ 9]; m_hash[ 9] = rotateLeft(last, 61); last = one;
one = m_hash[ 6]; m_hash[ 6] = rotateLeft(last, 20); last = one;
m_hash[ 1] = rotateLeft(last, 44);
one = m_hash[10];
m_hash[10] = rotateLeft(last, 1);
last = one;
one = m_hash[7];
m_hash[7] = rotateLeft(last, 3);
last = one;
one = m_hash[11];
m_hash[11] = rotateLeft(last, 6);
last = one;
one = m_hash[17];
m_hash[17] = rotateLeft(last, 10);
last = one;
one = m_hash[18];
m_hash[18] = rotateLeft(last, 15);
last = one;
one = m_hash[3];
m_hash[3] = rotateLeft(last, 21);
last = one;
one = m_hash[5];
m_hash[5] = rotateLeft(last, 28);
last = one;
one = m_hash[16];
m_hash[16] = rotateLeft(last, 36);
last = one;
one = m_hash[8];
m_hash[8] = rotateLeft(last, 45);
last = one;
one = m_hash[21];
m_hash[21] = rotateLeft(last, 55);
last = one;
one = m_hash[24];
m_hash[24] = rotateLeft(last, 2);
last = one;
one = m_hash[4];
m_hash[4] = rotateLeft(last, 14);
last = one;
one = m_hash[15];
m_hash[15] = rotateLeft(last, 27);
last = one;
one = m_hash[23];
m_hash[23] = rotateLeft(last, 41);
last = one;
one = m_hash[19];
m_hash[19] = rotateLeft(last, 56);
last = one;
one = m_hash[13];
m_hash[13] = rotateLeft(last, 8);
last = one;
one = m_hash[12];
m_hash[12] = rotateLeft(last, 25);
last = one;
one = m_hash[2];
m_hash[2] = rotateLeft(last, 43);
last = one;
one = m_hash[20];
m_hash[20] = rotateLeft(last, 62);
last = one;
one = m_hash[14];
m_hash[14] = rotateLeft(last, 18);
last = one;
one = m_hash[22];
m_hash[22] = rotateLeft(last, 39);
last = one;
one = m_hash[9];
m_hash[9] = rotateLeft(last, 61);
last = one;
one = m_hash[6];
m_hash[6] = rotateLeft(last, 20);
last = one;
m_hash[1] = rotateLeft(last, 44);
// Chi
for (unsigned int j = 0; j < 25; j += 5)
{
for (unsigned int j = 0; j < 25; j += 5) {
// temporaries
uint64_t one = m_hash[j];
uint64_t two = m_hash[j + 1];
m_hash[j] ^= m_hash[j + 2] & ~two;
m_hash[j] ^= m_hash[j + 2] & ~two;
m_hash[j + 1] ^= m_hash[j + 3] & ~m_hash[j + 2];
m_hash[j + 2] ^= m_hash[j + 4] & ~m_hash[j + 3];
m_hash[j + 3] ^= one & ~m_hash[j + 4];
m_hash[j + 4] ^= two & ~one;
m_hash[j + 3] ^= one & ~m_hash[j + 4];
m_hash[j + 4] ^= two & ~one;
}
// Iota
@ -167,27 +183,22 @@ void SHA3::processBlock(const void* data)
}
}
/// add arbitrary number of bytes
void SHA3::add(const void* data, size_t numBytes)
{
const uint8_t* current = (const uint8_t*) data;
void SHA3::add(const void *data, size_t numBytes) {
const uint8_t *current = (const uint8_t *)data;
// copy data to buffer
if (m_bufferSize > 0)
{
while (numBytes > 0 && m_bufferSize < m_blockSize)
{
if (m_bufferSize > 0) {
while (numBytes > 0 && m_bufferSize < m_blockSize) {
m_buffer[m_bufferSize++] = *current++;
numBytes--;
}
}
// full buffer
if (m_bufferSize == m_blockSize)
{
processBlock((void*)m_buffer);
m_numBytes += m_blockSize;
if (m_bufferSize == m_blockSize) {
processBlock((void *)m_buffer);
m_numBytes += m_blockSize;
m_bufferSize = 0;
}
@ -196,26 +207,22 @@ void SHA3::add(const void* data, size_t numBytes)
return;
// process full blocks
while (numBytes >= m_blockSize)
{
while (numBytes >= m_blockSize) {
processBlock(current);
current += m_blockSize;
current += m_blockSize;
m_numBytes += m_blockSize;
numBytes -= m_blockSize;
numBytes -= m_blockSize;
}
// keep remaining bytes in buffer
while (numBytes > 0)
{
while (numBytes > 0) {
m_buffer[m_bufferSize++] = *current++;
numBytes--;
}
}
/// process everything left in the internal buffer
void SHA3::processBuffer()
{
void SHA3::processBuffer() {
// add padding
size_t offset = m_bufferSize;
// add a "1" byte
@ -230,10 +237,8 @@ void SHA3::processBuffer()
processBlock(m_buffer);
}
/// return latest hash as 16 hex characters
std::string SHA3::getHash()
{
std::string SHA3::getHash() {
// process remaining bytes
processBuffer();
@ -249,7 +254,7 @@ std::string SHA3::getHash()
for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes
{
// convert a byte to hex
unsigned char oneByte = (unsigned char) (m_hash[i] >> (8 * j));
unsigned char oneByte = (unsigned char)(m_hash[i] >> (8 * j));
result += dec2hex[oneByte >> 4];
result += dec2hex[oneByte & 15];
}
@ -257,10 +262,9 @@ std::string SHA3::getHash()
// SHA3-224's last entry in m_hash provides only 32 bits instead of 64 bits
unsigned int remainder = m_bits - hashLength * 64;
unsigned int processed = 0;
while (processed < remainder)
{
while (processed < remainder) {
// convert a byte to hex
unsigned char oneByte = (unsigned char) (m_hash[hashLength] >> processed);
unsigned char oneByte = (unsigned char)(m_hash[hashLength] >> processed);
result += dec2hex[oneByte >> 4];
result += dec2hex[oneByte & 15];
@ -270,19 +274,15 @@ std::string SHA3::getHash()
return result;
}
/// compute SHA3 of a memory block
std::string SHA3::operator()(const void* data, size_t numBytes)
{
std::string SHA3::operator()(const void *data, size_t numBytes) {
reset();
add(data, numBytes);
return getHash();
}
/// compute SHA3 of a string, excluding final zero
std::string SHA3::operator()(const std::string& text)
{
std::string SHA3::operator()(const std::string &text) {
reset();
add(text.c_str(), text.size());
return getHash();

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <chaiscript/chaiscript_basic.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <list>
@ -25,11 +24,10 @@
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
{
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra() {
auto module = std::make_shared<chaiscript::Module>();
chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List", *module);
chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t> >("u16vector", *module);
chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value>>("List", *module);
chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t>>("u16vector", *module);
module->add(chaiscript::vector_conversion<std::vector<uint16_t>>());
return module;
}

View File

@ -3,133 +3,121 @@
#include <chaiscript/dispatchkit/bootstrap.hpp>
#include <string>
class TestBaseType {
public:
TestBaseType()
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(int)
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(int *)
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(const TestBaseType &other)
: val(other.val)
, const_val(other.const_val)
, const_val_ptr(&const_val)
, func_member(other.func_member) {
}
class TestBaseType
{
public:
TestBaseType() : val(10), const_val(15), mdarray{} { }
TestBaseType(int) : val(10), const_val(15), mdarray{} { }
TestBaseType(int *) : val(10), const_val(15), mdarray{} { }
TestBaseType(TestBaseType &&other)
: val(other.val)
, const_val(other.const_val)
, const_val_ptr(&const_val)
, func_member(std::move(other.func_member)) {
}
TestBaseType(const TestBaseType &) = default;
virtual ~TestBaseType() {}
virtual int func() { return 0; }
TestBaseType &operator=(TestBaseType &&) = delete;
TestBaseType &operator=(const TestBaseType &) = delete;
int base_only_func() { return -9; }
virtual ~TestBaseType() = default;
virtual int func() { return 0; }
const TestBaseType &constMe() const { return *this; }
int base_only_func() { return -9; }
int val;
const int const_val;
const int *const_val_ptr = &const_val;
const TestBaseType &constMe() const { return *this; }
const int *get_const_val_ptr() {
return const_val_ptr;
}
int val;
const int const_val;
const int *const_val_ptr = &const_val;
int mdarray[2][3][5];
std::function<int (int)> func_member;
const int *get_const_val_ptr() { return const_val_ptr; }
void set_string_val(std::string &t_str)
{
t_str = "42";
}
int mdarray[2][3][5];
std::function<int(int)> func_member;
private:
TestBaseType &operator=(const TestBaseType &) = delete;
void set_string_val(std::string &t_str) { t_str = "42"; }
};
class Type2
{
public:
Type2(TestBaseType t_bt)
: m_bt(std::move(t_bt)),
m_str("Hello World")
{
}
class Type2 {
public:
Type2(TestBaseType t_bt)
: m_bt(std::move(t_bt))
, m_str("Hello World") {
}
int get_val() const
{
return m_bt.val;
}
int get_val() const { return m_bt.val; }
const char *get_str() const { return m_str.c_str(); }
const char *get_str() const
{
return m_str.c_str();
}
private:
TestBaseType m_bt;
std::string m_str;
private:
TestBaseType m_bt;
std::string m_str;
};
enum TestEnum
{
enum TestEnum {
TestValue1 = 1
};
int to_int(TestEnum t)
{
int to_int(TestEnum t) {
return t;
}
class TestDerivedType : public TestBaseType
{
public:
~TestDerivedType() override {}
TestDerivedType(const TestDerivedType &) = default;
TestDerivedType() = default;
virtual int func() override { return 1; }
int derived_only_func() { return 19; }
private:
TestDerivedType &operator=(const TestDerivedType &) = delete;
class TestDerivedType : public TestBaseType {
public:
int func() override { return 1; }
int derived_only_func() { return 19; }
};
class TestMoreDerivedType : public TestDerivedType
{
public:
TestMoreDerivedType(const TestMoreDerivedType &) = default;
TestMoreDerivedType() = default;
virtual ~TestMoreDerivedType() {}
class TestMoreDerivedType : public TestDerivedType {
public:
};
std::shared_ptr<TestBaseType> derived_type_factory()
{
std::shared_ptr<TestBaseType> derived_type_factory() {
return std::make_shared<TestDerivedType>();
}
std::shared_ptr<TestBaseType> more_derived_type_factory()
{
std::shared_ptr<TestBaseType> more_derived_type_factory() {
return std::make_shared<TestMoreDerivedType>();
}
std::shared_ptr<TestBaseType> null_factory()
{
std::shared_ptr<TestBaseType> null_factory() {
return std::shared_ptr<TestBaseType>();
}
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
{
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr) {
ptr = std::make_shared<TestDerivedType>();
}
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
{
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr) {
ptr = nullptr;
}
std::string hello_world()
{
std::string hello_world() {
return "Hello World";
}
static int global_i = 1;
int *get_new_int()
{
int *get_new_int() {
return &global_i;
}
@ -145,8 +133,7 @@ int *get_new_int()
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module()
{
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module() {
chaiscript::ModulePtr m(new chaiscript::Module());
m->add(chaiscript::fun(hello_world), "hello_world");
@ -156,16 +143,16 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::user_type<Type2>(), "Type2");
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType (const TestBaseType &)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType (int *)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType(const TestBaseType &)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType(int *)>(), "TestBaseType");
m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType(const TestDerivedType &)>(), "TestDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType ()>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType (const TestMoreDerivedType &)>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType()>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType(const TestMoreDerivedType &)>(), "TestMoreDerivedType");
/// \todo automatic chaining of base classes?
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
@ -197,7 +184,6 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&TestBaseType::func_member), "func_member");
m->add(chaiscript::fun(&get_new_int), "get_new_int");
m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1");
m->add(chaiscript::user_type<TestEnum>(), "TestEnum");
@ -210,16 +196,14 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&Type2::get_val), "get_val");
m->add(chaiscript::fun(&Type2::get_str), "get_str");
m->add(chaiscript::type_conversion<const char *, std::string>());
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
m->add(chaiscript::constructor<Type2(const TestBaseType &)>(), "Type2");
m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr");
m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr");
return m;
}
#ifdef __llvm__
#pragma clang diagnostic pop
#endif

View File

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

View File

@ -2,11 +2,13 @@
#ifndef CHAISCRIPT_PARSER_LIB
#define CHAISCRIPT_PARSER_LIB
#include <memory>
namespace chaiscript {
namespace parser {
class ChaiScript_Parser_Base;
}
}
} // namespace chaiscript
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser();

View File

@ -1,8 +1,6 @@
#include "../include/chaiscript/chaiscript_stdlib.hpp"
#include "chaiscript_stdlib.hpp"
std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib()
{
std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib() {
return chaiscript::Std_Lib::library();
}

View File

@ -1,2 +0,0 @@
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 = 2 } );
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 + 2 = 2 } );

View File

@ -1,2 +0,0 @@
var prod = bind(foldl, _, `*`, 1.0)
assert_equal(60, prod([3, 4, 5]))

View File

@ -1,34 +0,0 @@
def add(x, y)
{
return x + y;
}
assert_equal(2, add.get_arity());
var b = bind(add, 2, _);
assert_equal(1, b.get_arity());
var c = bind(b, 3);
assert_equal(0, c.get_arity());
assert_equal(6, b(4));
assert_equal(5, c());
def concat2(a,b,c,d)
{
return to_string(a) + to_string(b) + to_string(c) + to_string(d);
}
var d = bind(concat2, _, " Hello ", _, " World");
assert_equal(2, d.get_arity());
assert_equal("1 Hello 3 World", d(1,3));
var e = bind(`<`, _, 5);
var types = e.get_param_types();
assert_equal(2, types.size());
assert_equal(true, types[0].bare_equal(bool_type));

View File

@ -1 +0,0 @@
{print("hello")}

View File

@ -1 +0,0 @@
assert_equal(false, !true)

View File

@ -1,7 +0,0 @@
var i = 0
while (i < 10) {
if (++i == 5) {
break
}
}
assert_equal(5, i);

View File

@ -1 +0,0 @@
assert_equal("b", to_string('b'))

View File

@ -1,7 +0,0 @@
assert_equal(true, 1.is_var_const());
assert_equal(false, 1.is_var_reference());
assert_equal(true, 1.is_var_pointer());
assert_equal(false, 1.is_var_null());
assert_equal(false, 1.is_var_undef());
var i;
assert_equal(true, i.is_var_undef());

View File

@ -1,3 +0,0 @@
var v = collate(1, 2)
assert_equal(1, v[0])
assert_equal(2, v[1])

View File

@ -1 +0,0 @@
assert_equal(false, 1 > 2);

View File

@ -1 +0,0 @@
assert_equal(true, 1 < 2)

View File

@ -1,5 +0,0 @@
var v = concat([1, 2], [3, 4]);
assert_equal(4, v.size());
assert_equal(1, v[0]);
assert_equal(4, v[3]);

View File

@ -1,4 +0,0 @@
//If the following succeeds, the test passes
"Hello World".for_each(fun(x) { print(x) } )

View File

@ -1 +0,0 @@
assert_equal("3.5bob", 3.5.to_string() + "bob");

View File

@ -1 +0,0 @@
assert_equal("3bob", 3.to_string + "bob")

View File

@ -1 +0,0 @@
assert_equal(6.8, "3.5".to_double() + 3.3)

View File

@ -1 +0,0 @@
assert_equal(8, "4".to_int() + 4)

View File

@ -1,11 +0,0 @@
var a = [1,2,3, [4,5,6] ]
assert_equal(a[3][0], 4)
def Test::Test() { this.a = [1,2,3]; }
attr Test::a;
var t = Test();
assert_equal(t.a[0], 1)

View File

@ -1,10 +0,0 @@
assert_equal(`==`, `==`);
assert_not_equal(`==`, `<`);
assert_equal(`<`.get_arity(), 2);
assert_equal(get_arity.get_contained_functions().size(), 0);
assert_equal(get_arity.get_arity(), 1);
assert_equal(get_arity.get_param_types().size(), 2);
var paramtypes = get_arity.get_param_types();
assert_equal(true, paramtypes[1].bare_equal(Function_type));

View File

@ -1 +0,0 @@
assert_equal([3,4], drop([1, 2, 3, 4], 2))

View File

@ -1 +0,0 @@
assert_equal([2, 3], drop_while([1, 2, 3], odd))

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