Merge pull request #248 from ChaiScript/release-5.x

Release 5.x
This commit is contained in:
Jason Turner 2016-02-16 17:52:50 -07:00
commit c0664d778c
115 changed files with 3244 additions and 1314 deletions

View File

@ -2,7 +2,8 @@ compilers:
- name: "clang" - name: "clang"
version: "3.5" version: "3.5"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: "clang" - name: "clang"
build_tag: "LibC++" build_tag: "LibC++"
version: "3.5" version: "3.5"
@ -12,7 +13,7 @@ compilers:
build_tag: AddressSanitizer build_tag: AddressSanitizer
version: "3.6" version: "3.6"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON cmake_extra_flags: -DRUN_FUZZY_TESTS:BOOL=TRUE -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
- name: "clang" - name: "clang"
build_tag: ThreadSanitizer build_tag: ThreadSanitizer
version: "3.6" version: "3.6"
@ -20,11 +21,21 @@ compilers:
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON
- name: "gcc" - name: "gcc"
version: "4.8" version: "4.8"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON build_tag: "NoThreads"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON -DMULTITHREAD_SUPPORT_ENABLED:BOOL=OFF
collect_performance_results: true
- name: "gcc"
version: "4.8"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: "gcc" - name: "gcc"
version: "4.6" version: "4.6"
skip_packaging: true skip_packaging: true
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: cppcheck - name: cppcheck
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:unittests/catch.hpp" --force --suppress="unusedFunction:*"
- name: custom_check
commands:
- ./contrib/check_for_tabs.rb

View File

@ -20,6 +20,7 @@ option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
option(BUILD_SAMPLES "Build Samples Folder" FALSE) option(BUILD_SAMPLES "Build Samples Folder" FALSE)
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE) option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE) option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
mark_as_advanced(USE_STD_MAKE_SHARED) mark_as_advanced(USE_STD_MAKE_SHARED)
@ -68,6 +69,13 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(LINKER_FLAGS "${LINKER_FLAGS} -flto") set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif() endif()
option(GPROF_OUTPUT "Generate profile data" FALSE)
if (GPROF_OUTPUT)
add_definitions(-pg)
set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE) option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE) if (PROFILE_GENERATE)
add_definitions(-fprofile-generate) add_definitions(-fprofile-generate)
@ -94,8 +102,8 @@ 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_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 5) set(CPACK_PACKAGE_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 7) set(CPACK_PACKAGE_VERSION_MINOR 8)
set(CPACK_PACKAGE_VERSION_PATCH 1) set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com") set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@ -115,16 +123,12 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest) include(CTest)
include(CPack) include(CPack)
include(cmake/CheckCXX11Features.cmake)
if(NOT MINGW) if(NOT MINGW)
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib) find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
endif() endif()
if(HAS_CXX11_VARIADIC_TEMPLATES) if (UNIX AND NOT APPLE)
message(STATUS "Variadic Template support detected") find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
else()
message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.")
endif() endif()
enable_testing() enable_testing()
@ -174,7 +178,7 @@ else()
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG}) add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_definitions(-Weverything -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors) add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command)
else() else()
add_definitions(-Wnoexcept) add_definitions(-Wnoexcept)
endif() endif()
@ -206,7 +210,7 @@ endif()
include_directories(include) include_directories(include)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
@ -253,10 +257,14 @@ add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
if(BUILD_SAMPLES) if(BUILD_SAMPLES)
add_executable(example samples/example.cpp) add_executable(example samples/example.cpp)
target_link_libraries(example ${LIBS}) target_link_libraries(example ${LIBS})
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
target_link_libraries(test_num_exceptions ${LIBS})
add_executable(memory_leak_test samples/memory_leak_test.cpp) add_executable(memory_leak_test samples/memory_leak_test.cpp)
target_link_libraries(memory_leak_test ${LIBS}) target_link_libraries(memory_leak_test ${LIBS})
add_executable(inheritance samples/inheritance.cpp) add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS}) target_link_libraries(inheritance ${LIBS})
add_executable(factory samples/factory.cpp)
target_link_libraries(factory ${LIBS})
add_executable(fun_call_performance samples/fun_call_performance.cpp) add_executable(fun_call_performance samples/fun_call_performance.cpp)
target_link_libraries(fun_call_performance ${LIBS}) target_link_libraries(fun_call_performance ${LIBS})
endif() endif()
@ -272,6 +280,9 @@ endif()
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai) file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
list(SORT UNIT_TESTS) list(SORT UNIT_TESTS)
file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/*.chai)
list(SORT PERFORMANCE_TESTS)
if (RUN_FUZZY_TESTS) if (RUN_FUZZY_TESTS)
@ -336,8 +347,8 @@ if(BUILD_TESTING)
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents}) string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
foreach(hit ${found_tests}) foreach(hit ${found_tests})
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit}) string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
add_test(${test_name} "${executable}" ${test_name}) add_test(compiled.${test_name} "${executable}" ${test_name})
set_tests_properties(${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}") set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
endforeach() endforeach()
endif() endif()
endif() endif()
@ -371,12 +382,32 @@ if(BUILD_TESTING)
) )
set(TESTS "")
foreach(filename ${UNIT_TESTS}) foreach(filename ${UNIT_TESTS})
message(STATUS "Adding test ${filename}") message(STATUS "Adding unit test ${filename}")
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename}) add_test(unit.${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
list(APPEND TESTS unit.${filename})
endforeach() endforeach()
set_property(TEST ${UNIT_TESTS} if (RUN_PERFORMANCE_TESTS)
foreach(filename ${PERFORMANCE_TESTS})
message(STATUS "Adding performance test ${filename}")
add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $<TARGET_FILE:chai> ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename})
list(APPEND TESTS performance.${filename})
endforeach()
add_executable(profile_cpp_calls_2 performance_tests/profile_cpp_calls_2.cpp)
target_link_libraries(profile_cpp_calls_2 ${LIBS})
add_test(NAME performance.profile_cpp_calls_2 COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_cpp_calls_2 $<TARGET_FILE:profile_cpp_calls_2>)
add_executable(profile_fun_wrappers performance_tests/profile_fun_wrappers.cpp)
target_link_libraries(profile_fun_wrappers ${LIBS})
add_test(NAME performance.profile_fun_wrappers COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_fun_wrappers $<TARGET_FILE:profile_fun_wrappers>)
endif()
set_property(TEST ${TESTS}
PROPERTY ENVIRONMENT PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/" "CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"

View File

@ -1,4 +1,4 @@
Copyright 2009-2015 Jason Turner Copyright 2009-2016 Jason Turner
Copyright 2009-2012 Jonathan Turner. Copyright 2009-2012 Jonathan Turner.
All Rights Reserved. All Rights Reserved.

16
appveyor.yml Normal file
View File

@ -0,0 +1,16 @@
version: 5.7.2.{build}
os: Visual Studio 2015
environment:
matrix:
- {}
build_script:
- cmd: >-
mkdir build
cd build
cmake c:\Projects\chaiscript -G "Visual Studio 14"
cmake --build . --config Debug
test_script:
- cmd: ctest -C Debug

View File

@ -77,7 +77,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. It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
``` ```
chai.add(chaiscript::user_type<MyClass>, "MyClass"); chai.add(chaiscript::user_type<MyClass>(), "MyClass");
``` ```
## Adding Type Conversions ## Adding Type Conversions
@ -90,6 +90,13 @@ A helper function exists for strongly typed and ChaiScript `Vector` function con
chai.add(chaiscript::vector_conversion<std::vector<int>>()); chai.add(chaiscript::vector_conversion<std::vector<int>>());
``` ```
A helper function also exists for strongly typed and ChaiScript `Map` function conversion definition:
```
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
```
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>` This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
## Adding Objects ## Adding Objects
@ -100,8 +107,9 @@ chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared
auto shareddouble = std::make_shared<double>(4.3); auto shareddouble = std::make_shared<double>(4.3);
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const, throws if object exists
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
``` ```
# Using STL # Using STL
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself. ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
@ -221,11 +229,13 @@ var k = 5; // initialized to 5 (integer)
var l := k; // reference to k var l := k; // reference to k
auto &m = k; // reference to k auto &m = k; // reference to k
GLOBAL g = 5; // creates a global variable. If global already exists, it is not re-added global g = 5; // creates a global variable. If global already exists, it is not re-added
GLOBAL g = 2; // global 'g' now equals 2 global g = 2; // global 'g' now equals 2
GLOBAL g2; global g2;
if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if GLOBAL decl hit more than once if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hit more than once
GLOBAL g3; // all upper case version also accepted
``` ```
## Built in Types ## Built in Types
@ -354,6 +364,19 @@ o.f = fun(y) { print(this.x + y); }
o.f(10); // prints 13 o.f(10); // prints 13
``` ```
### Option Explicit
If you want to disable dynamic parameter definitions, you can `set_explicit`.
```
class My_Class {
def My_Class() {
this.set_explicit(true);
this.x = 2; // this would fail with explicit set to true
}
};
```
## method_missing ## method_missing
A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

11
contrib/check_for_tabs.rb Executable file
View File

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

View File

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

View File

@ -1,18 +1,22 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_ #ifndef CHAISCRIPT_DEFINES_HPP_
#define CHAISCRIPT_DEFINES_HPP_ #define CHAISCRIPT_DEFINES_HPP_
#ifdef _MSC_VER #ifdef _MSC_VER
#define CHAISCRIPT_STRINGIZE(x) "" #x
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE(_MSC_FULL_VER)
#define CHAISCRIPT_MSVC _MSC_VER #define CHAISCRIPT_MSVC _MSC_VER
#define CHAISCRIPT_HAS_DECLSPEC #define CHAISCRIPT_HAS_DECLSPEC
#if _MSC_VER <= 1800 #if _MSC_VER <= 1800
#define CHAISCRIPT_MSVC_12 #define CHAISCRIPT_MSVC_12
#endif #endif
#else
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
#endif #endif
#ifndef CHAISCRIPT_MSVC_12 #ifndef CHAISCRIPT_MSVC_12
@ -29,7 +33,25 @@
#define CHAISCRIPT_WINDOWS #define CHAISCRIPT_WINDOWS
#endif #endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP)) #if defined(_WIN32)
#if defined(__llvm__)
#define CHAISCRIPT_COMPILER_NAME "clang(windows)"
#elif defined(__GNUC__)
#define CHAISCRIPT_COMPILER_NAME "gcc(mingw)"
#else
#define CHAISCRIPT_COMPILER_NAME "msvc"
#endif
#else
#if defined(__llvm__)
#define CHAISCRIPT_COMPILER_NAME "clang"
#elif defined(__GNUC__)
#define CHAISCRIPT_COMPILER_NAME "gcc"
#else
#define CHAISCRIPT_COMPILER_NAME "unknown"
#endif
#endif
#if (defined(CHAISCRIPT_MSVC) && !defined(CHAISCRIPT_MSVC_12)) || (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP))
/// Currently only g++>=4.8 supports this natively /// Currently only g++>=4.8 supports this natively
/// \todo Make this support other compilers when possible /// \todo Make this support other compilers when possible
#define CHAISCRIPT_HAS_THREAD_LOCAL #define CHAISCRIPT_HAS_THREAD_LOCAL
@ -39,7 +61,11 @@
#define CHAISCRIPT_GCC_4_6 #define CHAISCRIPT_GCC_4_6
#endif #endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__) #if defined(__llvm__)
#define CHAISCRIPT_CLANG
#endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_CLANG)
#define CHAISCRIPT_OVERRIDE override #define CHAISCRIPT_OVERRIDE override
#else #else
#define CHAISCRIPT_OVERRIDE #define CHAISCRIPT_OVERRIDE
@ -52,7 +78,7 @@
#define CHAISCRIPT_MODULE_EXPORT extern "C" #define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif #endif
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC_12
#define CHAISCRIPT_NOEXCEPT throw() #define CHAISCRIPT_NOEXCEPT throw()
#define CHAISCRIPT_CONSTEXPR #define CHAISCRIPT_CONSTEXPR
#else #else
@ -60,12 +86,22 @@
#define CHAISCRIPT_CONSTEXPR constexpr #define CHAISCRIPT_CONSTEXPR constexpr
#endif #endif
#ifdef _DEBUG
#define CHAISCRIPT_DEBUG true
#else
#define CHAISCRIPT_DEBUG false
#endif
#include <memory> #include <memory>
namespace chaiscript { namespace chaiscript {
static const int version_major = 5; static const int version_major = 5;
static const int version_minor = 7; static const int version_minor = 8;
static const int version_patch = 1; 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;
template<typename B, typename D, typename ...Arg> template<typename B, typename D, typename ...Arg>
inline std::shared_ptr<B> make_shared(Arg && ... arg) inline std::shared_ptr<B> make_shared(Arg && ... arg)

View File

@ -19,6 +19,7 @@
#include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/boxed_value.hpp" #include "dispatchkit/boxed_value.hpp"
#include "language/chaiscript_prelude.chai" #include "language/chaiscript_prelude.chai"
#include "utility/json_wrap.hpp"
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
#include <future> #include <future>
@ -51,6 +52,8 @@ namespace chaiscript
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async"); lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
#endif #endif
lib->add(json_wrap::library());
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ ); lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
return lib; return lib;

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_THREADING_HPP_ #ifndef CHAISCRIPT_THREADING_HPP_
@ -45,14 +45,14 @@ namespace chaiscript
class unique_lock : public std::unique_lock<T> class unique_lock : public std::unique_lock<T>
{ {
public: public:
unique_lock(T &t) : std::unique_lock<T>(t) {} explicit unique_lock(T &t) : std::unique_lock<T>(t) {}
}; };
template<typename T> template<typename T>
class shared_lock : public std::unique_lock<T> class shared_lock : public std::unique_lock<T>
{ {
public: public:
shared_lock(T &t) : std::unique_lock<T>(t) {} explicit shared_lock(T &t) : std::unique_lock<T>(t) {}
void unlock() {} void unlock() {}
}; };
@ -60,7 +60,7 @@ namespace chaiscript
class lock_guard : public std::lock_guard<T> class lock_guard : public std::lock_guard<T>
{ {
public: public:
lock_guard(T &t) : std::lock_guard<T>(t) {} explicit lock_guard(T &t) : std::lock_guard<T>(t) {}
}; };
class shared_mutex : public std::mutex { }; class shared_mutex : public std::mutex { };
@ -77,7 +77,7 @@ namespace chaiscript
{ {
public: public:
Thread_Storage(void *t_key) explicit Thread_Storage(void *t_key)
: m_key(t_key) : m_key(t_key)
{ {
} }
@ -129,7 +129,7 @@ namespace chaiscript
{ {
public: public:
Thread_Storage(void *) explicit Thread_Storage(void *)
{ {
} }
@ -160,13 +160,14 @@ namespace chaiscript
{ {
unique_lock<mutex> lock(m_mutex); unique_lock<mutex> lock(m_mutex);
auto itr = m_instances.find(std::this_thread::get_id()); const auto id = std::this_thread::get_id();
auto itr = m_instances.find(id);
if (itr != m_instances.end()) { return itr->second; } if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(std::make_shared<T>()); std::shared_ptr<T> new_instance(std::make_shared<T>());
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance)); m_instances.insert(std::make_pair(id, new_instance));
return new_instance; return new_instance;
} }
@ -182,7 +183,7 @@ namespace chaiscript
class unique_lock class unique_lock
{ {
public: public:
unique_lock(T &) {} explicit unique_lock(T &) {}
void lock() {} void lock() {}
void unlock() {} void unlock() {}
}; };
@ -191,7 +192,7 @@ namespace chaiscript
class shared_lock class shared_lock
{ {
public: public:
shared_lock(T &) {} explicit shared_lock(T &) {}
void lock() {} void lock() {}
void unlock() {} void unlock() {}
}; };
@ -200,7 +201,7 @@ namespace chaiscript
class lock_guard class lock_guard
{ {
public: public:
lock_guard(T &) {} explicit lock_guard(T &) {}
}; };
class shared_mutex { }; class shared_mutex { };
@ -212,7 +213,7 @@ namespace chaiscript
class Thread_Storage class Thread_Storage
{ {
public: public:
Thread_Storage(void *) explicit Thread_Storage(void *)
{ {
} }

View File

@ -46,7 +46,7 @@ namespace chaiscript {
private: private:
struct Data struct Data
{ {
Data(const std::type_info &t_type) explicit Data(const std::type_info &t_type)
: m_type(t_type) : m_type(t_type)
{ {
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
@ -40,7 +40,7 @@ namespace chaiscript
{ {
} }
bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT explicit bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT
: to(nullptr), m_what(std::move(t_what)) : to(nullptr), m_what(std::move(t_what))
{ {
} }

View File

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

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_ #ifndef CHAISCRIPT_BOOTSTRAP_HPP_
@ -440,6 +440,8 @@ namespace chaiscript
m->add(constructor<dispatch::Dynamic_Object ()>(), "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_type_name), "get_type_name");
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs"); 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(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr"); m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr"); m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
@ -450,7 +452,13 @@ namespace chaiscript
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]"); m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]"); m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
m->eval("def Dynamic_Object::clone() { auto &new_o = Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }"); m->eval(R""(
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->add(fun(&has_guard), "has_guard"); m->add(fun(&has_guard), "has_guard");
m->add(fun(&get_guard), "get_guard"); m->add(fun(&get_guard), "get_guard");
@ -460,9 +468,12 @@ namespace chaiscript
m->add(fun(&Boxed_Value::is_const), "is_var_const"); 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_ref), "is_var_reference");
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer"); 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::is_type), "is_type");
m->add(fun(&Boxed_Value::get_attr), "get_var_attr"); 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::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(fun(&Boxed_Value::get_type_info), "get_type_info");
m->add(user_type<Type_Info>(), "Type_Info"); m->add(user_type<Type_Info>(), "Type_Info");
@ -485,6 +496,7 @@ namespace chaiscript
basic_constructors<bool>("bool", m); basic_constructors<bool>("bool", m);
operators::assign<bool>(m); operators::assign<bool>(m);
operators::equal<bool>(m); operators::equal<bool>(m);
operators::not_equal<bool>(m);
m->add(fun([](const std::string &s) -> std::string { return s; }), "to_string"); m->add(fun([](const std::string &s) -> std::string { return s; }), "to_string");
m->add(fun(&Bootstrap::bool_to_string), "to_string"); m->add(fun(&Bootstrap::bool_to_string), "to_string");
@ -502,6 +514,8 @@ namespace chaiscript
bootstrap_pod_type<long>("long", m); bootstrap_pod_type<long>("long", m);
bootstrap_pod_type<unsigned int>("unsigned_int", m); bootstrap_pod_type<unsigned int>("unsigned_int", m);
bootstrap_pod_type<unsigned long>("unsigned_long", 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<size_t>("size_t", m);
bootstrap_pod_type<char>("char", m); bootstrap_pod_type<char>("char", m);
bootstrap_pod_type<wchar_t>("wchar_t", m); bootstrap_pod_type<wchar_t>("wchar_t", m);
@ -556,11 +570,12 @@ namespace chaiscript
"eval_error", "eval_error",
{ }, { },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"}, { {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> { {fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval; std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(), std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
std::back_inserter(retval), std::back_inserter(retval),
&chaiscript::var<std::shared_ptr<const chaiscript::AST_Node>>); &chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
return retval; return retval;
})), "call_stack"} } })), "call_stack"} }
); );
@ -588,7 +603,7 @@ namespace chaiscript
std::vector<Boxed_Value> retval; std::vector<Boxed_Value> retval;
std::transform(t_node.children.begin(), t_node.children.end(), std::transform(t_node.children.begin(), t_node.children.end(),
std::back_inserter(retval), std::back_inserter(retval),
&chaiscript::var<std::shared_ptr<chaiscript::AST_Node>>); &chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
return retval; return retval;
})), "children"}, })), "children"},
{fun(&AST_Node::replace_child), "replace_child"} {fun(&AST_Node::replace_child), "replace_child"}

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
/// \file /// \file
@ -334,7 +334,12 @@ namespace chaiscript
"# Pushes the second value onto the container while making a clone of the value\n" "# Pushes the second value onto the container while making a clone of the value\n"
"def push_back(" + type + " container, x)\n" "def push_back(" + type + " container, x)\n"
"{ \n" "{ \n"
" container.push_back_ref(clone(x)) \n" " if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n"
" container.push_back_ref(x) \n"
" } else { \n"
" container.push_back_ref(clone(x)); \n"
" }\n"
"} \n" "} \n"
); );
@ -370,7 +375,12 @@ namespace chaiscript
"# Pushes the second value onto the front of container while making a clone of the value\n" "# Pushes the second value onto the front of container while making a clone of the value\n"
"def push_front(" + type + " container, x)\n" "def push_front(" + type + " container, x)\n"
"{ \n" "{ \n"
" container.push_front_ref(clone(x)) \n" " if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n"
" container.push_front_ref(x) \n"
" } else { \n"
" container.push_front_ref(clone(x)); \n"
" }\n"
"} \n" "} \n"
); );
return "push_front_ref"; return "push_front_ref";
@ -460,6 +470,30 @@ namespace chaiscript
m->add(fun(static_cast<elem_access>(&MapType::at)), "at"); m->add(fun(static_cast<elem_access>(&MapType::at)), "at");
m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at"); m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>))
{
m->eval(R"(
def Map::`==`(Map rhs) {
if ( rhs.size() != this.size() ) {
return false;
} else {
auto r1 = range(this);
auto r2 = range(rhs);
while (!r1.empty())
{
if (!eq(r1.front().first, r2.front().first) || !eq(r1.front().second, r2.front().second))
{
return false;
}
r1.pop_front();
r2.pop_front();
}
true;
}
} )"
);
}
container_type<MapType>(type, m); container_type<MapType>(type, m);
default_constructible_type<MapType>(type, m); default_constructible_type<MapType>(type, m);
assignable_type<MapType>(type, m); assignable_type<MapType>(type, m);
@ -515,7 +549,7 @@ namespace chaiscript
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{ {
m->eval(R"( m->eval(R"(
def Vector::`==`(rhs) : type_match(rhs, this) { def Vector::`==`(Vector rhs) {
if ( rhs.size() != this.size() ) { if ( rhs.size() != this.size() ) {
return false; return false;
} else { } else {

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HPP_
@ -69,9 +69,9 @@ namespace chaiscript
/// assert(i == 5); /// assert(i == 5);
/// \endcode /// \endcode
template<typename Type> template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr) typename detail::Cast_Helper<Type>::Result_Type 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>())) { if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
try { 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 &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
@ -79,18 +79,18 @@ namespace chaiscript
} }
if (t_conversions && t_conversions->convertable_type<Type>()) if (t_conversions && (*t_conversions)->convertable_type<Type>())
{ {
try { try {
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n'; // std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // 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 // either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions); return detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions);
} catch (...) { } catch (...) {
try { try {
// std::cout << "trying a down conversion " << typeid(Type).name() << '\n'; // std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
// try going the other way - down the inheritance graph // try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(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 &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
@ -16,7 +16,7 @@
namespace chaiscript namespace chaiscript
{ {
class Type_Conversions; class Type_Conversions_State;
namespace detail namespace detail
{ {
@ -33,14 +33,14 @@ namespace chaiscript
template<typename Result> template<typename Result>
struct Cast_Helper_Inner struct Cast_Helper_Inner
{ {
typedef std::reference_wrapper<typename std::add_const<Result>::type > Result_Type; typedef typename std::add_const<Result>::type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{ {
if (ob.get_type_info().bare_equal_type_info(typeid(Result))) if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
auto p = throw_if_null(ob.get_const_ptr()); auto p = throw_if_null(ob.get_const_ptr());
return std::cref(*static_cast<const Result *>(p)); return *static_cast<const Result *>(p);
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
@ -52,23 +52,17 @@ namespace chaiscript
{ {
}; };
/// Cast_Helper_Inner for casting to a const & type
template<typename Result>
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
{
};
/// Cast_Helper_Inner for casting to a const * type /// Cast_Helper_Inner for casting to a const * type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result *> struct Cast_Helper_Inner<const Result *>
{ {
typedef const Result * Result_Type; typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{ {
if (ob.get_type_info().bare_equal_type_info(typeid(Result))) if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
return static_cast<const Result *>(throw_if_null(ob.get_const_ptr())); return static_cast<const Result *>(ob.get_const_ptr());
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
@ -80,11 +74,40 @@ namespace chaiscript
struct Cast_Helper_Inner<Result *> struct Cast_Helper_Inner<Result *>
{ {
typedef Result * Result_Type; typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{ {
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result)) if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
{ {
return static_cast<Result *>(throw_if_null(ob.get_ptr())); return static_cast<Result *>(ob.get_ptr());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
template<typename 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 &>
{
typedef const Result& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
auto p = throw_if_null(ob.get_const_ptr());
return *static_cast<const Result *>(p);
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
@ -99,7 +122,7 @@ namespace chaiscript
{ {
typedef Result& Result_Type; typedef Result& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{ {
if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result))) if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
@ -116,7 +139,7 @@ namespace chaiscript
{ {
typedef std::shared_ptr<Result> Result_Type; typedef std::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{ {
return ob.get().cast<std::shared_ptr<Result> >(); return ob.get().cast<std::shared_ptr<Result> >();
} }
@ -128,7 +151,7 @@ namespace chaiscript
{ {
typedef std::shared_ptr<const Result> Result_Type; typedef std::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{ {
if (!ob.get_type_info().is_const()) if (!ob.get_type_info().is_const())
{ {
@ -166,9 +189,9 @@ namespace chaiscript
template<> template<>
struct Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<Boxed_Value>
{ {
typedef const Boxed_Value & Result_Type; typedef Boxed_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{ {
return ob; return ob;
} }
@ -178,11 +201,11 @@ namespace chaiscript
template<> template<>
struct Cast_Helper_Inner<Boxed_Value &> struct Cast_Helper_Inner<Boxed_Value &>
{ {
typedef Boxed_Value& Result_Type; typedef std::reference_wrapper<Boxed_Value> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{ {
return const_cast<Boxed_Value &>(ob); return std::ref(const_cast<Boxed_Value &>(ob));
} }
}; };
@ -236,7 +259,7 @@ namespace chaiscript
{ {
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type; typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{ {
return Cast_Helper_Inner<T>::cast(ob, t_conversions); return Cast_Helper_Inner<T>::cast(ob, t_conversions);
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_ #ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_
@ -100,6 +100,7 @@ namespace chaiscript
:(Common_Types::t_uint64); :(Common_Types::t_uint64);
} }
static Common_Types get_common_type(const Boxed_Value &t_bv) static Common_Types get_common_type(const Boxed_Value &t_bv)
{ {
const Type_Info &inp_ = t_bv.get_type_info(); const Type_Info &inp_ = t_bv.get_type_info();
@ -120,8 +121,12 @@ namespace chaiscript
return get_common_type(sizeof(unsigned int), false); return get_common_type(sizeof(unsigned int), false);
} else if (inp_ == typeid(long)) { } else if (inp_ == typeid(long)) {
return get_common_type(sizeof(long), true); return get_common_type(sizeof(long), true);
} else if (inp_ == typeid(long long)) {
return get_common_type(sizeof(long long), true);
} else if (inp_ == typeid(unsigned long)) { } else if (inp_ == typeid(unsigned long)) {
return get_common_type(sizeof(unsigned long), false); return get_common_type(sizeof(unsigned long), false);
} else if (inp_ == typeid(unsigned long long)) {
return get_common_type(sizeof(unsigned long long), false);
} else if (inp_ == typeid(std::int8_t)) { } else if (inp_ == typeid(std::int8_t)) {
return Common_Types::t_int8; return Common_Types::t_int8;
} else if (inp_ == typeid(std::int16_t)) { } else if (inp_ == typeid(std::int16_t)) {
@ -513,6 +518,21 @@ namespace chaiscript
validate_boxed_number(bv); validate_boxed_number(bv);
} }
static bool is_floating_point(const Boxed_Value &t_bv)
{
const Type_Info &inp_ = t_bv.get_type_info();
if (inp_ == typeid(double)) {
return true;
} else if (inp_ == typeid(long double)) {
return true;
} else if (inp_ == typeid(float)) {
return true;
} else {
return false;
}
}
Boxed_Number get_as(const Type_Info &inp_) const Boxed_Number get_as(const Type_Info &inp_) const
{ {
if (inp_.bare_equal_type_info(typeid(int))) { if (inp_.bare_equal_type_info(typeid(int))) {
@ -537,8 +557,12 @@ namespace chaiscript
return Boxed_Number(get_as<unsigned int>()); return Boxed_Number(get_as<unsigned int>());
} else if (inp_.bare_equal_type_info(typeid(long))) { } else if (inp_.bare_equal_type_info(typeid(long))) {
return Boxed_Number(get_as<long>()); return Boxed_Number(get_as<long>());
} else if (inp_.bare_equal_type_info(typeid(long long))) {
return Boxed_Number(get_as<long long>());
} else if (inp_.bare_equal_type_info(typeid(unsigned long))) { } else if (inp_.bare_equal_type_info(typeid(unsigned long))) {
return Boxed_Number(get_as<unsigned long>()); return Boxed_Number(get_as<unsigned long>());
} else if (inp_.bare_equal_type_info(typeid(unsigned long long))) {
return Boxed_Number(get_as<unsigned long long>());
} else if (inp_.bare_equal_type_info(typeid(int8_t))) { } else if (inp_.bare_equal_type_info(typeid(int8_t))) {
return Boxed_Number(get_as<int8_t>()); return Boxed_Number(get_as<int8_t>());
} else if (inp_.bare_equal_type_info(typeid(int16_t))) { } else if (inp_.bare_equal_type_info(typeid(int16_t))) {
@ -987,7 +1011,7 @@ namespace chaiscript
{ {
typedef Boxed_Number Result_Type; typedef Boxed_Number Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
{ {
return Boxed_Number(ob); return Boxed_Number(ob);
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_ #ifndef CHAISCRIPT_BOXED_VALUE_HPP_
@ -297,6 +297,13 @@ namespace chaiscript
return *this; 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 /// \returns true if the two Boxed_Values share the same internal type
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT
@ -330,9 +337,9 @@ namespace chaiscript
/// ///
/// @sa @ref adding_objects /// @sa @ref adding_objects
template<typename T> template<typename T>
Boxed_Value var(T t) Boxed_Value var(T &&t)
{ {
return Boxed_Value(t); return Boxed_Value(std::forward<T>(t));
} }
namespace detail { namespace detail {

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_ #ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
@ -61,6 +61,17 @@ namespace chaiscript {
Ret (Class::*m_func)(Param...); Ret (Class::*m_func)(Param...);
}; };
template<typename T>
struct Arity
{
};
template<typename Ret, typename ... Params>
struct Arity<Ret (Params...)>
{
static const size_t arity = sizeof...(Params);
};
template<typename T> template<typename T>
struct Function_Signature struct Function_Signature

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DISPATCHKIT_HPP_ #ifndef CHAISCRIPT_DISPATCHKIT_HPP_
@ -314,7 +314,7 @@ namespace chaiscript
return arity; return arity;
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return std::any_of(m_funcs.cbegin(), m_funcs.cend(), return std::any_of(m_funcs.cbegin(), m_funcs.cend(),
[&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); }); [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
@ -326,7 +326,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return dispatch::dispatch(m_funcs, params, t_conversions); return dispatch::dispatch(m_funcs, params, t_conversions);
} }
@ -417,9 +417,9 @@ namespace chaiscript
struct State struct State
{ {
std::map<std::string, std::vector<Proxy_Function> > m_functions; std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> m_functions;
std::map<std::string, Proxy_Function> m_function_objects; std::vector<std::pair<std::string, Proxy_Function>> m_function_objects;
std::map<std::string, Boxed_Value> m_boxed_functions; std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions;
std::map<std::string, Boxed_Value> m_global_objects; std::map<std::string, Boxed_Value> m_global_objects;
Type_Name_Map m_types; Type_Name_Map m_types;
std::set<std::string> m_reserved_words; std::set<std::string> m_reserved_words;
@ -442,7 +442,8 @@ namespace chaiscript
template<typename Type> template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
{ {
return chaiscript::boxed_cast<Type>(bv, &m_conversions); Type_Conversions_State state(m_conversions, m_conversions.conversion_saves());
return chaiscript::boxed_cast<Type>(bv, &state);
} }
/// Add a new conversion for upcasting to a base class /// Add a new conversion for upcasting to a base class
@ -482,24 +483,31 @@ namespace chaiscript
add_object(name, std::move(obj)); add_object(name, std::move(obj));
} }
/// Adds a named object to the current scope
/// \warning This version does not check the validity of the name
/// it is meant for internal use only
void add_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder)
{
auto &stack_elem = get_stack_data(t_holder).back();
if (std::any_of(stack_elem.begin(), stack_elem.end(),
[&](const std::pair<std::string, Boxed_Value> &o) {
return o.first == t_name;
}))
{
throw chaiscript::exception::name_conflict_error(t_name);
}
get_stack_data(t_holder).back().emplace_back(t_name, std::move(obj));
}
/// Adds a named object to the current scope /// Adds a named object to the current scope
/// \warning This version does not check the validity of the name /// \warning This version does not check the validity of the name
/// it is meant for internal use only /// it is meant for internal use only
void add_object(const std::string &name, Boxed_Value obj) void add_object(const std::string &name, Boxed_Value obj)
{ {
auto &stack_elem = get_stack_data().back(); add_object(name, std::move(obj), get_stack_holder());
if (std::any_of(stack_elem.begin(), stack_elem.end(),
[&](const std::pair<std::string, Boxed_Value> &o) {
return o.first == name;
}))
{
throw chaiscript::exception::name_conflict_error(name);
}
get_stack_data().back().emplace_back(name, std::move(obj));
} }
/// Adds a new global shared object, between all the threads /// Adds a new global shared object, between all the threads
@ -511,7 +519,7 @@ namespace chaiscript
throw chaiscript::exception::global_non_const(); throw chaiscript::exception::global_non_const();
} }
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
{ {
@ -526,7 +534,7 @@ namespace chaiscript
{ {
validate_object_name(name); validate_object_name(name);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto itr = m_state.m_global_objects.find(name); const auto itr = m_state.m_global_objects.find(name);
if (itr == m_state.m_global_objects.end()) if (itr == m_state.m_global_objects.end())
@ -544,7 +552,7 @@ namespace chaiscript
{ {
validate_object_name(name); validate_object_name(name);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
{ {
@ -554,6 +562,21 @@ namespace chaiscript
} }
} }
/// Updates an existing global shared object or adds a new global shared object if not found
void set_global(const Boxed_Value &obj, const std::string &name)
{
validate_object_name(name);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto itr = m_state.m_global_objects.find(name);
if (itr != m_state.m_global_objects.end())
{
itr->second.assign(obj);
} else {
m_state.m_global_objects.insert(std::make_pair(name, obj));
}
}
/// Adds a new scope to the stack /// Adds a new scope to the stack
void new_scope() void new_scope()
@ -589,13 +612,13 @@ namespace chaiscript
/// Pushes a new stack on to the list of stacks /// Pushes a new stack on to the list of stacks
void new_stack(Stack_Holder &t_holder) static void new_stack(Stack_Holder &t_holder)
{ {
// add a new Stack with 1 element // add a new Stack with 1 element
t_holder.stacks.emplace_back(1); t_holder.stacks.emplace_back(1);
} }
void pop_stack(Stack_Holder &t_holder) static void pop_stack(Stack_Holder &t_holder)
{ {
t_holder.stacks.pop_back(); t_holder.stacks.pop_back();
} }
@ -641,19 +664,21 @@ namespace chaiscript
return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second; return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second;
} }
// Is the value we are looking for a global? // Is the value we are looking for a global or function?
{ chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
const auto itr = m_state.m_global_objects.find(name); const auto itr = m_state.m_global_objects.find(name);
if (itr != m_state.m_global_objects.end()) if (itr != m_state.m_global_objects.end())
{ {
return itr->second; return itr->second;
} }
}
// If all that failed, then check to see if it's a function // no? is it a function object?
return get_function_object(name); auto obj = get_function_object_int(name, loc);
if (obj.first != loc) t_loc.store(uint_fast32_t(obj.first), std::memory_order_relaxed);
return obj.second;
} }
/// Registers a new named type /// Registers a new named type
@ -711,20 +736,29 @@ namespace chaiscript
return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end()); return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end());
} }
std::shared_ptr<std::vector<Proxy_Function>> get_method_missing_functions() const
{
uint_fast32_t method_missing_loc = m_method_missing_loc.load(std::memory_order_relaxed);
auto method_missing_funs = get_function("method_missing", method_missing_loc);
if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(uint_fast32_t(method_missing_funs.first), std::memory_order_relaxed);
return std::move(method_missing_funs.second);
}
/// Return a function by name /// Return a function by name
std::vector< Proxy_Function > get_function(const std::string &t_name) const std::pair<size_t, std::shared_ptr<std::vector< Proxy_Function>>> get_function(const std::string &t_name, const size_t t_hint) const
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto &funs = get_functions_int(); const auto &funs = get_functions_int();
auto itr = funs.find(t_name); auto itr = find_keyed_value(funs, t_name, t_hint);
if (itr != funs.end()) if (itr != funs.end())
{ {
return itr->second; return std::make_pair(std::distance(funs.begin(), itr), itr->second);
} else { } else {
return std::vector<Proxy_Function>(); return std::make_pair(size_t(0), std::make_shared<std::vector<Proxy_Function>>());
} }
} }
@ -732,28 +766,36 @@ namespace chaiscript
/// \throws std::range_error if it does not /// \throws std::range_error if it does not
Boxed_Value get_function_object(const std::string &t_name) const Boxed_Value get_function_object(const std::string &t_name) const
{ {
// std::cout << "Getting function object: " << t_name << '\n';
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return get_function_object_int(t_name, 0).second;
}
/// \returns a function object (Boxed_Value wrapper) if it exists
/// \throws std::range_error if it does not
/// \warn does not obtain a mutex lock. \sa get_function_object for public version
std::pair<size_t, Boxed_Value> get_function_object_int(const std::string &t_name, const size_t t_hint) const
{
const auto &funs = get_boxed_functions_int(); const auto &funs = get_boxed_functions_int();
auto itr = funs.find(t_name); auto itr = find_keyed_value(funs, t_name, t_hint);
if (itr != funs.end()) if (itr != funs.end())
{ {
return itr->second; return std::make_pair(std::distance(funs.begin(), itr), itr->second);
} else { } else {
throw std::range_error("Object not found: " + t_name); throw std::range_error("Object not found: " + t_name);
} }
} }
/// Return true if a function exists /// Return true if a function exists
bool function_exists(const std::string &name) const bool function_exists(const std::string &name) const
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto &functions = get_functions_int(); const auto &functions = get_functions_int();
return functions.find(name) != functions.end(); return find_keyed_value(functions, name) != functions.end();
} }
/// \returns All values in the local thread state in the parent scope, or if it doesn't exist, /// \returns All values in the local thread state in the parent scope, or if it doesn't exist,
@ -810,11 +852,8 @@ namespace chaiscript
} }
// add the global values // add the global values
{ chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end());
}
return retval; return retval;
} }
@ -851,7 +890,7 @@ namespace chaiscript
for (const auto & function : functions) for (const auto & function : functions)
{ {
for (const auto & internal_func : function.second) for (const auto & internal_func : *function.second)
{ {
rets.emplace_back(function.first, internal_func); rets.emplace_back(function.first, internal_func);
} }
@ -873,7 +912,7 @@ namespace chaiscript
} }
bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const std::vector<Boxed_Value> &t_params, bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const std::vector<Boxed_Value> &t_params,
bool t_has_params) const bool t_has_params, const Type_Conversions_State &t_conversions) const
{ {
if (!t_has_params || t_params.empty()) { if (!t_has_params || t_params.empty()) {
return false; return false;
@ -881,7 +920,7 @@ namespace chaiscript
for (const auto &fun : t_funs) { for (const auto &fun : t_funs) {
if (fun->is_attribute_function()) { if (fun->is_attribute_function()) {
if (fun->compare_first_type(t_params[0], m_conversions)) { if (fun->compare_first_type(t_params[0], t_conversions)) {
return true; return true;
} }
} }
@ -896,38 +935,55 @@ namespace chaiscript
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4715) #pragma warning(disable : 4715)
#endif #endif
Boxed_Value call_member(const std::string &t_name, const std::vector<Boxed_Value> &params, bool t_has_params) const Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> &params, bool t_has_params,
const Type_Conversions_State &t_conversions)
{ {
const auto funs = get_function(t_name); uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
const auto funs = get_function(t_name, loc);
if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed);
const auto do_attribute_call = const auto do_attribute_call =
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions &l_conversions)->Boxed_Value [this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value
{ {
std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params}; std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params};
std::vector<Boxed_Value> remaining_params{l_params.begin() + l_num_params, l_params.end()};
Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions);
if (!remaining_params.empty() || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) { if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
struct This_Foist {
This_Foist(Dispatch_Engine &e, const Boxed_Value &t_bv) : m_e(e) {
m_e.get().new_scope();
m_e.get().add_object("__this", t_bv);
}
~This_Foist() {
m_e.get().pop_scope();
}
std::reference_wrapper<Dispatch_Engine> m_e;
};
This_Foist fi(*this, l_params.front());
auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv); auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv);
try { try {
return (*func)(remaining_params, l_conversions); return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions);
} catch (const chaiscript::exception::bad_boxed_cast &) { } catch (const chaiscript::exception::bad_boxed_cast &) {
} catch (const chaiscript::exception::arity_error &) { } catch (const chaiscript::exception::arity_error &) {
} catch (const chaiscript::exception::guard_error &) { } catch (const chaiscript::exception::guard_error &) {
} }
throw chaiscript::exception::dispatch_error(remaining_params, std::vector<Const_Proxy_Function>{func}); throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector<Const_Proxy_Function>{func});
} else { } else {
return bv; return bv;
} }
}; };
if (is_attribute_call(funs, params, t_has_params)) { if (is_attribute_call(*funs.second, params, t_has_params, t_conversions)) {
return do_attribute_call(1, params, funs, m_conversions); return do_attribute_call(1, params, *funs.second, t_conversions);
} else { } else {
std::exception_ptr except; std::exception_ptr except;
if (!funs.empty()) { if (!funs.second->empty()) {
try { try {
return dispatch::dispatch(funs, params, m_conversions); return dispatch::dispatch(*funs.second, params, t_conversions);
} catch(chaiscript::exception::dispatch_error&) { } catch(chaiscript::exception::dispatch_error&) {
except = std::current_exception(); except = std::current_exception();
} }
@ -939,9 +995,11 @@ namespace chaiscript
const auto functions = [&]()->std::vector<Proxy_Function> { const auto functions = [&]()->std::vector<Proxy_Function> {
std::vector<Proxy_Function> fs; std::vector<Proxy_Function> fs;
for (const auto &f : get_function("method_missing")) const auto method_missing_funs = get_method_missing_functions();
for (const auto &f : *method_missing_funs)
{ {
if(f->compare_first_type(params[0], m_conversions)) { if(f->compare_first_type(params[0], t_conversions)) {
fs.push_back(f); fs.push_back(f);
} }
} }
@ -961,12 +1019,17 @@ namespace chaiscript
}(); }();
if (!functions.empty()) { if (!functions.empty()) {
try {
if (is_no_param) { if (is_no_param) {
std::vector<Boxed_Value> tmp_params(params); std::vector<Boxed_Value> tmp_params(params);
tmp_params.insert(tmp_params.begin() + 1, var(t_name)); tmp_params.insert(tmp_params.begin() + 1, var(t_name));
return do_attribute_call(2, tmp_params, functions, m_conversions); return do_attribute_call(2, tmp_params, functions, t_conversions);
} else { } else {
return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, m_conversions); return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, t_conversions);
}
} catch (const dispatch::option_explicit_set &e) {
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()),
e.what());
} }
} }
@ -975,7 +1038,7 @@ namespace chaiscript
if (except) { if (except) {
std::rethrow_exception(except); std::rethrow_exception(except);
} else { } else {
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.begin(), funs.end())); throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()));
} }
} }
} }
@ -985,30 +1048,15 @@ namespace chaiscript
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> &params,
const Type_Conversions_State &t_conversions) const
{ {
Boxed_Value bv = dispatch::dispatch(get_function(t_name), params, m_conversions); uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
// the result of a clone is never to be marked as a return_value const auto funs = get_function(t_name, loc);
if (t_name == "clone") { if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed);
bv.reset_return_value(); return dispatch::dispatch(*funs.second, params, t_conversions);
}
return bv;
} }
Boxed_Value call_function(const std::string &t_name) const
{
return call_function(t_name, std::vector<Boxed_Value>());
}
Boxed_Value call_function(const std::string &t_name, Boxed_Value p1) const
{
return call_function(t_name, std::vector<Boxed_Value>({std::move(p1)}));
}
Boxed_Value call_function(const std::string &t_name, Boxed_Value p1, Boxed_Value p2) const
{
return call_function(t_name, std::vector<Boxed_Value>({std::move(p1), std::move(p2)}));
}
/// Dump object info to stdout /// Dump object info to stdout
void dump_object(const Boxed_Value &o) const void dump_object(const Boxed_Value &o) const
@ -1052,7 +1100,7 @@ namespace chaiscript
/// Returns true if a call can be made that consists of the first parameter /// Returns true if a call can be made that consists of the first parameter
/// (the function) with the remaining parameters as its arguments. /// (the function) with the remaining parameters as its arguments.
Boxed_Value call_exists(const std::vector<Boxed_Value> &params) Boxed_Value call_exists(const std::vector<Boxed_Value> &params) const
{ {
if (params.empty()) if (params.empty())
{ {
@ -1060,8 +1108,9 @@ namespace chaiscript
} }
const Const_Proxy_Function &f = this->boxed_cast<Const_Proxy_Function>(params[0]); const Const_Proxy_Function &f = this->boxed_cast<Const_Proxy_Function>(params[0]);
const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves());
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), m_conversions)); return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), convs));
} }
/// Dump all system info to stdout /// Dump all system info to stdout
@ -1119,7 +1168,6 @@ namespace chaiscript
State get_state() const State get_state() const
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
return m_state; return m_state;
} }
@ -1127,17 +1175,16 @@ namespace chaiscript
void set_state(const State &t_state) void set_state(const State &t_state)
{ {
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
m_state = t_state; m_state = t_state;
} }
void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params) static void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params)
{ {
t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(t_params)); t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(t_params));
} }
void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params) static void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params)
{ {
for (auto &&param : t_params) for (auto &&param : t_params)
{ {
@ -1145,7 +1192,7 @@ namespace chaiscript
} }
} }
void save_function_params(Stack_Holder &t_s, const std::vector<Boxed_Value> &t_params) static void save_function_params(Stack_Holder &t_s, const std::vector<Boxed_Value> &t_params)
{ {
t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end()); t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end());
} }
@ -1165,19 +1212,19 @@ namespace chaiscript
save_function_params(*m_stack_holder, t_params); save_function_params(*m_stack_holder, t_params);
} }
void new_function_call(Stack_Holder &t_s) void new_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves)
{ {
if (t_s.call_depth == 0) if (t_s.call_depth == 0)
{ {
m_conversions.enable_conversion_saves(true); m_conversions.enable_conversion_saves(t_saves, true);
} }
++t_s.call_depth; ++t_s.call_depth;
save_function_params(m_conversions.take_saves()); save_function_params(m_conversions.take_saves(t_saves));
} }
void pop_function_call(Stack_Holder &t_s) void pop_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves)
{ {
--t_s.call_depth; --t_s.call_depth;
@ -1186,18 +1233,18 @@ namespace chaiscript
if (t_s.call_depth == 0) if (t_s.call_depth == 0)
{ {
t_s.call_params.back().clear(); t_s.call_params.back().clear();
m_conversions.enable_conversion_saves(false); m_conversions.enable_conversion_saves(t_saves, false);
} }
} }
void new_function_call() void new_function_call()
{ {
new_function_call(*m_stack_holder); new_function_call(*m_stack_holder, m_conversions.conversion_saves());
} }
void pop_function_call() void pop_function_call()
{ {
pop_function_call(*m_stack_holder); pop_function_call(*m_stack_holder, m_conversions.conversion_saves());
} }
Stack_Holder &get_stack_holder() Stack_Holder &get_stack_holder()
@ -1205,7 +1252,6 @@ namespace chaiscript
return *m_stack_holder; return *m_stack_holder;
} }
private:
/// Returns the current stack /// Returns the current stack
/// make const/non const versions /// make const/non const versions
const StackData &get_stack_data() const const StackData &get_stack_data() const
@ -1213,7 +1259,7 @@ namespace chaiscript
return m_stack_holder->stacks.back(); return m_stack_holder->stacks.back();
} }
StackData &get_stack_data(Stack_Holder &t_holder) static StackData &get_stack_data(Stack_Holder &t_holder)
{ {
return t_holder.stacks.back(); return t_holder.stacks.back();
} }
@ -1223,32 +1269,34 @@ namespace chaiscript
return m_stack_holder->stacks.back(); return m_stack_holder->stacks.back();
} }
const std::map<std::string, Boxed_Value> &get_boxed_functions_int() const private:
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const
{ {
return m_state.m_boxed_functions; return m_state.m_boxed_functions;
} }
std::map<std::string, Boxed_Value> &get_boxed_functions_int() std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int()
{ {
return m_state.m_boxed_functions; return m_state.m_boxed_functions;
} }
const std::map<std::string, Proxy_Function> &get_function_objects_int() const const std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int() const
{ {
return m_state.m_function_objects; return m_state.m_function_objects;
} }
std::map<std::string, Proxy_Function> &get_function_objects_int() std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int()
{ {
return m_state.m_function_objects; return m_state.m_function_objects;
} }
const std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() const const std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int() const
{ {
return m_state.m_functions; return m_state.m_functions;
} }
std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int()
{ {
return m_state.m_functions; return m_state.m_functions;
} }
@ -1362,6 +1410,49 @@ namespace chaiscript
} }
} }
template<typename Container, typename Key, typename Value>
static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value)
{
auto itr = find_keyed_value(t_c, t_key);
if (itr == t_c.end()) {
t_c.reserve(t_c.size() + 1); // tightly control growth of memory usage here
t_c.emplace_back(t_key, std::forward<Value>(t_value));
} else {
typedef typename Container::value_type value_type;
*itr = value_type(t_key, std::forward<Value>(t_value));
}
}
template<typename Container, typename Key>
static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key)
{
return std::find_if(t_c.begin(), t_c.end(),
[&t_key](const typename Container::value_type &o) {
return o.first == t_key;
});
}
template<typename Container, typename Key>
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key)
{
return std::find_if(t_c.begin(), t_c.end(),
[&t_key](const typename Container::value_type &o) {
return o.first == t_key;
});
}
template<typename Container, typename Key>
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint)
{
if (t_c.size() > t_hint && t_c[t_hint].first == t_key) {
return t_c.begin() + t_hint;
} else {
return find_keyed_value(t_c, t_key);
}
}
/// Implementation detail for adding a function. /// Implementation detail for adding a function.
/// \throws exception::name_conflict_error if there's a function matching the given one being added /// \throws exception::name_conflict_error if there's a function matching the given one being added
void add_function(const Proxy_Function &t_f, const std::string &t_name) void add_function(const Proxy_Function &t_f, const std::string &t_name)
@ -1370,16 +1461,13 @@ namespace chaiscript
auto &funcs = get_functions_int(); auto &funcs = get_functions_int();
auto itr = funcs.find(t_name); auto itr = find_keyed_value(funcs, t_name);
auto &func_objs = get_function_objects_int();
auto &boxed_funcs = get_boxed_functions_int();
Proxy_Function new_func = Proxy_Function new_func =
[&]() -> Proxy_Function { [&]() -> Proxy_Function {
if (itr != funcs.end()) if (itr != funcs.end())
{ {
auto &vec = itr->second; auto vec = *itr->second;
for (const auto &func : vec) for (const auto &func : vec)
{ {
if ((*t_f) == *(func)) if ((*t_f) == *(func))
@ -1388,33 +1476,35 @@ namespace chaiscript
} }
} }
vec.reserve(vec.size() + 1); // tightly control vec growth
vec.push_back(t_f); vec.push_back(t_f);
std::stable_sort(vec.begin(), vec.end(), &function_less_than); std::stable_sort(vec.begin(), vec.end(), &function_less_than);
return std::make_shared<Dispatch_Function>(vec); itr->second = std::make_shared<std::vector<Proxy_Function>>(vec);
return std::make_shared<Dispatch_Function>(std::move(vec));
} else if (t_f->has_arithmetic_param()) { } else if (t_f->has_arithmetic_param()) {
// if the function is the only function but it also contains // if the function is the only function but it also contains
// arithmetic operators, we must wrap it in a dispatch function // arithmetic operators, we must wrap it in a dispatch function
// to allow for automatic arithmetic type conversions // to allow for automatic arithmetic type conversions
std::vector<Proxy_Function> vec({t_f}); std::vector<Proxy_Function> vec({t_f});
funcs.insert(std::make_pair(t_name, vec)); funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(vec));
return std::make_shared<Dispatch_Function>(std::move(vec)); return std::make_shared<Dispatch_Function>(std::move(vec));
} else { } else {
funcs.insert(std::make_pair(t_name, std::vector<Proxy_Function>{t_f})); funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(std::initializer_list<Proxy_Function>({t_f})));
return t_f; return t_f;
} }
}(); }();
boxed_funcs[t_name] = const_var(new_func); add_keyed_value(get_boxed_functions_int(), t_name, const_var(new_func));
func_objs[t_name] = std::move(new_func); add_keyed_value(get_function_objects_int(), t_name, std::move(new_func));
} }
mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::shared_mutex m_mutex;
mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex;
Type_Conversions m_conversions; Type_Conversions m_conversions;
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder; chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
mutable std::atomic_uint_fast32_t m_method_missing_loc;
State m_state; State m_state;
}; };
@ -1424,7 +1514,8 @@ namespace chaiscript
public: public:
Dispatch_State(Dispatch_Engine &t_engine) Dispatch_State(Dispatch_Engine &t_engine)
: m_engine(t_engine), : m_engine(t_engine),
m_stack_holder(t_engine.get_stack_holder()) m_stack_holder(t_engine.get_stack_holder()),
m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves())
{ {
} }
@ -1440,9 +1531,22 @@ namespace chaiscript
return m_stack_holder.get(); return m_stack_holder.get();
} }
const Type_Conversions_State &conversions() const {
return m_conversions;
}
Type_Conversions::Conversion_Saves &conversion_saves() const {
return m_conversions.saves();
}
void add_object(const std::string &t_name, Boxed_Value obj) const {
m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get());
}
private: private:
std::reference_wrapper<Dispatch_Engine> m_engine; std::reference_wrapper<Dispatch_Engine> m_engine;
std::reference_wrapper<Stack_Holder> m_stack_holder; std::reference_wrapper<Stack_Holder> m_stack_holder;
Type_Conversions_State m_conversions;
}; };
} }
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
@ -24,23 +24,55 @@ namespace chaiscript
{ {
namespace dispatch namespace dispatch
{ {
struct option_explicit_set : std::runtime_error {
option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
{
}
option_explicit_set(const option_explicit_set &) = default;
virtual ~option_explicit_set() CHAISCRIPT_NOEXCEPT {}
};
class Dynamic_Object class Dynamic_Object
{ {
public: public:
Dynamic_Object(std::string t_type_name) Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name)) : m_type_name(std::move(t_type_name)), m_option_explicit(false)
{ {
} }
Dynamic_Object() : m_type_name("") Dynamic_Object() : m_type_name(""), m_option_explicit(false)
{ {
} }
bool is_explicit() const
{
return m_option_explicit;
}
void set_explicit(const bool t_explicit)
{
m_option_explicit = t_explicit;
}
std::string get_type_name() const std::string get_type_name() const
{ {
return m_type_name; 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 const Boxed_Value &get_attr(const std::string &t_attr_name) const
{ {
auto a = m_attrs.find(t_attr_name); auto a = m_attrs.find(t_attr_name);
@ -59,11 +91,19 @@ namespace chaiscript
Boxed_Value &method_missing(const std::string &t_method_name) Boxed_Value &method_missing(const std::string &t_method_name)
{ {
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name);
}
return get_attr(t_method_name); return get_attr(t_method_name);
} }
const Boxed_Value &method_missing(const std::string &t_method_name) const const Boxed_Value &method_missing(const std::string &t_method_name) const
{ {
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name);
}
return get_attr(t_method_name); return get_attr(t_method_name);
} }
@ -75,6 +115,7 @@ namespace chaiscript
private: private:
std::string m_type_name; std::string m_type_name;
bool m_option_explicit;
std::map<std::string, Boxed_Value> m_attrs; std::map<std::string, Boxed_Value> m_attrs;
}; };

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
@ -84,7 +84,7 @@ namespace chaiscript
virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return m_is_attribute; } virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return m_is_attribute; }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{ {
@ -106,7 +106,7 @@ namespace chaiscript
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{ {
@ -116,7 +116,7 @@ namespace chaiscript
} }
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
} }
@ -134,7 +134,7 @@ namespace chaiscript
} }
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
{ {
if (bv.get_type_info().bare_equal(m_doti)) if (bv.get_type_info().bare_equal(m_doti))
{ {
@ -156,7 +156,7 @@ namespace chaiscript
} }
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name, bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
{ {
if (bvs.size() > 0) if (bvs.size() > 0)
{ {
@ -216,7 +216,7 @@ namespace chaiscript
return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))}; std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.insert(new_vals.end(), vals.begin(), vals.end()); new_vals.insert(new_vals.end(), vals.begin(), vals.end());
@ -230,9 +230,9 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
auto bv = var(Dynamic_Object(m_type_name)); auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
std::vector<Boxed_Value> new_params{bv}; std::vector<Boxed_Value> new_params{bv};
new_params.insert(new_params.end(), params.begin(), params.end()); new_params.insert(new_params.end(), params.begin(), params.end());

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
@ -32,7 +32,7 @@ namespace chaiscript
protected: protected:
template<typename T> template<typename T>
void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) 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 &) {} try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
@ -14,10 +14,11 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "function_call_detail.hpp" #include "function_call_detail.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "callable_traits.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Value; class Boxed_Value;
class Type_Conversions; class Type_Conversions_State;
namespace detail { namespace detail {
template <typename T> struct Cast_Helper; template <typename T> struct Cast_Helper;
} // namespace detail } // namespace detail
@ -35,8 +36,17 @@ namespace chaiscript
/// \param[in] funcs the set of functions to dispatch on. /// \param[in] funcs the set of functions to dispatch on.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions) 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;
});
if (!has_arity_match) {
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
}
FunctionType *p=nullptr; FunctionType *p=nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions); return detail::build_function_caller_helper(p, funcs, t_conversions);
} }
@ -54,7 +64,7 @@ namespace chaiscript
/// \param[in] func A function to execute. /// \param[in] func A function to execute.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType>
functor(Const_Proxy_Function func, const Type_Conversions *t_conversions) functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions)
{ {
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions); return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
} }
@ -63,7 +73,7 @@ namespace chaiscript
/// and creating a typesafe C++ function caller from it. /// and creating a typesafe C++ function caller from it.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType>
functor(const Boxed_Value &bv, const Type_Conversions *t_conversions) functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions)
{ {
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions); return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
} }
@ -76,7 +86,7 @@ namespace chaiscript
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@ -93,7 +103,7 @@ namespace chaiscript
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@ -110,7 +120,7 @@ namespace chaiscript
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
@ -31,9 +31,15 @@ namespace chaiscript
struct Function_Caller_Ret struct Function_Caller_Ret
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{ {
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()), t_conversions); if (t_conversions) {
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);
}
} }
}; };
@ -44,9 +50,15 @@ namespace chaiscript
struct Function_Caller_Ret<Ret, true> struct Function_Caller_Ret<Ret, true>
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{ {
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions())).get_as<Ret>(); if (t_conversions) {
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>();
}
} }
}; };
@ -58,9 +70,15 @@ namespace chaiscript
struct Function_Caller_Ret<void, false> struct Function_Caller_Ret<void, false>
{ {
static void call(const std::vector<Const_Proxy_Function> &t_funcs, static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{ {
dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()); if (t_conversions) {
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);
}
} }
}; };
@ -79,11 +97,18 @@ namespace chaiscript
template<typename ... P> template<typename ... P>
Ret operator()(P&& ... param) 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, { 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))... box<P>(std::forward<P>(param))...
}, m_conversions }, &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
);
}
} }
@ -114,7 +139,7 @@ namespace chaiscript
/// \todo what happens if t_conversions is deleted out from under us?! /// \todo what happens if t_conversions is deleted out from under us?!
template<typename Ret, typename ... Params> 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 *t_conversions) 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) if (funcs.size() == 1)
@ -132,7 +157,7 @@ namespace chaiscript
} }
*/ */
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions)); return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?t_conversions->get():nullptr));
} }
} }
} }

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@ -43,7 +43,7 @@ namespace chaiscript
namespace dispatch namespace dispatch
{ {
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func, const Type_Conversions *t_conversions); std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func, const Type_Conversions_State *t_conversions);
class Param_Types class Param_Types
{ {
@ -72,7 +72,7 @@ namespace chaiscript
return m_types == t_rhs.m_types; return m_types == t_rhs.m_types;
} }
bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
{ {
if (!m_has_types) return true; if (!m_has_types) return true;
if (vals.size() != m_types.size()) return false; if (vals.size() != m_types.size()) return false;
@ -147,7 +147,7 @@ namespace chaiscript
public: public:
virtual ~Proxy_Function_Base() {} virtual ~Proxy_Function_Base() {}
Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions &t_conversions) const Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions_State &t_conversions) const
{ {
if (m_arity < 0 || size_t(m_arity) == params.size()) { if (m_arity < 0 || size_t(m_arity) == params.size()) {
return do_call(params, t_conversions); return do_call(params, t_conversions);
@ -163,7 +163,7 @@ namespace chaiscript
const std::vector<Type_Info> &get_param_types() const { return m_types; } const std::vector<Type_Info> &get_param_types() const { return m_types; }
virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0;
virtual bool is_attribute_function() const { return false; } virtual bool is_attribute_function() const { return false; }
@ -179,7 +179,7 @@ namespace chaiscript
//! Return true if the function is a possible match //! Return true if the function is a possible match
//! to the passed in values //! to the passed in values
bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
{ {
if (m_arity < 0) if (m_arity < 0)
{ {
@ -206,15 +206,15 @@ namespace chaiscript
virtual std::string annotation() const = 0; virtual std::string annotation() const = 0;
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions) static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions)
{ {
if (ti.is_undef() if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>()) || ti.bare_equal(user_type<Boxed_Value>())
|| (!bv.get_type_info().is_undef() || (!bv.get_type_info().is_undef()
&& (ti.bare_equal(user_type<Boxed_Number>()) && ( (ti.bare_equal(user_type<Boxed_Number>()) && bv.get_type_info().is_arithmetic())
|| ti.bare_equal(bv.get_type_info()) || ti.bare_equal(bv.get_type_info())
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >()) || bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|| t_conversions.converts(ti, bv.get_type_info()) || t_conversions->converts(ti, bv.get_type_info())
) )
) )
) )
@ -225,13 +225,13 @@ namespace chaiscript
} }
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const
{ {
return compare_type_to_param(m_types[1], bv, t_conversions); return compare_type_to_param(m_types[1], bv, t_conversions);
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const = 0; virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const = 0;
Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity) Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
: m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false) : m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false)
@ -248,7 +248,7 @@ namespace chaiscript
} }
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs, const Type_Conversions_State &t_conversions)
{ {
if (tis.size() - 1 != bvs.size()) if (tis.size() - 1 != bvs.size())
{ {
@ -257,10 +257,7 @@ namespace chaiscript
const size_t size = bvs.size(); const size_t size = bvs.size();
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
{ {
if (!(tis[i+1].bare_equal(bvs[i].get_type_info()) && tis[i+1].is_const() >= bvs[i].get_type_info().is_const() )) if (!compare_type_to_param(tis[i + 1], bvs[i], t_conversions)) { return false; }
{
return false;
}
} }
} }
return true; return true;
@ -330,7 +327,7 @@ namespace chaiscript
&& this->m_param_types == prhs->m_param_types); && this->m_param_types == prhs->m_param_types);
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions))) return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions)))
&& test_guard(vals, t_conversions); && test_guard(vals, t_conversions);
@ -354,7 +351,7 @@ namespace chaiscript
protected: protected:
bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const
{ {
if (m_guard) if (m_guard)
{ {
@ -422,7 +419,7 @@ namespace chaiscript
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (call_match(params, t_conversions) && test_guard(params, t_conversions)) if (call_match(params, t_conversions) && test_guard(params, t_conversions))
{ {
@ -472,7 +469,7 @@ namespace chaiscript
virtual ~Bound_Function() {} virtual ~Bound_Function() {}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return m_f->call_match(build_param_list(vals), t_conversions); return m_f->call_match(build_param_list(vals), t_conversions);
} }
@ -551,7 +548,7 @@ namespace chaiscript
return retval; return retval;
} }
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return (*m_f)(build_param_list(params), t_conversions); return (*m_f)(build_param_list(params), t_conversions);
} }
@ -576,12 +573,12 @@ namespace chaiscript
return ""; return "";
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return static_cast<int>(vals.size()) == get_arity() && (compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions)); return static_cast<int>(vals.size()) == get_arity() && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions));
} }
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0; virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0;
}; };
@ -599,7 +596,7 @@ namespace chaiscript
virtual ~Proxy_Function_Callable_Impl() {} virtual ~Proxy_Function_Callable_Impl() {}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions); return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
} }
@ -611,7 +608,7 @@ namespace chaiscript
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
typedef typename detail::Function_Signature<Func>::Return_Type Return_Type; typedef typename detail::Function_Signature<Func>::Return_Type Return_Type;
return detail::Do_Call<Return_Type>::template go<Func>(m_f, params, t_conversions); return detail::Do_Call<Return_Type>::template go<Func>(m_f, params, t_conversions);
@ -651,7 +648,7 @@ namespace chaiscript
virtual ~Assignable_Proxy_Function_Impl() {} virtual ~Assignable_Proxy_Function_Impl() {}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions); return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
} }
@ -671,7 +668,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return detail::Do_Call<typename std::function<Func>::result_type>::template go<Func>(m_f.get(), params, t_conversions); return detail::Do_Call<typename std::function<Func>::result_type>::template go<Func>(m_f.get(), params, t_conversions);
} }
@ -708,7 +705,7 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &) const CHAISCRIPT_OVERRIDE
{ {
if (vals.size() != 1) if (vals.size() != 1)
{ {
@ -724,7 +721,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
const Boxed_Value &bv = params[0]; const Boxed_Value &bv = params[0];
if (bv.is_const()) if (bv.is_const())
@ -763,6 +760,14 @@ namespace chaiscript
{ {
} }
dispatch_error(std::vector<Boxed_Value> t_parameters,
std::vector<Const_Proxy_Function> t_functions,
const std::string &t_desc)
: std::runtime_error(t_desc), parameters(std::move(t_parameters)), functions(std::move(t_functions))
{
}
dispatch_error(const dispatch_error &) = default; dispatch_error(const dispatch_error &) = default;
virtual ~dispatch_error() CHAISCRIPT_NOEXCEPT {} virtual ~dispatch_error() CHAISCRIPT_NOEXCEPT {}
@ -777,7 +782,7 @@ namespace chaiscript
{ {
template<typename FuncType> template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist, bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
const Type_Conversions &t_conversions) const Type_Conversions_State &t_conversions)
{ {
const std::vector<Type_Info> &types = t_func->get_param_types(); const std::vector<Type_Info> &types = t_func->get_param_types();
@ -796,7 +801,7 @@ namespace chaiscript
template<typename InItr, typename Funcs> template<typename InItr, typename Funcs>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist, Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
const Type_Conversions &t_conversions, const Funcs &t_funcs) const Type_Conversions_State &t_conversions, const Funcs &t_funcs)
{ {
InItr matching_func(end); InItr matching_func(end);
@ -873,7 +878,7 @@ namespace chaiscript
*/ */
template<typename Funcs> template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs, Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions) const std::vector<Boxed_Value> &plist, const Type_Conversions_State &t_conversions)
{ {
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs; std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
ordered_funcs.reserve(funcs.size()); ordered_funcs.reserve(funcs.size());

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
@ -19,7 +19,7 @@
#include "callable_traits.hpp" #include "callable_traits.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions_State;
namespace exception { namespace exception {
class bad_boxed_cast; class bad_boxed_cast;
} // namespace exception } // namespace exception
@ -77,7 +77,7 @@ namespace chaiscript
template<typename Param, typename ... Rest> template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...> struct Try_Cast<Param, Rest...>
{ {
static void do_try(const std::vector<Boxed_Value> &params, size_t generation, const Type_Conversions &t_conversions) static void do_try(const std::vector<Boxed_Value> &params, size_t generation, const Type_Conversions_State &t_conversions)
{ {
boxed_cast<Param>(params[generation], &t_conversions); boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions); Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
@ -88,7 +88,7 @@ namespace chaiscript
template<> template<>
struct Try_Cast<> struct Try_Cast<>
{ {
static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions &) static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions_State &)
{ {
} }
}; };
@ -101,7 +101,7 @@ namespace chaiscript
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...), bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
try { try {
Try_Cast<Params...>::do_try(params, 0, t_conversions); Try_Cast<Params...>::do_try(params, 0, t_conversions);
@ -118,7 +118,7 @@ namespace chaiscript
template<typename Callable, typename ... InnerParams> template<typename Callable, typename ... InnerParams>
static Ret do_call(const Callable &f, static Ret do_call(const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions, InnerParams &&... innerparams) const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions, InnerParams &&... innerparams)
{ {
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]); return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
} }
@ -133,7 +133,7 @@ namespace chaiscript
#endif #endif
template<typename Callable, typename ... InnerParams> template<typename Callable, typename ... InnerParams>
static Ret do_call(const Callable &f, static Ret do_call(const Callable &f,
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams) const std::vector<Boxed_Value> &, const Type_Conversions_State &t_conversions, InnerParams &&... innerparams)
{ {
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...); return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
} }
@ -150,7 +150,7 @@ namespace chaiscript
*/ */
template<typename Callable, typename Ret, typename ... Params> template<typename Callable, typename Ret, typename ... Params>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, const Callable &f, Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
if (params.size() == sizeof...(Params)) if (params.size() == sizeof...(Params))
{ {
@ -190,7 +190,7 @@ namespace chaiscript
*/ */
template<typename Ret, typename ... Params, size_t ... I> template<typename Ret, typename ... Params, size_t ... I>
bool compare_types_cast(Indexes<I...>, Ret (*)(Params...), bool compare_types_cast(Indexes<I...>, Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
try { try {
(void)params; (void)t_conversions; (void)params; (void)t_conversions;
@ -204,7 +204,7 @@ namespace chaiscript
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*f)(Params...), bool compare_types_cast(Ret (*f)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes; typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
return compare_types_cast(indexes(), f, params, t_conversions); return compare_types_cast(indexes(), f, params, t_conversions);
@ -213,7 +213,7 @@ namespace chaiscript
template<typename Callable, typename Ret, typename ... Params, size_t ... I> template<typename Callable, typename Ret, typename ... Params, size_t ... I>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, Indexes<I...>, const Callable &f, Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, Indexes<I...>, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
(void)params; (void)t_conversions; (void)params; (void)t_conversions;
return f(boxed_cast<Params>(params[I], &t_conversions)...); return f(boxed_cast<Params>(params[I], &t_conversions)...);
@ -228,7 +228,7 @@ namespace chaiscript
*/ */
template<typename Callable, typename Ret, typename ... Params> template<typename Callable, typename Ret, typename ... Params>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f, Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes; typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
return call_func(sig, indexes(), f, params, t_conversions); return call_func(sig, indexes(), f, params, t_conversions);
@ -252,7 +252,7 @@ namespace chaiscript
struct Do_Call struct Do_Call
{ {
template<typename Signature, typename Callable> template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions)); return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions));
} }
@ -262,7 +262,7 @@ namespace chaiscript
struct Do_Call<void> struct Do_Call<void>
{ {
template<typename Signature, typename Callable> template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{ {
call_func(Function_Signature<Signature>(), fun, params, t_conversions); call_func(Function_Signature<Signature>(), fun, params, t_conversions);
return Handle_Return<void>::handle(); return Handle_Return<void>::handle();

View File

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

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
@ -310,12 +310,21 @@ namespace chaiscript
private: private:
Callable m_func; Callable m_func;
}; };
} }
class Type_Conversions class Type_Conversions
{ {
public: public:
struct Conversion_Saves
{
Conversion_Saves()
: enabled(false)
{}
bool enabled;
std::vector<Boxed_Value> saves;
};
struct Less_Than struct Less_Than
{ {
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
@ -387,15 +396,14 @@ namespace chaiscript
} else { } else {
return false; return false;
} }
} }
template<typename To> template<typename To>
Boxed_Value boxed_type_conversion(const Boxed_Value &from) const Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
{ {
try { try {
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from); Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret); if (t_saves.enabled) t_saves.saves.push_back(ret);
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion"); throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion");
@ -405,11 +413,11 @@ namespace chaiscript
} }
template<typename From> template<typename From>
Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const
{ {
try { try {
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to); Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret); if (t_saves.enabled) t_saves.saves.push_back(ret);
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion"); throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion");
@ -418,15 +426,15 @@ namespace chaiscript
} }
} }
void enable_conversion_saves(bool t_val) static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val)
{ {
m_conversion_saves->enabled = t_val; t_saves.enabled = t_val;
} }
std::vector<Boxed_Value> take_saves() std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves)
{ {
std::vector<Boxed_Value> ret; std::vector<Boxed_Value> ret;
std::swap(ret, m_conversion_saves->saves); std::swap(ret, t_saves.saves);
return ret; return ret;
} }
@ -450,6 +458,10 @@ namespace chaiscript
} }
} }
Conversion_Saves &conversion_saves() const {
return *m_conversion_saves;
}
private: private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir( std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir(
const Type_Info &to, const Type_Info &from) const const Type_Info &to, const Type_Info &from) const
@ -459,7 +471,6 @@ namespace chaiscript
{ {
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from)) return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from)); || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
;
} }
); );
} }
@ -483,15 +494,6 @@ namespace chaiscript
} }
struct Conversion_Saves
{
Conversion_Saves()
: enabled(false)
{}
bool enabled;
std::vector<Boxed_Value> saves;
};
mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions; std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
@ -501,6 +503,33 @@ namespace chaiscript
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves; mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
}; };
class Type_Conversions_State
{
public:
Type_Conversions_State(const Type_Conversions &t_conversions,
Type_Conversions::Conversion_Saves &t_saves)
: m_conversions(t_conversions),
m_saves(t_saves)
{
}
const Type_Conversions *operator->() const {
return &m_conversions.get();
}
const Type_Conversions *get() const {
return &m_conversions.get();
}
Type_Conversions::Conversion_Saves &saves() const {
return m_saves;
}
private:
std::reference_wrapper<const Type_Conversions> m_conversions;
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
};
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion; typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you /// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
@ -582,7 +611,7 @@ namespace chaiscript
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr); const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
To vec; To vec;
vec.reserve(from_vec.size());
for (const Boxed_Value &bv : from_vec) { for (const Boxed_Value &bv : from_vec) {
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr)); vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
} }
@ -593,6 +622,22 @@ namespace chaiscript
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func);
} }
template<typename To>
Type_Conversion map_conversion()
{
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::map<std::string, Boxed_Value> &from_map = detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
To map;
for (const std::pair<std::string, Boxed_Value> &p : from_map) {
map.insert(std::make_pair(p.first, detail::Cast_Helper<typename To::mapped_type>::cast(p.second, nullptr)));
}
return Boxed_Value(std::move(map));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
}
} }

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_TYPE_INFO_HPP_ #ifndef CHAISCRIPT_TYPE_INFO_HPP_
@ -32,17 +32,17 @@ namespace chaiscript
CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void, CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti) 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_type_info(t_ti), m_bare_type_info(t_bare_ti),
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer), m_flags((t_is_const << is_const_flag)
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic), + (t_is_reference << is_reference_flag)
m_is_undef(false) + (t_is_pointer << is_pointer_flag)
+ (t_is_void << is_void_flag)
+ (t_is_arithmetic << is_arithmetic_flag))
{ {
} }
CHAISCRIPT_CONSTEXPR Type_Info() CHAISCRIPT_CONSTEXPR Type_Info()
: m_type_info(nullptr), m_bare_type_info(nullptr), : m_type_info(nullptr), m_bare_type_info(nullptr),
m_is_const(false), m_is_reference(false), m_is_pointer(false), m_flags(1 << is_undef_flag)
m_is_void(false), m_is_arithmetic(false),
m_is_undef(true)
{ {
} }
@ -83,12 +83,12 @@ namespace chaiscript
&& (*m_bare_type_info) == ti; && (*m_bare_type_info) == ti;
} }
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; } CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_const_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; } CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_reference_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; } CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_void_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; } CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef; } CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_undef_flag)) != 0; }
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; } CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_pointer_flag)) != 0; }
std::string name() const std::string name() const
{ {
@ -118,12 +118,13 @@ namespace chaiscript
private: private:
const std::type_info *m_type_info; const std::type_info *m_type_info;
const std::type_info *m_bare_type_info; const std::type_info *m_bare_type_info;
bool m_is_const; unsigned int m_flags;
bool m_is_reference; static const int is_const_flag = 0;
bool m_is_pointer; static const int is_reference_flag = 1;
bool m_is_void; static const int is_pointer_flag = 2;
bool m_is_arithmetic; static const int is_void_flag = 3;
bool m_is_undef; static const int is_arithmetic_flag = 4;
static const int is_undef_flag = 5;
}; };
namespace detail namespace detail

View File

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

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_COMMON_HPP_ #ifndef CHAISCRIPT_COMMON_HPP_
@ -34,7 +34,7 @@ namespace chaiscript
/// Types of AST nodes available to the parser and eval /// Types of AST nodes available to the parser and eval
class AST_Node_Type { class AST_Node_Type {
public: public:
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl, enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or, Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
@ -47,7 +47,7 @@ namespace chaiscript
/// Helper lookup to get the name of each node type /// Helper lookup to get the name of each node type
const char *ast_node_type_to_string(int ast_node_type) { const char *ast_node_type_to_string(int ast_node_type) {
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl", const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String", "Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or", "Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
@ -582,12 +582,12 @@ namespace chaiscript
Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds)
{ {
m_ds.get()->new_function_call(m_ds.get().stack_holder()); m_ds.get()->new_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
} }
~Function_Push_Pop() ~Function_Push_Pop()
{ {
m_ds.get()->pop_function_call(m_ds.get().stack_holder()); m_ds.get()->pop_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
} }
void save_params(const std::vector<Boxed_Value> &t_params) void save_params(const std::vector<Boxed_Value> &t_params)

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_ENGINE_HPP_ #ifndef CHAISCRIPT_ENGINE_HPP_
@ -36,7 +36,9 @@
#else #else
#ifdef CHAISCRIPT_WINDOWS #ifdef CHAISCRIPT_WINDOWS
#define VC_EXTRA_LEAN #define VC_EXTRA_LEAN
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h> #include <windows.h>
#endif #endif
#endif #endif
@ -175,11 +177,11 @@ namespace chaiscript
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, nullptr,
t_err, t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<StringType>(&lpMsgBuf), reinterpret_cast<StringType>(&lpMsgBuf),
0, NULL ) != 0 && lpMsgBuf) 0, nullptr ) != 0 && lpMsgBuf)
{ {
retval = lpMsgBuf; retval = lpMsgBuf;
LocalFree(lpMsgBuf); LocalFree(lpMsgBuf);
@ -284,14 +286,7 @@ namespace chaiscript
const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast)
{
try {
return t_ast->eval(m_engine);
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
}
/// Evaluates the given file and looks in the 'use' paths /// Evaluates the given file and looks in the 'use' paths
const Boxed_Value internal_eval_file(const std::string &t_filename) { const Boxed_Value internal_eval_file(const std::string &t_filename) {
@ -347,6 +342,7 @@ namespace chaiscript
m_engine.add_reserved_word("class"); m_engine.add_reserved_word("class");
m_engine.add_reserved_word("attr"); m_engine.add_reserved_word("attr");
m_engine.add_reserved_word("var"); m_engine.add_reserved_word("var");
m_engine.add_reserved_word("global");
m_engine.add_reserved_word("GLOBAL"); m_engine.add_reserved_word("GLOBAL");
m_engine.add_reserved_word("_"); m_engine.add_reserved_word("_");
@ -372,11 +368,15 @@ namespace chaiscript
// m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call"); // m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
// //
//
m_engine.add(fun( m_engine.add(fun(
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) { [=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
return t_fun(t_params, this->m_engine.conversions()); Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves());
return t_fun(t_params, s);
}), "call"); }), "call");
m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name"); m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name");
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type"); m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type");
@ -396,16 +396,21 @@ namespace chaiscript
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 use(t_file); }), "use");
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file"); m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval"); m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
m_engine.add(fun([this](const AST_NodePtr &t_ast){ return internal_eval_ast(t_ast); }), "eval"); m_engine.add(fun([this](const AST_NodePtr &t_ast){ return eval(t_ast); }), "eval");
m_engine.add(fun(&parse), "parse");
m_engine.add(fun(&ChaiScript::version_major), "version_major"); m_engine.add(fun(&ChaiScript::version_major), "version_major");
m_engine.add(fun(&ChaiScript::version_minor), "version_minor"); m_engine.add(fun(&ChaiScript::version_minor), "version_minor");
m_engine.add(fun(&ChaiScript::version_patch), "version_patch"); m_engine.add(fun(&ChaiScript::version_patch), "version_patch");
m_engine.add(fun(&ChaiScript::version), "version"); m_engine.add(fun(&ChaiScript::version), "version");
m_engine.add(fun(&ChaiScript::compiler_version), "compiler_version");
m_engine.add(fun(&ChaiScript::compiler_name), "compiler_name");
m_engine.add(fun(&ChaiScript::compiler_id), "compiler_id");
m_engine.add(fun(&ChaiScript::debug_build), "debug_build");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
} }
@ -517,6 +522,28 @@ namespace chaiscript
build_eval_system(ModulePtr()); build_eval_system(ModulePtr());
} }
const Boxed_Value eval(const AST_NodePtr &t_ast)
{
try {
return t_ast->eval(m_engine);
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
}
static AST_NodePtr parse(const std::string &t_input)
{
parser::ChaiScript_Parser parser;
if (parser.parse(t_input, "PARSE")) {
//parser.show_match_stack();
return parser.optimized_ast();
} else {
throw chaiscript::exception::eval_error("Unknown error while parsing");
}
}
static int version_major() static int version_major()
{ {
return chaiscript::version_major; return chaiscript::version_major;
@ -534,11 +561,36 @@ namespace chaiscript
static std::string version() static std::string version()
{ {
std::stringstream ss; return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
ss << version_major() << "." << version_minor() << "." << version_patch();
return ss.str();
} }
static std::string compiler_id()
{
return compiler_name() + '-' + compiler_version();
}
static std::string build_id()
{
return compiler_id() + (debug_build()?"-Debug":"-Release");
}
static std::string compiler_version()
{
return chaiscript::compiler_version;
}
static std::string compiler_name()
{
return chaiscript::compiler_name;
}
static bool debug_build()
{
return chaiscript::debug_build;
}
std::string get_type_name(const Type_Info &ti) const std::string get_type_name(const Type_Info &ti) const
{ {
return m_engine.get_type_name(ti); return m_engine.get_type_name(ti);
@ -608,6 +660,12 @@ namespace chaiscript
return *this; return *this;
} }
ChaiScript &set_global(const Boxed_Value &t_bv, const std::string &t_name)
{
m_engine.set_global(t_bv, t_name);
return *this;
}
/// \brief Represents the current state of the ChaiScript system. State and be saved and restored /// \brief Represents the current state of the ChaiScript system. State and be saved and restored
/// \warning State object does not contain the user defined type conversions of the engine. They /// \warning State object does not contain the user defined type conversions of the engine. They
/// are left out due to performance considerations involved in tracking the state /// are left out due to performance considerations involved in tracking the state

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_EVAL_HPP_ #ifndef CHAISCRIPT_EVAL_HPP_
@ -44,16 +44,33 @@ namespace chaiscript
namespace detail namespace detail
{ {
/// Helper function that will set up the scope around a function call, including handling the named function parameters /// Helper function that will set up the scope around a function call, including handling the named function parameters
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> &t_locals=std::map<std::string, Boxed_Value>()) { static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr) {
chaiscript::detail::Dispatch_State state(t_ss); chaiscript::detail::Dispatch_State state(t_ss);
chaiscript::eval::detail::Scope_Push_Pop spp(state);
for (const auto &local : t_locals) { const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
t_ss.add_object(local.first, local.second); auto &stack = t_ss.get_stack_data(state.stack_holder()).back();
if (!stack.empty() && stack.back().first == "__this") {
return &stack.back().second;
} else if (!t_vals.empty()) {
return &t_vals[0];
} else {
return nullptr;
}
}();
chaiscript::eval::detail::Stack_Push_Pop tpp(state);
if (thisobj) state.add_object("this", *thisobj);
if (t_locals) {
for (const auto &local : *t_locals) {
state.add_object(local.first, local.second);
}
} }
for (size_t i = 0; i < t_param_names.size(); ++i) { for (size_t i = 0; i < t_param_names.size(); ++i) {
t_ss.add_object(t_param_names[i], t_vals[i]); if (t_param_names[i] != "this") {
state.add_object(t_param_names[i], t_vals[i]);
}
} }
try { try {
@ -73,9 +90,9 @@ namespace chaiscript
virtual ~Binary_Operator_AST_Node() {} virtual ~Binary_Operator_AST_Node() {}
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
return do_oper(t_ss, m_oper, text, auto lhs = this->children[0]->eval(t_ss);
this->children[0]->eval(t_ss), auto rhs = this->children[1]->eval(t_ss);
this->children[1]->eval(t_ss)); return do_oper(t_ss, m_oper, text, lhs, rhs);
} }
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
@ -101,8 +118,7 @@ namespace chaiscript
} else { } else {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
fpp.save_params({t_lhs, t_rhs}); fpp.save_params({t_lhs, t_rhs});
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}, t_ss.conversions());
return t_ss->call_function(t_oper_string, t_lhs, t_rhs);
} }
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
@ -112,13 +128,14 @@ namespace chaiscript
private: private:
Operators::Opers m_oper; Operators::Opers m_oper;
mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Int_AST_Node : public AST_Node { struct Int_AST_Node : public AST_Node {
public: public:
Int_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) : Int_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)), AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)),
m_value(std::move(t_bv)) { } m_value(std::move(t_bv)) { assert(text != ""); }
virtual ~Int_AST_Node() {} virtual ~Int_AST_Node() {}
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
return m_value; return m_value;
@ -236,8 +253,7 @@ namespace chaiscript
Boxed_Value fn(this->children[0]->eval(t_ss)); Boxed_Value fn(this->children[0]->eval(t_ss));
try { try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); return (*t_ss->boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss.conversions());
return (*t_ss->boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss->conversions());
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss); throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
@ -286,73 +302,6 @@ namespace chaiscript
/// Used in the context of in-string ${} evals, so that no new scope is created
struct Inplace_Fun_Call_AST_Node : public AST_Node {
public:
Inplace_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(t_ast_node_text, AST_Node_Type::Inplace_Fun_Call, std::move(t_loc), std::move(t_children))
{ assert(children.size() == 2); }
virtual ~Inplace_Fun_Call_AST_Node() {}
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params;
params.reserve(this->children[1]->children.size());
for (const auto &child : this->children[1]->children) {
params.push_back(child->eval(t_ss));
}
Const_Proxy_Function fn;
try {
Boxed_Value bv = this->children[0]->eval(t_ss);
try {
fn = t_ss->boxed_cast<const Const_Proxy_Function &>(bv);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
}
return (*fn)(params, t_ss->conversions());
}
catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
}
catch(const exception::bad_boxed_cast &){
// handle the case where there is only 1 function to try to call and dispatch fails on it
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {fn}, false, *t_ss);
}
catch(const exception::arity_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(const exception::guard_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(detail::Return_Value &rv) {
return rv.retval;
}
}
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
{
std::ostringstream oss;
int count = 0;
for (const auto &child : this->children) {
oss << child->pretty_print();
if (count == 0)
{
oss << "(";
}
++count;
}
oss << ")";
return oss.str();
}
};
struct Arg_AST_Node : public AST_Node { struct Arg_AST_Node : public AST_Node {
public: public:
Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
@ -448,6 +397,8 @@ namespace chaiscript
{ assert(children.size() == 3); } { assert(children.size() == 3); }
Operators::Opers m_oper; Operators::Opers m_oper;
mutable std::atomic_uint_fast32_t m_loc;
mutable std::atomic_uint_fast32_t m_clone_loc;
virtual ~Equation_AST_Node() {} virtual ~Equation_AST_Node() {}
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
@ -483,14 +434,14 @@ namespace chaiscript
} else { } else {
if (!rhs.is_return_value()) if (!rhs.is_return_value())
{ {
rhs = t_ss->call_function("clone", rhs); rhs = t_ss->call_function("clone", m_clone_loc, {rhs}, t_ss.conversions());
} }
rhs.reset_return_value(); rhs.reset_return_value();
} }
} }
try { try {
return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs); return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss); throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss);
@ -503,13 +454,14 @@ namespace chaiscript
else if (this->children[1]->text == ":=") { else if (this->children[1]->text == ":=") {
if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) { if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) {
lhs.assign(rhs); lhs.assign(rhs);
lhs.reset_return_value();
} else { } else {
throw exception::eval_error("Mismatched types in equation"); throw exception::eval_error("Mismatched types in equation");
} }
} }
else { else {
try { try {
return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs); return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
} catch(const exception::dispatch_error &e){ } catch(const exception::dispatch_error &e){
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss); throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss);
} }
@ -560,7 +512,7 @@ namespace chaiscript
try { try {
Boxed_Value bv; Boxed_Value bv;
t_ss->add_object(idname, bv); t_ss.add_object(idname, bv);
return bv; return bv;
} }
catch (const exception::reserved_word_error &) { catch (const exception::reserved_word_error &) {
@ -591,9 +543,8 @@ namespace chaiscript
std::vector<Boxed_Value> params{children[0]->eval(t_ss), children[1]->eval(t_ss)}; std::vector<Boxed_Value> params{children[0]->eval(t_ss), children[1]->eval(t_ss)};
try { try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
fpp.save_params(params); fpp.save_params(params);
return t_ss->call_function("[]", params); return t_ss->call_function("[]", m_loc, params, t_ss.conversions());
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss ); throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss );
@ -615,6 +566,8 @@ namespace chaiscript
return oss.str(); return oss.str();
} }
mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Dot_Access_AST_Node : public AST_Node { struct Dot_Access_AST_Node : public AST_Node {
@ -629,6 +582,7 @@ namespace chaiscript
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value retval = children[0]->eval(t_ss); Boxed_Value retval = children[0]->eval(t_ss);
std::vector<Boxed_Value> params{retval}; std::vector<Boxed_Value> params{retval};
@ -643,9 +597,7 @@ namespace chaiscript
fpp.save_params(params); fpp.save_params(params);
try { try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params, t_ss.conversions());
t_ss->add_object("this", retval);
retval = t_ss->call_member(m_fun_name, std::move(params), has_function_params);
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
if (e.functions.empty()) if (e.functions.empty())
@ -661,7 +613,7 @@ namespace chaiscript
if (this->children[2]->identifier == AST_Node_Type::Array_Call) { if (this->children[2]->identifier == AST_Node_Type::Array_Call) {
try { try {
retval = t_ss->call_function("[]", retval, this->children[2]->children[1]->eval(t_ss)); retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[2]->children[1]->eval(t_ss)}, t_ss.conversions());
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss); throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss);
@ -672,6 +624,8 @@ namespace chaiscript
} }
private: private:
mutable std::atomic_uint_fast32_t m_loc;
mutable std::atomic_uint_fast32_t m_array_loc;
std::string m_fun_name; std::string m_fun_name;
}; };
@ -745,7 +699,7 @@ namespace chaiscript
dispatch::make_dynamic_proxy_function( dispatch::make_dynamic_proxy_function(
[engine, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params) [engine, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params)
{ {
return detail::eval_function(engine, lambda_node, param_names, t_params, captures); return detail::eval_function(engine, lambda_node, param_names, t_params, &captures);
}, },
static_cast<int>(numparams), lambda_node, param_types static_cast<int>(numparams), lambda_node, param_types
) )
@ -876,7 +830,7 @@ namespace chaiscript
/// \todo do this better /// \todo do this better
// put class name in current scope so it can be looked up by the attrs and methods // put class name in current scope so it can be looked up by the attrs and methods
t_ss->add_object("_current_class_name", const_var(children[0]->text)); t_ss.add_object("_current_class_name", const_var(children[0]->text));
children[1]->eval(t_ss); children[1]->eval(t_ss);
@ -985,7 +939,7 @@ namespace chaiscript
if (this->children[currentCase]->identifier == AST_Node_Type::Case) { if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
//This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here. //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
try { try {
if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) { if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}, t_ss.conversions()))) {
this->children[currentCase]->eval(t_ss); this->children[currentCase]->eval(t_ss);
hasMatched = true; hasMatched = true;
} }
@ -996,7 +950,7 @@ namespace chaiscript
} }
else if (this->children[currentCase]->identifier == AST_Node_Type::Default) { else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
this->children[currentCase]->eval(t_ss); this->children[currentCase]->eval(t_ss);
breaking = true; hasMatched = true;
} }
} }
catch (detail::Break_Loop &) { catch (detail::Break_Loop &) {
@ -1006,6 +960,8 @@ namespace chaiscript
} }
return Boxed_Value(); return Boxed_Value();
} }
mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Case_AST_Node : public AST_Node { struct Case_AST_Node : public AST_Node {
@ -1049,10 +1005,11 @@ namespace chaiscript
try { try {
std::vector<Boxed_Value> vec; std::vector<Boxed_Value> vec;
if (!children.empty()) { if (!children.empty()) {
vec.reserve(children[0]->children.size());
for (const auto &child : children[0]->children) { for (const auto &child : children[0]->children) {
auto obj = child->eval(t_ss); auto obj = child->eval(t_ss);
if (!obj.is_return_value()) { if (!obj.is_return_value()) {
vec.push_back(t_ss->call_function("clone", obj)); vec.push_back(t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions()));
} else { } else {
vec.push_back(std::move(obj)); vec.push_back(std::move(obj));
} }
@ -1069,6 +1026,8 @@ namespace chaiscript
{ {
return "[" + AST_Node::pretty_print() + "]"; return "[" + AST_Node::pretty_print() + "]";
} }
mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Inline_Map_AST_Node : public AST_Node { struct Inline_Map_AST_Node : public AST_Node {
@ -1083,7 +1042,7 @@ namespace chaiscript
for (const auto &child : children[0]->children) { for (const auto &child : children[0]->children) {
auto obj = child->children[1]->eval(t_ss); auto obj = child->children[1]->eval(t_ss);
if (!obj.is_return_value()) { if (!obj.is_return_value()) {
obj = t_ss->call_function("clone", obj); obj = t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions());
} }
retval[t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(obj); retval[t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(obj);
@ -1096,6 +1055,7 @@ namespace chaiscript
} }
} }
mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Return_AST_Node : public AST_Node { struct Return_AST_Node : public AST_Node {
@ -1148,7 +1108,7 @@ namespace chaiscript
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
try { try {
Boxed_Value bv; Boxed_Value bv;
t_ss->add_object(this->children[0]->text, bv); t_ss.add_object(this->children[0]->text, bv);
return bv; return bv;
} }
catch (const exception::reserved_word_error &) { catch (const exception::reserved_word_error &) {
@ -1177,9 +1137,8 @@ namespace chaiscript
return Boxed_Number::do_oper(m_oper, bv); return Boxed_Number::do_oper(m_oper, bv);
} else { } else {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
fpp.save_params({bv}); fpp.save_params({bv});
return t_ss->call_function(children[0]->text, std::move(bv)); return t_ss->call_function(children[0]->text, m_loc, {std::move(bv)}, t_ss.conversions());
} }
} catch (const exception::dispatch_error &e) { } catch (const exception::dispatch_error &e) {
throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, *t_ss); throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
@ -1188,6 +1147,7 @@ namespace chaiscript
private: private:
Operators::Opers m_oper; Operators::Opers m_oper;
mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Break_AST_Node : public AST_Node { struct Break_AST_Node : public AST_Node {
@ -1248,15 +1208,16 @@ namespace chaiscript
virtual ~Inline_Range_AST_Node() {} virtual ~Inline_Range_AST_Node() {}
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
try { try {
return t_ss->call_function("generate_range", auto oper1 = children[0]->children[0]->children[0]->eval(t_ss);
children[0]->children[0]->children[0]->eval(t_ss), auto oper2 = children[0]->children[0]->children[1]->eval(t_ss);
children[0]->children[0]->children[1]->eval(t_ss)); return t_ss->call_function("generate_range", m_loc, {oper1, oper2}, t_ss.conversions());
} }
catch (const exception::dispatch_error &e) { catch (const exception::dispatch_error &e) {
throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss); throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss);
} }
} }
mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Annotation_AST_Node : public AST_Node { struct Annotation_AST_Node : public AST_Node {
@ -1294,9 +1255,9 @@ namespace chaiscript
if (dispatch::Param_Types( if (dispatch::Param_Types(
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)} std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)}
).match(std::vector<Boxed_Value>{t_except}, t_ss->conversions())) ).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()))
{ {
t_ss->add_object(name, t_except); t_ss.add_object(name, t_except);
if (catch_block->children.size() == 2) { if (catch_block->children.size() == 2) {
//Variable capture, no guards //Variable capture, no guards
@ -1433,7 +1394,7 @@ namespace chaiscript
if (guardnode) { if (guardnode) {
guard = dispatch::make_dynamic_proxy_function( guard = dispatch::make_dynamic_proxy_function(
[engine, t_param_names, guardnode](const std::vector<Boxed_Value> &t_params) { [engine, t_param_names, guardnode](const std::vector<Boxed_Value> &t_params) {
return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params, std::map<std::string, Boxed_Value>()); return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params);
}, },
static_cast<int>(numparams), guardnode); static_cast<int>(numparams), guardnode);
} }
@ -1450,7 +1411,7 @@ namespace chaiscript
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name, std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
dispatch::make_dynamic_proxy_function( dispatch::make_dynamic_proxy_function(
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) { [engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map<std::string, Boxed_Value>()); return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
}, },
static_cast<int>(numparams), node, param_types, l_annotation, guard static_cast<int>(numparams), node, param_types, l_annotation, guard
) )
@ -1466,7 +1427,7 @@ namespace chaiscript
t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name, t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
dispatch::make_dynamic_proxy_function( dispatch::make_dynamic_proxy_function(
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) { [engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map<std::string, Boxed_Value>()); return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
}, },
static_cast<int>(numparams), node, param_types, l_annotation, guard), type), static_cast<int>(numparams), node, param_types, l_annotation, guard), type),
function_name); function_name);

File diff suppressed because it is too large Load Diff

View File

@ -41,25 +41,25 @@ def new(x) {
} }
def clone(double x) { def clone(double x) {
double(x).copy_var_attrs(x) double(x).clone_var_attrs(x)
} }
def clone(string x) { def clone(string x) {
string(x).copy_var_attrs(x) string(x).clone_var_attrs(x)
} }
def clone(vector x) { def clone(vector x) {
vector(x).copy_var_attrs(x) vector(x).clone_var_attrs(x)
} }
def clone(int x) { def clone(int x) {
int(x).copy_var_attrs(x) int(x).clone_var_attrs(x)
} }
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
{ {
eval(type_name(x))(x).copy_var_attrs(x); eval(type_name(x))(x).clone_var_attrs(x);
} }
@ -145,11 +145,6 @@ def reverse(container) {
retval; retval;
} }
# Return a range from a range
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{
clone(r);
}
def range(r) : call_exists(range_internal, r) def range(r) : call_exists(range_internal, r)
{ {
@ -158,6 +153,13 @@ def range(r) : call_exists(range_internal, r)
ri; ri;
} }
# Return a range from a range
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{
clone(r);
}
# The retro attribute that contains the underlying range # The retro attribute that contains the underlying range
attr retro::m_range; attr retro::m_range;

View File

@ -0,0 +1,663 @@
// From github.com/nbsdx/SimpleJSON.
// Released under the DWTFYW PL
//
#pragma once
#ifndef SIMPLEJSON_HPP
#define SIMPLEJSON_HPP
#include <cstdint>
#include <cmath>
#include <cctype>
#include <string>
#include <deque>
#include <map>
#include <type_traits>
#include <initializer_list>
#include <ostream>
#include <iostream>
#include "../chaiscript_defines.hpp"
namespace json {
using std::map;
using std::deque;
using std::string;
using std::enable_if;
using std::initializer_list;
using std::is_same;
using std::is_convertible;
using std::is_integral;
using std::is_floating_point;
namespace {
string json_escape( const string &str ) {
string output;
for( unsigned i = 0; i < str.length(); ++i )
switch( str[i] ) {
case '\"': output += "\\\""; break;
case '\\': output += "\\\\"; break;
case '\b': output += "\\b"; break;
case '\f': output += "\\f"; break;
case '\n': output += "\\n"; break;
case '\r': output += "\\r"; break;
case '\t': output += "\\t"; break;
default : output += str[i]; break;
}
return output;
}
bool isspace(const char c)
{
#ifdef CHAISCRIPT_MSVC
// MSVC warns on these line in some circumstances
#pragma warning(push)
#pragma warning(disable : 6330)
#endif
return ::isspace(c) != 0;
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
}
class JSON
{
union BackingData {
BackingData( double d ) : Float( d ){}
BackingData( long l ) : Int( l ){}
BackingData( bool b ) : Bool( b ){}
BackingData( string s ) : String( new string( s ) ){}
BackingData() : Int( 0 ){}
deque<JSON> *List;
map<string,JSON> *Map;
string *String;
double Float;
long Int;
bool Bool;
} Internal;
public:
enum class Class {
Null,
Object,
Array,
String,
Floating,
Integral,
Boolean
};
template <typename Container>
class JSONWrapper {
Container *object;
public:
JSONWrapper( Container *val ) : object( val ) {}
JSONWrapper( std::nullptr_t ) : object( nullptr ) {}
typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
};
template <typename Container>
class JSONConstWrapper {
const Container *object;
public:
JSONConstWrapper( const Container *val ) : object( val ) {}
JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {}
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
};
JSON() : Internal(), Type( Class::Null ){}
explicit JSON(Class type)
: Internal(), Type(Class::Null)
{
SetType( type );
}
JSON( initializer_list<JSON> list )
: Internal(), Type(Class::Null)
{
SetType( Class::Object );
for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i )
operator[]( i->ToString() ) = *std::next( i );
}
JSON( JSON&& other )
: Internal( other.Internal )
, Type( other.Type )
{ other.Type = Class::Null; other.Internal.Map = nullptr; }
JSON& operator=( JSON&& other ) {
Internal = other.Internal;
Type = other.Type;
other.Internal.Map = nullptr;
other.Type = Class::Null;
return *this;
}
JSON( const JSON &other ) {
switch( other.Type ) {
case Class::Object:
Internal.Map =
new map<string,JSON>( other.Internal.Map->begin(),
other.Internal.Map->end() );
break;
case Class::Array:
Internal.List =
new deque<JSON>( other.Internal.List->begin(),
other.Internal.List->end() );
break;
case Class::String:
Internal.String =
new string( *other.Internal.String );
break;
default:
Internal = other.Internal;
}
Type = other.Type;
}
JSON& operator=( const JSON &other ) {
if (&other == this) return *this;
switch( other.Type ) {
case Class::Object:
Internal.Map =
new map<string,JSON>( other.Internal.Map->begin(),
other.Internal.Map->end() );
break;
case Class::Array:
Internal.List =
new deque<JSON>( other.Internal.List->begin(),
other.Internal.List->end() );
break;
case Class::String:
Internal.String =
new string( *other.Internal.String );
break;
default:
Internal = other.Internal;
}
Type = other.Type;
return *this;
}
~JSON() {
switch( Type ) {
case Class::Array:
delete Internal.List;
break;
case Class::Object:
delete Internal.Map;
break;
case Class::String:
delete Internal.String;
break;
default:;
}
}
template <typename T>
JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){}
template <typename T>
JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = 0 ) : Internal( long(i) ), Type( Class::Integral ){}
template <typename T>
JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = 0 ) : Internal( double(f) ), Type( Class::Floating ){}
template <typename T>
JSON( T s, typename enable_if<is_convertible<T,string>::value>::type* = 0 ) : Internal( string( s ) ), Type( Class::String ){}
JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){}
static JSON Make( Class type ) {
return JSON(type);
}
static JSON Load( const string & );
template <typename T>
void append( T arg ) {
SetType( Class::Array ); Internal.List->emplace_back( arg );
}
template <typename T, typename... U>
void append( T arg, U... args ) {
append( arg ); append( args... );
}
template <typename T>
typename enable_if<is_same<T,bool>::value, JSON&>::type operator=( T b ) {
SetType( Class::Boolean ); Internal.Bool = b; return *this;
}
template <typename T>
typename enable_if<is_integral<T>::value && !is_same<T,bool>::value, JSON&>::type operator=( T i ) {
SetType( Class::Integral ); Internal.Int = i; return *this;
}
template <typename T>
typename enable_if<is_floating_point<T>::value, JSON&>::type operator=( T f ) {
SetType( Class::Floating ); Internal.Float = f; return *this;
}
template <typename T>
typename enable_if<is_convertible<T,string>::value, JSON&>::type operator=( T s ) {
SetType( Class::String ); *Internal.String = string( s ); return *this;
}
JSON& operator[]( const string &key ) {
SetType( Class::Object ); return Internal.Map->operator[]( key );
}
JSON& operator[]( const size_t index ) {
SetType( Class::Array );
if( index >= Internal.List->size() ) Internal.List->resize( index + 1 );
return Internal.List->operator[]( index );
}
JSON &at( const string &key ) {
return operator[]( key );
}
const JSON &at( const string &key ) const {
return Internal.Map->at( key );
}
JSON &at( unsigned index ) {
return operator[]( index );
}
const JSON &at( unsigned index ) const {
return Internal.List->at( index );
}
int length() const {
if( Type == Class::Array )
return static_cast<int>(Internal.List->size());
else
return -1;
}
bool hasKey( const string &key ) const {
if( Type == Class::Object )
return Internal.Map->find( key ) != Internal.Map->end();
return false;
}
int size() const {
if( Type == Class::Object )
return static_cast<int>(Internal.Map->size());
else if( Type == Class::Array )
return static_cast<int>(Internal.List->size());
else
return -1;
}
Class JSONType() const { return Type; }
/// Functions for getting primitives from the JSON object.
bool IsNull() const { return Type == Class::Null; }
string ToString() const { bool b; return ToString( b ); }
string ToString( bool &ok ) const {
ok = (Type == Class::String);
return ok ? *Internal.String : string("");
}
double ToFloat() const { bool b; return ToFloat( b ); }
double ToFloat( bool &ok ) const {
ok = (Type == Class::Floating);
return ok ? Internal.Float : 0.0;
}
long ToInt() const { bool b; return ToInt( b ); }
long ToInt( bool &ok ) const {
ok = (Type == Class::Integral);
return ok ? Internal.Int : 0;
}
bool ToBool() const { bool b; return ToBool( b ); }
bool ToBool( bool &ok ) const {
ok = (Type == Class::Boolean);
return ok ? Internal.Bool : false;
}
JSONWrapper<map<string,JSON>> ObjectRange() {
if( Type == Class::Object )
return JSONWrapper<map<string,JSON>>( Internal.Map );
return JSONWrapper<map<string,JSON>>( nullptr );
}
JSONWrapper<deque<JSON>> ArrayRange() {
if( Type == Class::Array )
return JSONWrapper<deque<JSON>>( Internal.List );
return JSONWrapper<deque<JSON>>( nullptr );
}
JSONConstWrapper<map<string,JSON>> ObjectRange() const {
if( Type == Class::Object )
return JSONConstWrapper<map<string,JSON>>( Internal.Map );
return JSONConstWrapper<map<string,JSON>>( nullptr );
}
JSONConstWrapper<deque<JSON>> ArrayRange() const {
if( Type == Class::Array )
return JSONConstWrapper<deque<JSON>>( Internal.List );
return JSONConstWrapper<deque<JSON>>( nullptr );
}
string dump( int depth = 1, string tab = " ") const {
switch( Type ) {
case Class::Null:
return "null";
case Class::Object: {
string pad = "";
for( int i = 0; i < depth; ++i, pad += tab );
string s = "{\n";
bool skip = true;
for( auto &p : *Internal.Map ) {
if( !skip ) s += ",\n";
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
skip = false;
}
s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
return s;
}
case Class::Array: {
string s = "[";
bool skip = true;
for( auto &p : *Internal.List ) {
if( !skip ) s += ", ";
s += p.dump( depth + 1, tab );
skip = false;
}
s += "]";
return s;
}
case Class::String:
return "\"" + json_escape( *Internal.String ) + "\"";
case Class::Floating:
return std::to_string( Internal.Float );
case Class::Integral:
return std::to_string( Internal.Int );
case Class::Boolean:
return Internal.Bool ? "true" : "false";
}
throw std::runtime_error("Unhandled JSON type");
}
friend std::ostream& operator<<( std::ostream&, const JSON & );
private:
void SetType( Class type ) {
if( type == Type )
return;
switch( Type ) {
case Class::Object: delete Internal.Map; break;
case Class::Array: delete Internal.List; break;
case Class::String: delete Internal.String; break;
default:;
}
switch( type ) {
case Class::Null: Internal.Map = nullptr; break;
case Class::Object: Internal.Map = new map<string,JSON>(); break;
case Class::Array: Internal.List = new deque<JSON>(); break;
case Class::String: Internal.String = new string(); break;
case Class::Floating: Internal.Float = 0.0; break;
case Class::Integral: Internal.Int = 0; break;
case Class::Boolean: Internal.Bool = false; break;
}
Type = type;
}
private:
Class Type;
};
inline JSON Array() {
return JSON::Make( JSON::Class::Array );
}
template <typename... T>
inline JSON Array( T... args ) {
JSON arr = JSON::Make( JSON::Class::Array );
arr.append( args... );
return arr;
}
inline JSON Object() {
return JSON::Make( JSON::Class::Object );
}
inline std::ostream& operator<<( std::ostream &os, const JSON &json ) {
os << json.dump();
return os;
}
namespace {
JSON parse_next( const string &, size_t & );
void consume_ws( const string &str, size_t &offset ) {
while( isspace( str[offset] ) ) ++offset;
}
JSON parse_object( const string &str, size_t &offset ) {
JSON Object = JSON::Make( JSON::Class::Object );
++offset;
consume_ws( str, offset );
if( str[offset] == '}' ) {
++offset; return Object;
}
for (;offset<str.size();) {
JSON Key = parse_next( str, offset );
consume_ws( str, offset );
if( str[offset] != ':' ) {
throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str[offset] + "'\n");
}
consume_ws( str, ++offset );
JSON Value = parse_next( str, offset );
Object[Key.ToString()] = Value;
consume_ws( str, offset );
if( str[offset] == ',' ) {
++offset; continue;
}
else if( str[offset] == '}' ) {
++offset; break;
}
else {
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str[offset] + "'\n");
}
}
return Object;
}
JSON parse_array( const string &str, size_t &offset ) {
JSON Array = JSON::Make( JSON::Class::Array );
unsigned index = 0;
++offset;
consume_ws( str, offset );
if( str[offset] == ']' ) {
++offset; return Array;
}
for (;offset < str.size();) {
Array[index++] = parse_next( str, offset );
consume_ws( str, offset );
if( str[offset] == ',' ) {
++offset; continue;
}
else if( str[offset] == ']' ) {
++offset; break;
}
else {
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str[offset] + "'\n");
}
}
return Array;
}
JSON parse_string( const string &str, size_t &offset ) {
string val;
for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
if( c == '\\' ) {
switch( str[ ++offset ] ) {
case '\"': val += '\"'; break;
case '\\': val += '\\'; break;
case '/' : val += '/' ; break;
case 'b' : val += '\b'; break;
case 'f' : val += '\f'; break;
case 'n' : val += '\n'; break;
case 'r' : val += '\r'; break;
case 't' : val += '\t'; break;
case 'u' : {
val += "\\u" ;
for( unsigned i = 1; i <= 4; ++i ) {
c = str[offset+i];
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
val += c;
else {
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
}
}
offset += 4;
} break;
default : val += '\\'; break;
}
}
else
val += c;
}
++offset;
return JSON(val);
}
JSON parse_number( const string &str, size_t &offset ) {
JSON Number;
string val, exp_str;
char c = '\0';
bool isDouble = false;
long exp = 0;
for (; offset < str.size() ;) {
c = str[offset++];
if( (c == '-') || (c >= '0' && c <= '9') )
val += c;
else if( c == '.' ) {
val += c;
isDouble = true;
}
else
break;
}
if( offset < str.size() && (c == 'E' || c == 'e' )) {
c = str[ offset++ ];
if( c == '-' ) { exp_str += '-';}
else if( c == '+' ) { }
else --offset;
for (; offset < str.size() ;) {
c = str[ offset++ ];
if( c >= '0' && c <= '9' )
exp_str += c;
else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
}
else
break;
}
exp = std::stol( exp_str );
}
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
}
--offset;
if( isDouble )
Number = std::stod( val ) * std::pow( 10, exp );
else {
if( !exp_str.empty() )
Number = std::stol( val ) * std::pow( 10, exp );
else
Number = std::stol( val );
}
return Number;
}
JSON parse_bool( const string &str, size_t &offset ) {
JSON Bool;
if( str.substr( offset, 4 ) == "true" ) {
offset += 4;
Bool = true;
} else if( str.substr( offset, 5 ) == "false" ) {
offset += 5;
Bool = false;
} else {
throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'");
}
return Bool;
}
JSON parse_null( const string &str, size_t &offset ) {
if( str.substr( offset, 4 ) != "null" ) {
throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'");
}
offset += 4;
return JSON();
}
JSON parse_next( const string &str, size_t &offset ) {
char value;
consume_ws( str, offset );
value = str[offset];
switch( value ) {
case '[' : return parse_array( str, offset );
case '{' : return parse_object( str, offset );
case '\"': return parse_string( str, offset );
case 't' :
case 'f' : return parse_bool( str, offset );
case 'n' : return parse_null( str, offset );
default : if( ( value <= '9' && value >= '0' ) || value == '-' )
return parse_number( str, offset );
}
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
}
}
inline JSON JSON::Load( const string &str ) {
size_t offset = 0;
return parse_next( str, offset );
}
} // End Namespace json
#endif

View File

@ -0,0 +1,158 @@
#ifndef CHAISCRIPT_SIMPLEJSON_WRAP_HPP
#define CHAISCRIPT_SIMPLEJSON_WRAP_HPP
#include "json.hpp"
namespace chaiscript
{
class json_wrap
{
public:
static ModulePtr library(ModulePtr m = std::make_shared<Module>())
{
m->add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
m->add(chaiscript::fun(&json_wrap::to_json), "to_json");
return m;
}
private:
static Boxed_Value from_json(const json::JSON &t_json)
{
switch( t_json.JSONType() ) {
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.ObjectRange())
{
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.ArrayRange())
{
vec.emplace_back(from_json(p));
}
return Boxed_Value(vec);
}
case json::JSON::Class::String:
return Boxed_Value(t_json.ToString());
case json::JSON::Class::Floating:
return Boxed_Value(t_json.ToFloat());
case json::JSON::Class::Integral:
return Boxed_Value(t_json.ToInt());
case json::JSON::Class::Boolean:
return Boxed_Value(t_json.ToBool());
}
throw std::runtime_error("Unknown JSON type");
}
static Boxed_Value from_json(const std::string &t_json)
{
return from_json( json::JSON::Load(t_json) );
}
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;
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;
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);
json::JSON obj;
if (Boxed_Number::is_floating_point(t_bv))
{
obj = bn.get_as<double>();
} else {
obj = bn.get_as<long>();
}
return obj;
} catch (const chaiscript::detail::exception::bad_any_cast &) {
// not a number
}
try {
bool b = boxed_cast<bool>(t_bv);
json::JSON obj;
obj = b;
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a bool
}
try {
std::string s = boxed_cast<std::string>(t_bv);
json::JSON obj;
obj = s;
return obj;
} 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;
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
}
throw std::runtime_error("Unknown object type to convert to JSON");
}
};
}
#endif

View File

@ -1,19 +1,21 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ #ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
#define CHAISCRIPT_UTILITY_UTILITY_HPP_ #define CHAISCRIPT_UTILITY_UTILITY_HPP_
#include <string> #include <string>
#include <type_traits>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "../chaiscript.hpp" #include "../chaiscript.hpp"
#include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp" #include "../dispatchkit/type_info.hpp"
#include "../dispatchkit/operators.hpp"
namespace chaiscript namespace chaiscript
@ -62,6 +64,42 @@ namespace chaiscript
t_module.add(fun.first, fun.second); 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,
#ifdef CHAISCRIPT_GCC_4_6
const std::vector<std::pair<int, std::string>> &t_constants
#else
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants
#endif
)
{
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;
t_module.add([](){
// add some comparison and assignment operators
return assign<Enum>(not_equal<Enum>(equal<Enum>()));
}());
#ifdef CHAISCRIPT_GCC_4_6
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; }), "==");
#else
t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type<Enum>::type &i) { return e == i; }), "==");
t_module.add(chaiscript::fun([](const typename std::underlying_type<Enum>::type &i, const Enum &e) { return i == e; }), "==");
#endif
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
}
}
} }
} }

View File

@ -1,4 +1,4 @@
Copyright 2009-2015 Jason Turner Copyright 2009-2016 Jason Turner
Copyright 2009-2012 Jonathan Turner. Copyright 2009-2012 Jonathan Turner.
All Rights Reserved. All Rights Reserved.

View File

@ -0,0 +1,26 @@
var test_str = "bob was a string";
for( var i = 0; i < 200000; ++i)
{
test_str.size();
// test_str.find("a", i);
test_str.c_str();
test_str.erase_at(1);
test_str.erase_at(1);
test_str.erase_at(1);
test_str.erase_at(1);
test_str.erase_at(1);
test_str.erase_at(1);
size(test_str);
// test_str.find("a", i);
c_str(test_str);
erase_at(test_str, 1);
erase_at(test_str, 1);
erase_at(test_str, 1);
erase_at(test_str, 1);
erase_at(test_str, 1);
erase_at(test_str, 1);
test_str = "bob was a string";
}

View File

@ -0,0 +1,20 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
double f(const std::string &, double, bool) noexcept {
return .0;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&f), "f");
chai.eval(R"(
for (var i = 0; i < 100000; ++i) {
f("str", 1.2, false);
}
)");
}

View File

@ -0,0 +1,20 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
double f(const std::string &, double, bool) noexcept {
return .0;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&f), "f");
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

@ -12,7 +12,7 @@ ChaiScript
http://www.chaiscript.com http://www.chaiscript.com
(c) 2009-2012 Jonathan Turner (c) 2009-2012 Jonathan Turner
(c) 2009-2015 Jason Turner (c) 2009-2016 Jason Turner
Release under the BSD license, see "license.txt" for details. Release under the BSD license, see "license.txt" for details.

View File

@ -1,6 +1,29 @@
Notes: Notes:
======= =======
Current Version: 5.7.1 Current Version: 5.8.0
### Changes since 5.7.1
* Make all parser iterator operations range checked
* Parse in-string eval statements once, not once for each execution
* Fix parsing of operators (ie 1<-1 now parses)
* Fix variable scoping for functors
* Exception reduction
* Various object lifetime fixes
* Add JSON support for load / save #207
* Numeric overload resolution fixes #209
* Fix long long #208
* Add octal escapes in strings #211
* Fixed sizing of binary literals #213
* Added support for != with bool values #217
* Various value assignment vector fixes
* Fixed broken hex escape sequences from @ChristianKaeser
* Multiply defined symbols fixes #232 @RaptorFactor
* Add add_class<Enum> helper #233 @vrennert
* Cheatsheet fixes #235 @mlamby
* Fix parsing of strings inside of in-string eval statements
* Allow lower-case global keyword
* Enable thread-local on MSVC (should be significant performance boost)
### Changes since 5.7.0 ### Changes since 5.7.0
* Build time reduction * Build time reduction

103
samples/factory.cpp Normal file
View File

@ -0,0 +1,103 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
class Entity
{
public:
int width;
int height;
int x;
int y;
std::string name;
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))
{
}
};
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);
}
// 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;
};
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&Entity::width), "width");
chai.add(chaiscript::fun(&Entity::height), "height");
chai.add(chaiscript::fun(&Entity::x), "x");
chai.add(chaiscript::fun(&Entity::y), "y");
chai.add(chaiscript::fun(&Entity::name), "name");
chai.add(chaiscript::fun(&Entity::updater), "updater");
chai.add(chaiscript::user_type<Entity>(), "Entity"); // this isn't strictly necessary but makes error messages nicer
chai.add(chaiscript::fun(&Factory::make_entity), "make_entity");
chai.add(chaiscript::fun(&Factory::get_entity), "get_entity");
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");
std::string script = R""(
f.make_entity(10,10,1,1,"entity1").updater = fun(e){ e.x += 1; e.y += 1 };
f.make_entity(10,10,10,10,"entity2").updater = fun(e){ e.x += 2; e.y += 2 };
f.make_entity(10,10,20,20,"entity3");
print(f.get_entity("entity1").x == 1)
print(f.get_entity("entity2").x == 10)
print(f.get_entity("entity3").x == 20)
f.update_entities(); // this runs the function objects we set in the previous lines
// we should now see the updated values
print(f.get_entity("entity1").x == 2)
print(f.get_entity("entity2").x == 12)
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
)"";
chai.eval(script);
}

View File

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

View File

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

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#include <iostream> #include <iostream>
@ -66,7 +66,7 @@ std::vector<std::string> default_search_paths()
#ifdef CHAISCRIPT_WINDOWS // force no unicode #ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096]; CHAR path[4096];
int size = GetModuleFileNameA(0, path, sizeof(path)-1); int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
std::string exepath(path, size); std::string exepath(path, size);
@ -344,17 +344,16 @@ int main(int argc, char *argv[])
mode = eFile; mode = eFile;
} }
chaiscript::Boxed_Value val ;
try { try {
switch ( mode ) { switch ( mode ) {
case eInteractive: case eInteractive:
interactive(chai); interactive(chai);
break; break;
case eCommand: case eCommand:
val = chai.eval(arg); chai.eval(arg);
break; break;
case eFile: case eFile:
val = chai.eval_file(arg); chai.eval_file(arg);
} }
} }
catch (const chaiscript::exception::eval_error &ee) { catch (const chaiscript::exception::eval_error &ee) {

View File

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

View File

@ -0,0 +1,3 @@
var v = [[[15]]]
assert_true(v[0][0][0] == 15)

View File

@ -0,0 +1,12 @@
assert_true(true == true)
assert_false(true == false)
assert_true(true != false)
assert_true(false != true)
assert_true(false || true)
assert_true(true || false)
assert_false(true && false)
assert_false(false && true)
assert_true(!false)
assert_false(!true)

View File

@ -13,9 +13,9 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
try { try {
To ret = chaiscript::boxed_cast<To>(bv); To ret = chaiscript::boxed_cast<To>(bv);
use(ret); use(ret);
} catch (const chaiscript::exception::bad_boxed_cast &/*e*/) { } catch (const chaiscript::exception::bad_boxed_cast &e) {
if (expectedpass) { if (expectedpass) {
// std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n'; std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n';
return false; return false;
} else { } else {
return true; return true;

View File

@ -2,6 +2,7 @@
// caught in other cpp files if chaiscript causes them // caught in other cpp files if chaiscript causes them
#include <chaiscript/utility/utility.hpp> #include <chaiscript/utility/utility.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
@ -396,7 +397,7 @@ class Short_Comparison_Test {
public: public:
Short_Comparison_Test() : value_(5) {} Short_Comparison_Test() : value_(5) {}
short get_value() { return value_; } short get_value() const { return value_; }
short value_; short value_;
}; };
@ -518,6 +519,65 @@ TEST_CASE("Utility_Test utility class wrapper")
} }
enum Utility_Test_Numbers
{
ONE,
TWO,
THREE
};
void do_something_with_enum_vector(const std::vector<Utility_Test_Numbers> &v)
{
CHECK(v.size() == 3);
CHECK(v[0] == ONE);
CHECK(v[1] == THREE);
CHECK(v[2] == TWO);
}
TEST_CASE("Utility_Test utility class wrapper for enum")
{
chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
using namespace chaiscript;
chaiscript::utility::add_class<Utility_Test_Numbers>(*m,
"Utility_Test_Numbers",
{ { ONE, "ONE" },
{ TWO, "TWO" },
{ THREE, "THREE" }
}
);
chaiscript::ChaiScript chai;
chai.add(m);
CHECK(chai.eval<Utility_Test_Numbers>("ONE ") == 0);
CHECK(chai.eval<Utility_Test_Numbers>("TWO ") == 1);
CHECK(chai.eval<Utility_Test_Numbers>("THREE ") == 2);
CHECK(chai.eval<bool>("ONE == 0"));
chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector");
chai.add(chaiscript::vector_conversion<std::vector<Utility_Test_Numbers>>());
CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]"));
CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE, THREE, TWO])"));
CHECK_NOTHROW(chai.eval("[ONE]"));
const auto v = chai.eval<std::vector<Utility_Test_Numbers>>("a");
CHECK(v.size() == 3);
CHECK(v.at(1) == TWO);
CHECK(chai.eval<bool>("ONE == ONE"));
CHECK(chai.eval<bool>("ONE != TWO"));
CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO"));
}
////// Object copy count test ////// Object copy count test
class Object_Copy_Count_Test class Object_Copy_Count_Test
@ -743,3 +803,139 @@ TEST_CASE("Test Derived->Base with non-polymorphic classes")
chai.add(chaiscript::fun(&myfunction), "myfunction"); chai.add(chaiscript::fun(&myfunction), "myfunction");
CHECK(chai.eval<int>("myfunction(d)") == 2); CHECK(chai.eval<int>("myfunction(d)") == 2);
} }
struct TestCppVariableScope
{
void print()
{
std::cout << "Printed" << std::endl;
}
};
TEST_CASE("Variable Scope When Calling From C++")
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::user_type<TestCppVariableScope>(), "Test");
chai.add(chaiscript::constructor<TestCppVariableScope()>(), "Test");
chai.add(chaiscript::fun(&TestCppVariableScope::print), "print");
chai.eval(R"(var t := Test();
def func()
{
t.print();
}
)");
CHECK_THROWS(chai.eval("func()"));
chai.eval("dump_object(t)");
auto func = chai.eval<std::function<void()>>("func");
CHECK_THROWS(func());
}
TEST_CASE("Variable Scope When Calling From C++ 2")
{
chaiscript::ChaiScript chai;
chai.eval("var obj = 2;");
auto func = chai.eval<std::function<void()>>("fun(){ return obj; }");
CHECK_THROWS(func());
}
void ulonglong(unsigned long long i) {
std::cout << i << '\n';
}
void longlong(long long i) {
std::cout << i << '\n';
}
TEST_CASE("Test long long dispatch")
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&longlong), "longlong");
chai.add(chaiscript::fun(&ulonglong), "ulonglong");
chai.eval("longlong(15)");
chai.eval("ulonglong(15)");
}
struct Returned_Converted_Config
{
int num_iterations;
int something_else;
std::string a_string;
std::function<int (const std::string &)> a_function;
};
TEST_CASE("Return of converted type from script")
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::constructor<Returned_Converted_Config ()>(), "Returned_Converted_Config");
chai.add(chaiscript::fun(&Returned_Converted_Config::num_iterations), "num_iterations");
chai.add(chaiscript::fun(&Returned_Converted_Config::something_else), "something_else");
chai.add(chaiscript::fun(&Returned_Converted_Config::a_string), "a_string");
chai.add(chaiscript::fun(&Returned_Converted_Config::a_function), "a_function");
chai.add(chaiscript::vector_conversion<std::vector<Returned_Converted_Config>>());
auto c = chai.eval<std::vector<Returned_Converted_Config>>(R"(
var c = Returned_Converted_Config();
c.num_iterations = 5;
c.something_else = c.num_iterations * 2;
c.a_string = "string";
c.a_function = fun(s) { s.size(); }
print("making vector");
var v = [];
print("adding config item");
v.push_back_ref(c);
print("returning vector");
v;
)");
std::cout << typeid(decltype(c)).name() << std::endl;
std::cout << "Info: " << c.size() << " " << &c[0] << std::endl;
std::cout << "num_iterations " << c[0].num_iterations << '\n'
<< "something_else " << c[0].something_else << '\n'
<< "a_string " << c[0].a_string << '\n'
<< "a_function " << c[0].a_function("bob") << '\n';
chai.add(chaiscript::user_type<Returned_Converted_Config>(), "Returned_Converted_Config");
}
int get_value_a(const std::map<std::string, int> &t_m)
{
return t_m.at("a");
}
TEST_CASE("Map conversions")
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
chai.add(chaiscript::fun(&get_value_a), "get_value_a");
const auto c = chai.eval<int>(R"(
var m = ["a": 42];
get_value_a(m);
)");
CHECK(c == 42);
}

View File

@ -0,0 +1,14 @@
class MyClass {
def MyClass()
{
this.set_explicit(true);
}
};
var o = MyClass();
assert_true(o.is_explicit());
assert_throws("error", fun[o](){o.x = 2})

View File

@ -8,3 +8,17 @@ def myFun()
} }
myFun(); myFun();
def myFun2()
{
assert_equal(j, 7)
}
set_global(7, "j")
myFun2();
set_global(5, "j")
myFun();

View File

@ -0,0 +1,18 @@
// Test global
global g = 3;
assert_true(g == 3);
var v := g;
assert_true(v == 3);
global g = 2;
assert_true(g == 2);
assert_true(v == 2);
def f() {
assert_true(g == 2);
}
f();

View File

@ -0,0 +1,7 @@
assert_equal("\x39", "9")
assert_equal("\x39ec", "9ec")
assert_equal("\x39g", "9g")
assert_equal("b\x39g", "b9g")
assert_equal("\x39\x38g", "98g")

View File

@ -0,0 +1 @@
assert_equal("a string", "${"a string"}")

View File

@ -5,9 +5,10 @@
template<typename T> template<typename T>
bool test_literal(T val, const std::string &str) bool test_literal(T val, const std::string &str)
{ {
std::cout << "Comparing : " << val;
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
T val2 = chai.eval<T>(str); T val2 = chai.eval<T>(str);
std::cout << "Comparing : " << val << " " << val2 << '\n'; std::cout << " " << val2 << '\n';
return val == val2; return val == val2;
} }
@ -74,6 +75,39 @@ int main()
&& TEST_LITERAL(177777777777777777) && TEST_LITERAL(177777777777777777)
&& TEST_LITERAL(1777777777777777777) && TEST_LITERAL(1777777777777777777)
&& test_literal(0xF, "0b1111")
&& test_literal(0xFF, "0b11111111")
&& test_literal(0xFFF, "0b111111111111")
&& test_literal(0xFFFF, "0b1111111111111111")
&& test_literal(0xFFFFF, "0b11111111111111111111")
&& test_literal(0xFFFFFF, "0b111111111111111111111111")
&& test_literal(0xFFFFFFF, "0b1111111111111111111111111111")
&& test_literal(0xFFFFFFFF, "0b11111111111111111111111111111111")
&& test_literal(0xFFFFFFFFF, "0b111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFF, "0b1111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111111111111")
&& test_literal(0x7, "0b111")
&& test_literal(0x7F, "0b1111111")
&& test_literal(0x7FF, "0b11111111111")
&& test_literal(0x7FFF, "0b111111111111111")
&& test_literal(0x7FFFF, "0b1111111111111111111")
&& test_literal(0x7FFFFF, "0b11111111111111111111111")
&& test_literal(0x7FFFFFF, "0b111111111111111111111111111")
&& test_literal(0x7FFFFFFF, "0b1111111111111111111111111111111")
&& test_literal(0x7FFFFFFFF, "0b11111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFF, "0b111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFF, "0b1111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111111")
) )
{ {
return EXIT_SUCCESS; return EXIT_SUCCESS;

3
unittests/json_1.chai Normal file
View File

@ -0,0 +1,3 @@
assert_true(from_json("null").is_var_null())

1
unittests/json_10.chai Normal file
View File

@ -0,0 +1 @@
assert_equal(from_json("\"This is a\\n\\nMultiline string\""), "This is a\n\nMultiline string")

14
unittests/json_11.chai Normal file
View File

@ -0,0 +1,14 @@
assert_equal(from_json(
"{\n" +
" \"T1\" : \"Value With a Quote : \\\"\",\n" +
" \"T2\" : \"Value With a Rev Solidus : \\/\",\n" +
" \"T3\" : \"Value with a Solidus : \\\\\",\n" +
" \"T4\" : \"Value with a Backspace : \\b\",\n" +
" \"T5\" : \"Value with a Formfeed : \\f\",\n" +
" \"T6\" : \"Value with a Newline : \\n\",\n" +
" \"T7\" : \"Value with a Carriage Return : \\r\",\n" +
" \"T8\" : \"Value with a Horizontal Tab : \\t\"\n" +
"}"), [ "T1" : "Value With a Quote : \"", "T2" : "Value With a Rev Solidus : /", "T3" : "Value with a Solidus : \\", "T4" : "Value with a Backspace : \b", "T5" : "Value with a Formfeed : \f", "T6" : "Value with a Newline : \n", "T7" : "Value with a Carriage Return : \r", "T8" : "Value with a Horizontal Tab : \t" ]);

1
unittests/json_12.chai Normal file
View File

@ -0,0 +1 @@
assert_equal(from_json("\"\""), "")

1
unittests/json_13.chai Normal file
View File

@ -0,0 +1 @@
assert_equal(from_json("1.20E+2"), 1.20e2)

3
unittests/json_2.chai Normal file
View File

@ -0,0 +1,3 @@
assert_true(from_json("true"))

1
unittests/json_3.chai Normal file
View File

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

1
unittests/json_4.chai Normal file
View File

@ -0,0 +1 @@
assert_equal(from_json("1.234"), 1.234)

1
unittests/json_5.chai Normal file
View File

@ -0,0 +1 @@
assert_equal(from_json("\"StringTest\""), "StringTest")

1
unittests/json_6.chai Normal file
View File

@ -0,0 +1 @@
assert_equal(from_json("{}"), Map())

4
unittests/json_7.chai Normal file
View File

@ -0,0 +1,4 @@
assert_equal(from_json("\n" +
"{\n" +
" \"Key\" : \"Value\"\n" +
"}\n"), ["Key":"Value"])

1
unittests/json_8.chai Normal file
View File

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

2
unittests/json_9.chai Normal file
View File

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

View File

@ -0,0 +1,6 @@
var m = ["a" : 1, "b" : [ 1, 2, 3 ], "c" : [1, "a string", ["d" : 15.4]]]
assert_equal(from_json(to_json(m)), m)

View File

@ -6,3 +6,7 @@ x.push_back("A")
assert_equal(3, x.front()); assert_equal(3, x.front());
assert_equal("A", x.back()); assert_equal("A", x.back());

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