diff --git a/.decent_ci-Linux.yaml b/.decent_ci-Linux.yaml index 6f7125f0..24990bd8 100644 --- a/.decent_ci-Linux.yaml +++ b/.decent_ci-Linux.yaml @@ -10,12 +10,12 @@ compilers: cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON - name: "clang" build_tag: AddressSanitizer - version: "3.5" + version: "3.6" 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 - name: "clang" build_tag: ThreadSanitizer - version: "3.5" + version: "3.6" skip_packaging: true 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" diff --git a/.travis.yml b/.travis.yml index dc3b2ad4..a53e346f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,24 +2,34 @@ language: cpp compiler: - gcc env: - - GCC_VER=4.6 - - GCC_VER=4.8 + matrix: + - GCC_VER="4.6" + - GCC_VER="4.8" + + global: + - secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU= + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + - secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM=" + before_install: + - export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" + - if [ "$GCC_VER" = "4.8" ]; then export COVERAGE=1 CPPCHECK=1; fi + - if [ ${COVERAGE} = 1 ]; then export FUZZY_CMD="-D RUN_FUZZY_TESTS:BOOL=TRUE"; fi - sudo pip install cpp-coveralls - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt-get update - - sudo apt-get install -qq g++-4.8 - - if [ "$GCC_VER" = "4.8" ]; then export CXX="g++-4.8" CC="gcc-4.8" GCOV="gcov-4.8"; else export CXX="g++-4.6" CC="gcc-4.6" GCOV="gcov-4.6"; fi + - sudo apt-get install -qq g++-$GCC_VER + script: - - cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . - - make -j2 + - if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $FUZZY_CMD . ; fi + - if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -j2 ; fi - make test - - mkdir gcov - - find CMakeFiles/ -name "*.gc*" -exec mv {} gcov/ \; - - $GCOV -d -o gcov gcov/*.gcda - - coveralls -n -E ".*\.cpp" + - if [ ${COVERAGE} = 1 ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi + after_script: - - contrib/codeanalysis/runcppcheck.sh + - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi + + notifications: email: recipients: @@ -32,8 +42,15 @@ notifications: on_success: change # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always on_start: false # default: false -env: - global: - secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU= + +addons: + coverity_scan: + project: + name: "ChaiScript/ChaiScript" + description: "Build submitted via Travis CI" + notification_email: jason@emptycrate.com + build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . " + build_command: "cmake --build . -- -j2" + branch_pattern: coverity_scan diff --git a/CMakeLists.txt b/CMakeLists.txt index f8425918..59c33a36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE) option(BUILD_MODULES "Build Extra Modules (stl)" TRUE) option(BUILD_SAMPLES "Build Samples Folder" FALSE) +option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE) option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE) mark_as_advanced(USE_STD_MAKE_SHARED) @@ -94,7 +95,7 @@ set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt" set(CPACK_PACKAGE_VERSION_MAJOR 5) set(CPACK_PACKAGE_VERSION_MINOR 7) -set(CPACK_PACKAGE_VERSION_PATCH 0) +set(CPACK_PACKAGE_VERSION_PATCH 1) set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_VENDOR "ChaiScript.com") @@ -269,9 +270,51 @@ if(BUILD_MODULES) 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) - list(SORT UNIT_TESTS) + +if (RUN_FUZZY_TESTS) + + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests") + + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2015-07-16.tar.bz2 + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests + ) + + + file(GLOB FUZZY_CRASH_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/id*) + list(SORT FUZZY_CRASH_TESTS) + + file(GLOB FUZZY_EXCEPTION_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/id*) + list(SORT FUZZY_EXCEPTION_TESTS) + + + foreach(filename ${FUZZY_CRASH_TESTS}) + message(STATUS "Adding test ${filename}") + add_test(${filename} chai "-e" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename}) + endforeach() + + set_property(TEST ${FUZZY_CRASH_TESTS} + PROPERTY ENVIRONMENT + "CHAI_USE_PATH=${CMAKE_BINARY_DIR}/unittests/" + "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" + ) + + foreach(filename ${FUZZY_EXCEPTION_TESTS}) + message(STATUS "Adding test ${filename}") + add_test(${filename} chai "--exception" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename}) + endforeach() + + set_property(TEST ${FUZZY_EXCEPTION_TESTS} + PROPERTY ENVIRONMENT + "CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/" + "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" + ) + +endif() + + if(BUILD_TESTING) # Add catch tests macro @@ -314,6 +357,19 @@ if(BUILD_TESTING) "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" ) + add_test(version_check_2 chai --version ) + set_property(TEST version_check_2 + PROPERTY ENVIRONMENT + "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" + PROPERTY PASS_REGULAR_EXPRESSION "${CHAI_VERSION}" + ) + + add_test(help chai --help ) + set_property(TEST help + PROPERTY ENVIRONMENT + "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" + ) + foreach(filename ${UNIT_TESTS}) message(STATUS "Adding test ${filename}") diff --git a/cheatsheet.md b/cheatsheet.md index 8ec408ae..9ff4ad4b 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -1,3 +1,13 @@ +# ChaiScript Versioning + +ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme. This basically means: + + * Major Version Number: API changes / breaking changes + * Minor Version Number: New Features + * Patch Version Number: Minor changes / enhancements + + + # Initializing ChaiScript ``` @@ -30,6 +40,19 @@ chai.add(chaiscript::fun(&function_with_ove ``` chai.add(chaiscript::fun(std::static_cast(&function_with_overloads)), "function_name"); ``` +This overload technique is also used when exposing base member using derived type + +``` +struct Base +{ + int data; +}; + +struct Derived : public Base +{}; + +chai.add(chaiscript::fun(static_cast(&Derived::data)), "data"); +``` ### Lambda @@ -57,6 +80,18 @@ It's not strictly necessary to add types, but it helps with many things. Cloning chai.add(chaiscript::user_type, "MyClass"); ``` +## Adding Type Conversions + +User defined type conversions are possible, defined in either script or in C++. + +A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition: + +``` +chai.add(chaiscript::vector_conversion>()); +``` + +This allows you to pass a ChaiScript function to a function requiring `std::vector` + ## Adding Objects ``` @@ -68,6 +103,22 @@ 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(chaiscript::var(somevar), "somevar"); // global non-const ``` +# Using STL +ChaiScript recognize many types from STL, but you have to add specific instantiation yourself. + +``` +typedef std::vector> data_list; +data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") }; +chai.add(chaiscript::bootstrap::standard_library::vector_type("DataList")); +chai.add(chaiscript::bootstrap::standard_library::pair_type("DataElement")); +chai.add(chaiscript::var(&my_list), "data_list"); +chai.eval(R"_( + for(var i=0; i>(fun(x,y) { to_string(x) + to_string(y); }); +auto p = chai.eval>("fun(x,y) { to_string(x) + to_string(y); }"); p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++ ``` @@ -183,7 +236,7 @@ var m = ["a":1, "b":2]; // map of string:value pairs ``` Floating point values default to `double` type and integers default to `int` type. All C++ suffixes -such as `f`, `ll`, `u` as well as scientific notion is supported +such as `f`, `ll`, `u` as well as scientific notation are supported ``` 1.0 // double @@ -201,6 +254,9 @@ on your platform. ## Functions +Note that any type of ChaiScript function can be passed freely to C++ and automatically +converted into an `std::function` object. + ### General ``` diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 6bfa3e72..5b3bea5b 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -35,6 +35,10 @@ #define CHAISCRIPT_HAS_THREAD_LOCAL #endif +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 6) +#define CHAISCRIPT_GCC_4_6 +#endif + #if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__) #define CHAISCRIPT_OVERRIDE override #else @@ -61,7 +65,7 @@ namespace chaiscript { static const int version_major = 5; static const int version_minor = 7; - static const int version_patch = 0; + static const int version_patch = 1; template inline std::shared_ptr make_shared(Arg && ... arg) diff --git a/include/chaiscript/chaiscript_stdlib.hpp b/include/chaiscript/chaiscript_stdlib.hpp index 92483fd4..c07e64c6 100644 --- a/include/chaiscript/chaiscript_stdlib.hpp +++ b/include/chaiscript/chaiscript_stdlib.hpp @@ -18,6 +18,7 @@ #include "dispatchkit/bootstrap.hpp" #include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/boxed_value.hpp" +#include "language/chaiscript_prelude.chai" #ifndef CHAISCRIPT_NO_THREADS #include @@ -47,9 +48,11 @@ namespace chaiscript #ifndef CHAISCRIPT_NO_THREADS lib->add(standard_library::future_type>("future")); - lib->add(chaiscript::fun (const std::function &)>([](const std::function &t_func){ return std::async(std::launch::async, t_func);}), "async"); + lib->add(chaiscript::fun([](const std::function &t_func){ return std::async(std::launch::async, t_func);}), "async"); #endif + lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ ); + return lib; } diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index 6bac83ad..09fc617d 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -14,8 +14,10 @@ #include #include #else +#ifndef CHAISCRIPT_NO_THREADS_WARNING #pragma message ("ChaiScript is compiling without thread safety.") #endif +#endif #include "chaiscript_defines.hpp" @@ -153,6 +155,7 @@ namespace chaiscript private: + /// \todo this leaks thread instances. It needs to be culled from time to time std::shared_ptr get_tls() const { unique_lock lock(m_mutex); diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index 31344d45..c2be40fc 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -36,7 +36,7 @@ namespace chaiscript } bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) - : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast") + : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name()) { } diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 291a75f6..1624e023 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -57,7 +57,7 @@ namespace chaiscript typedef typename std::remove_extent::type ReturnType; const auto extent = std::extent::value; m->add(user_type(), type); - m->add(fun( + m->add(fun( [extent](T& t, size_t index)->ReturnType &{ if (extent > 0 && index >= extent) { throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); @@ -68,7 +68,7 @@ namespace chaiscript ), "[]" ); - m->add(fun( + m->add(fun( [extent](const T &t, size_t index)->const ReturnType &{ if (extent > 0 && index >= extent) { throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); @@ -79,7 +79,7 @@ namespace chaiscript ), "[]" ); - m->add(fun( + m->add(fun( [extent](const T &) { return extent; }), "size"); @@ -157,7 +157,12 @@ namespace chaiscript /// Internal function for converting from a string to a value /// uses ostream operator >> to perform the conversion template - Input parse_string(const std::string &i) + auto parse_string(const std::string &i) + -> typename std::enable_if< + !std::is_same::value + && !std::is_same::value + && !std::is_same::value, + Input>::type { std::stringstream ss(i); Input t; @@ -165,6 +170,17 @@ namespace chaiscript return t; } + template + auto parse_string(const std::string &) + -> typename std::enable_if< + std::is_same::value + || std::is_same::value + || std::is_same::value, + Input>::type + { + throw std::runtime_error("Parsing of wide characters is not yet supported"); + } + /// Add all common functions for a POD type. All operators, and /// common conversions @@ -175,11 +191,6 @@ namespace chaiscript m->add(constructor(), name); construct_pod(name, m); - auto to_s = fun(&to_string); - - if (!m->has_function(to_s, "to_string")) { - m->add(to_s, "to_string"); - } m->add(fun(&parse_string), "to_" + name); return m; } @@ -293,13 +304,17 @@ namespace chaiscript /// the remaining parameters are the args to bind into the result static Boxed_Value bind_function(const std::vector ¶ms) { - if (params.size() < 2) - { - throw exception::arity_error(static_cast(params.size()), 2); + if (params.empty()) { + throw exception::arity_error(0, 1); } Const_Proxy_Function f = boxed_cast(params[0]); + if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) + { + throw exception::arity_error(static_cast(params.size()), f->get_arity()); + } + return Boxed_Value(Const_Proxy_Function(std::make_shared(std::move(f), std::vector(params.begin() + 1, params.end())))); } @@ -408,6 +423,12 @@ namespace chaiscript m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); + m->add(user_type(), "out_of_range"); + m->add(user_type(), "logic_error"); + m->add(chaiscript::base_class()); + m->add(chaiscript::base_class()); + m->add(chaiscript::base_class()); + m->add(user_type(), "runtime_error"); m->add(chaiscript::base_class()); @@ -465,12 +486,15 @@ namespace chaiscript operators::assign(m); operators::equal(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(&unknown_assign), "="); m->add(fun(&throw_exception), "throw"); m->add(fun(&what), "what"); + m->add(fun(&to_string), "to_string"); + m->add(fun(&Boxed_Number::to_string), "to_string"); + bootstrap_pod_type("double", m); bootstrap_pod_type("long_double", m); bootstrap_pod_type("float", m); @@ -480,6 +504,9 @@ namespace chaiscript bootstrap_pod_type("unsigned_long", m); bootstrap_pod_type("size_t", m); bootstrap_pod_type("char", m); + bootstrap_pod_type("wchar_t", m); + bootstrap_pod_type("char16_t", m); + bootstrap_pod_type("char32_t", m); bootstrap_pod_type("int8_t", m); bootstrap_pod_type("int16_t", m); bootstrap_pod_type("int32_t", m); @@ -497,13 +524,13 @@ namespace chaiscript m->add(fun(&print), "print_string"); m->add(fun(&println), "println_string"); - m->add(chaiscript::make_shared(&bind_function), "bind"); + m->add(dispatch::make_dynamic_proxy_function(&bind_function), "bind"); m->add(fun(&shared_ptr_unconst_clone), "clone"); m->add(fun(&ptr_assign::type>), "="); m->add(fun(&ptr_assign::type>), "="); m->add(chaiscript::base_class()); - m->add(fun &)>( + m->add(fun( [](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr &t_rhs) { t_lhs.assign(t_rhs); } diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 260dc992..1a03888f 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -243,18 +243,18 @@ namespace chaiscript template ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = std::make_shared()) { - // cppcheck-suppress syntaxError - typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t); - //In the interest of runtime safety for the m, we prefer the at() method for [] access, //to throw an exception in an out of bounds condition. m->add( - fun(std::function - (std::mem_fn(static_cast(&ContainerType::at)))), "[]"); + fun( + [](ContainerType &c, int index) -> typename ContainerType::reference { + return c.at(index); + }), "[]"); + m->add( - fun( - [](const ContainerType *c, int index) -> typename ContainerType::const_reference { - return c->at(index); + fun( + [](const ContainerType &c, int index) -> typename ContainerType::const_reference { + return c.at(index); }), "[]"); return m; @@ -277,9 +277,9 @@ namespace chaiscript template ModulePtr container_type(const std::string &/*type*/, ModulePtr m = std::make_shared()) { - m->add(fun([](const ContainerType *a) { return a->size(); } ), "size"); - m->add(fun([](const ContainerType *a) { return a->empty(); } ), "empty"); - m->add(fun([](ContainerType *a) { a->clear(); } ), "clear"); + m->add(fun([](const ContainerType *a) { return a->size(); } ), "size"); + m->add(fun([](const ContainerType *a) { return a->empty(); } ), "empty"); + m->add(fun([](ContainerType *a) { a->clear(); } ), "clear"); return m; } @@ -319,7 +319,7 @@ namespace chaiscript /// Add back insertion sequence concept to the given ContainerType /// http://www.sgi.com/tech/stl/BackInsertionSequence.html template - ModulePtr back_insertion_sequence_type(const std::string &/*type*/, ModulePtr m = std::make_shared()) + ModulePtr back_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared()) { typedef typename ContainerType::reference (ContainerType::*backptr)(); @@ -328,8 +328,16 @@ namespace chaiscript typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &); m->add(fun(static_cast(&ContainerType::push_back)), - []()->std::string{ - if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { + [&]()->std::string{ + if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { + m->eval( + "# Pushes the second value onto the container while making a clone of the value\n" + "def push_back(" + type + " container, x)\n" + "{ \n" + " container.push_back_ref(clone(x)) \n" + "} \n" + ); + return "push_back_ref"; } else { return "push_back"; @@ -345,7 +353,7 @@ namespace chaiscript /// Front insertion sequence /// http://www.sgi.com/tech/stl/FrontInsertionSequence.html template - ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = std::make_shared()) + ModulePtr front_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared()) { typedef typename ContainerType::reference (ContainerType::*front_ptr)(); typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const; @@ -356,8 +364,15 @@ namespace chaiscript m->add(fun(static_cast(&ContainerType::front)), "front"); m->add(fun(static_cast(&ContainerType::push_front)), - []()->std::string{ + [&]()->std::string{ if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { + m->eval( + "# Pushes the second value onto the front of container while making a clone of the value\n" + "def push_front(" + type + " container, x)\n" + "{ \n" + " container.push_front_ref(clone(x)) \n" + "} \n" + ); return "push_front_ref"; } else { return "push_front"; @@ -438,9 +453,13 @@ namespace chaiscript m->add(user_type(), type); typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &); + typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const; m->add(fun(static_cast(&MapType::operator[])), "[]"); + m->add(fun(static_cast(&MapType::at)), "at"); + m->add(fun(static_cast(&MapType::at)), "at"); + container_type(type, m); default_constructible_type(type, m); assignable_type(type, m); @@ -547,23 +566,20 @@ namespace chaiscript }()); - typedef std::function find_func; + m->add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find"); + m->add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind"); + m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ), "find_first_of"); + m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of"); + m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of"); + m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of"); + m->add(fun([](String *s) { s->clear(); } ), "clear"); + m->add(fun([](const String *s) { return s->empty(); } ), "empty"); + m->add(fun([](const String *s) { return s->size(); } ), "size"); - m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find(f, pos); } )), "find"); - m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ) ), "rfind"); - m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ) ), "find_first_of"); - m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ) ), "find_last_of"); - m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ) ), "find_last_not_of"); - m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ) ), "find_first_not_of"); - - m->add(fun( std::function( [](String *s) { return s->clear(); } ) ), "clear"); - m->add(fun( std::function( [](const String *s) { return s->empty(); } ) ), "empty"); - m->add(fun( std::function( [](const String *s) { return s->size(); } ) ), "size"); - - m->add(fun( std::function( [](const String *s) { return s->c_str(); } ) ), "c_str"); - m->add(fun( std::function( [](const String *s) { return s->data(); } ) ), "data"); - m->add(fun( std::function( [](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ) ), "substr"); + m->add(fun([](const String *s) { return s->c_str(); } ), "c_str"); + m->add(fun([](const String *s) { return s->data(); } ), "data"); + m->add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr"); return m; } @@ -577,7 +593,7 @@ namespace chaiscript { m->add(user_type(), type); - m->add(fun([](const FutureType &t) { return t.valid(); }), "valid"); + m->add(fun([](const FutureType &t) { return t.valid(); }), "valid"); m->add(fun(&FutureType::get), "get"); m->add(fun(&FutureType::wait), "wait"); diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 106b9d8d..1ddaacc1 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -79,13 +79,6 @@ namespace chaiscript } -#ifdef CHAISCRIPT_MSVC - //Thank you MSVC, yes we know that a constant value is being used in the if - // statment in THIS VERSION of the template instantiation -#pragma warning(push) -#pragma warning(disable : 4127) -#endif - if (t_conversions && t_conversions->convertable_type()) { try { @@ -108,10 +101,6 @@ namespace chaiscript throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); } -#ifdef CHAISCRIPT_MSVC -#pragma warning(pop) -#endif - } } diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 3c96931f..8f478bf4 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -58,6 +58,7 @@ namespace chaiscript { }; + /// Cast_Helper_Inner for casting to a const * type template struct Cast_Helper_Inner @@ -81,11 +82,11 @@ namespace chaiscript typedef Result * Result_Type; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { - if (ob.is_ref()) + if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result)) { - return &(ob.get().cast >()).get(); + return static_cast(throw_if_null(ob.get_ptr())); } else { - return (ob.get().cast >()).get(); + throw chaiscript::detail::exception::bad_any_cast(); } } }; @@ -149,7 +150,6 @@ namespace chaiscript { }; - /// Cast_Helper_Inner for casting to a const std::shared_ptr & type template struct Cast_Helper_Inner > : Cast_Helper_Inner > @@ -162,7 +162,6 @@ namespace chaiscript }; - /// Cast_Helper_Inner for casting to a Boxed_Value type template<> struct Cast_Helper_Inner diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index a57ed7ab..c953886e 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -43,7 +43,7 @@ namespace chaiscript // this is OK, so we're disabling size/and sign type warnings #ifdef CHAISCRIPT_MSVC #pragma warning(push) -#pragma warning(disable : 4244 4018 4389 4146 4365) +#pragma warning(disable : 4244 4018 4389 4146 4365 4267) #endif @@ -59,8 +59,22 @@ namespace chaiscript class Boxed_Number { private: + enum class Common_Types { + t_int32, + t_double, + t_uint8, + t_int8, + t_uint16, + t_int16, + t_uint32, + t_uint64, + t_int64, + t_float, + t_long_double + }; + template - static void check_divide_by_zero(T t, typename std::enable_if::value>::type* = nullptr) + static inline void check_divide_by_zero(T t, typename std::enable_if::value>::type* = nullptr) { #ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO if (t == 0) { @@ -70,292 +84,401 @@ namespace chaiscript } template - static void check_divide_by_zero(T, typename std::enable_if::value>::type* = nullptr) + static inline void check_divide_by_zero(T, typename std::enable_if::value>::type* = nullptr) { } - struct boolean + static CHAISCRIPT_CONSTEXPR Common_Types get_common_type(size_t t_size, bool t_signed) { + return (t_size == 1 && t_signed)?(Common_Types::t_int8) + :(t_size == 1)?(Common_Types::t_uint8) + :(t_size == 2 && t_signed)?(Common_Types::t_int16) + :(t_size == 2)?(Common_Types::t_uint16) + :(t_size == 4 && t_signed)?(Common_Types::t_int32) + :(t_size == 4)?(Common_Types::t_uint32) + :(t_size == 8 && t_signed)?(Common_Types::t_int64) + :(Common_Types::t_uint64); + } - template - static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &) - { - switch (t_oper) - { - case Operators::equals: - return const_var(t == u); - case Operators::less_than: - return const_var(t < u); - case Operators::greater_than: - return const_var(t > u); - case Operators::less_than_equal: - return const_var(t <= u); - case Operators::greater_than_equal: - return const_var(t >= u); - case Operators::not_equal: - return const_var(t != u); - default: - throw chaiscript::detail::exception::bad_any_cast(); - } + static Common_Types get_common_type(const Boxed_Value &t_bv) + { + const Type_Info &inp_ = t_bv.get_type_info(); + + if (inp_ == typeid(int)) { + return get_common_type(sizeof(int), true); + } else if (inp_ == typeid(double)) { + return Common_Types::t_double; + } else if (inp_ == typeid(long double)) { + return Common_Types::t_long_double; + } else if (inp_ == typeid(float)) { + return Common_Types::t_float; + } else if (inp_ == typeid(char)) { + return get_common_type(sizeof(char), std::is_signed::value); + } else if (inp_ == typeid(unsigned char)) { + return get_common_type(sizeof(unsigned char), false); + } else if (inp_ == typeid(unsigned int)) { + return get_common_type(sizeof(unsigned int), false); + } else if (inp_ == typeid(long)) { + return get_common_type(sizeof(long), true); + } else if (inp_ == typeid(unsigned long)) { + return get_common_type(sizeof(unsigned long), false); + } else if (inp_ == typeid(std::int8_t)) { + return Common_Types::t_int8; + } else if (inp_ == typeid(std::int16_t)) { + return Common_Types::t_int16; + } else if (inp_ == typeid(std::int32_t)) { + return Common_Types::t_int32; + } else if (inp_ == typeid(std::int64_t)) { + return Common_Types::t_int64; + } else if (inp_ == typeid(std::uint8_t)) { + return Common_Types::t_uint8; + } else if (inp_ == typeid(std::uint16_t)) { + return Common_Types::t_uint16; + } else if (inp_ == typeid(std::uint32_t)) { + return Common_Types::t_uint32; + } else if (inp_ == typeid(std::uint64_t)) { + return Common_Types::t_uint64; + } else if (inp_ == typeid(wchar_t)) { + return get_common_type(sizeof(wchar_t), std::is_signed::value); + } else if (inp_ == typeid(char16_t)) { + return get_common_type(sizeof(char16_t), std::is_signed::value); + } else if (inp_ == typeid(char32_t)) { + return get_common_type(sizeof(char32_t), std::is_signed::value); + } else { + throw chaiscript::detail::exception::bad_any_cast(); } - }; + } - struct binary + template + static Boxed_Value boolean_go(Operators::Opers t_oper, const T &t, const T &u) { - template - static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs) + switch (t_oper) { - switch (t_oper) - { - case Operators::assign: - t = u; - break; - case Operators::pre_increment: - ++t; - break; - case Operators::pre_decrement: - --t; - break; - case Operators::assign_product: - t *= u; - break; - case Operators::assign_sum: - t += u; - break; - case Operators::assign_quotient: - check_divide_by_zero(u); - t /= u; - break; - case Operators::assign_difference: - t -= u; - break; - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - - return t_lhs; - } - }; - - struct binary_int - { - template - static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs) - { - switch (t_oper) - { - case Operators::assign_bitwise_and: - t &= u; - break; - case Operators::assign_bitwise_or: - t |= u; - break; - case Operators::assign_shift_left: - t <<= u; - break; - case Operators::assign_shift_right: - t >>= u; - break; - case Operators::assign_remainder: - check_divide_by_zero(u); - t %= u; - break; - case Operators::assign_bitwise_xor: - t ^= u; - break; - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - return t_lhs; - } - }; - - struct const_binary_int - { - template - static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &) - { - switch (t_oper) - { - case Operators::shift_left: - return const_var(t << u); - case Operators::shift_right: - return const_var(t >> u); - case Operators::remainder: - check_divide_by_zero(u); - return const_var(t % u); - case Operators::bitwise_and: - return const_var(t & u); - case Operators::bitwise_or: - return const_var(t | u); - case Operators::bitwise_xor: - return const_var(t ^ u); - case Operators::bitwise_complement: - return const_var(~t); - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - } - }; - - struct const_binary - { - template - static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &) - { - switch (t_oper) - { - case Operators::sum: - return const_var(t + u); - case Operators::quotient: - check_divide_by_zero(u); - return const_var(t / u); - case Operators::product: - return const_var(t * u); - case Operators::difference: - return const_var(t - u); - case Operators::unary_minus: - return const_var(-t); - case Operators::unary_plus: - return const_var(+t); - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - } - }; - - template - struct Go - { - static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) - { - if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag) - { - return boolean::go(t_oper, *static_cast(t_lhs.get_const_ptr()), *static_cast(t_rhs.get_const_ptr()), t_lhs); - } else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { - return binary::go(t_oper, *static_cast(t_lhs.get_ptr()), *static_cast(t_rhs.get_const_ptr()), t_lhs); - } else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { - return binary_int::go(t_oper, *static_cast(t_lhs.get_ptr()), *static_cast(t_rhs.get_const_ptr()), t_lhs); - } else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) { - return const_binary_int::go(t_oper, *static_cast(t_lhs.get_const_ptr()), *static_cast(t_rhs.get_const_ptr()), t_lhs); - } else if (t_oper > Operators::const_flag) { - return const_binary::go(t_oper, *static_cast(t_lhs.get_const_ptr()), *static_cast(t_rhs.get_const_ptr()), t_lhs); - } else { + case Operators::equals: + return const_var(t == u); + case Operators::less_than: + return const_var(t < u); + case Operators::greater_than: + return const_var(t > u); + case Operators::less_than_equal: + return const_var(t <= u); + case Operators::greater_than_equal: + return const_var(t >= u); + case Operators::not_equal: + return const_var(t != u); + default: throw chaiscript::detail::exception::bad_any_cast(); - } } - }; + } + + template + static Boxed_Value unary_go(Operators::Opers t_oper, T &t, const Boxed_Value &t_lhs) + { + switch (t_oper) + { + case Operators::pre_increment: + ++t; + break; + case Operators::pre_decrement: + --t; + break; + default: + throw chaiscript::detail::exception::bad_any_cast(); + } + + return t_lhs; + } + + template + static Boxed_Value binary_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs) + { + switch (t_oper) + { + case Operators::assign: + t = u; + break; + case Operators::assign_product: + t *= u; + break; + case Operators::assign_sum: + t += u; + break; + case Operators::assign_quotient: + check_divide_by_zero(u); + t /= u; + break; + case Operators::assign_difference: + t -= u; + break; + default: + throw chaiscript::detail::exception::bad_any_cast(); + } + + return t_lhs; + } + + template + static Boxed_Value binary_int_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs) + { + switch (t_oper) + { + case Operators::assign_bitwise_and: + t &= u; + break; + case Operators::assign_bitwise_or: + t |= u; + break; + case Operators::assign_shift_left: + t <<= u; + break; + case Operators::assign_shift_right: + t >>= u; + break; + case Operators::assign_remainder: + check_divide_by_zero(u); + t %= u; + break; + case Operators::assign_bitwise_xor: + t ^= u; + break; + default: + throw chaiscript::detail::exception::bad_any_cast(); + } + return t_lhs; + } + + template + static Boxed_Value const_unary_int_go(Operators::Opers t_oper, const T &t) + { + switch (t_oper) + { + case Operators::bitwise_complement: + return const_var(~t); + default: + throw chaiscript::detail::exception::bad_any_cast(); + } + } + + template + static Boxed_Value const_binary_int_go(Operators::Opers t_oper, const T &t, const T &u) + { + switch (t_oper) + { + case Operators::shift_left: + return const_var(t << u); + case Operators::shift_right: + return const_var(t >> u); + case Operators::remainder: + check_divide_by_zero(u); + return const_var(t % u); + case Operators::bitwise_and: + return const_var(t & u); + case Operators::bitwise_or: + return const_var(t | u); + case Operators::bitwise_xor: + return const_var(t ^ u); + default: + throw chaiscript::detail::exception::bad_any_cast(); + } + } + + template + static Boxed_Value const_unary_go(Operators::Opers t_oper, const T &t) + { + switch (t_oper) + { + case Operators::unary_minus: + return const_var(-t); + case Operators::unary_plus: + return const_var(+t); + default: + throw chaiscript::detail::exception::bad_any_cast(); + } + } + + template + static Boxed_Value const_binary_go(Operators::Opers t_oper, const T &t, const T &u) + { + switch (t_oper) + { + case Operators::sum: + return const_var(t + u); + case Operators::quotient: + check_divide_by_zero(u); + return const_var(t / u); + case Operators::product: + return const_var(t * u); + case Operators::difference: + return const_var(t - u); + default: + throw chaiscript::detail::exception::bad_any_cast(); + } + } template - struct Go + static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) + -> typename std::enable_if::value && !std::is_floating_point::value, Boxed_Value>::type { - static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) + typedef typename std::common_type::type common_type; + if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag) { - if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag) - { - return boolean::go(t_oper, *static_cast(t_lhs.get_const_ptr()), *static_cast(t_rhs.get_const_ptr()), t_lhs); - } else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { - return binary::go(t_oper, *static_cast(t_lhs.get_ptr()), *static_cast(t_rhs.get_const_ptr()), t_lhs); - } else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag) { - throw chaiscript::detail::exception::bad_any_cast(); - } else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) { - throw chaiscript::detail::exception::bad_any_cast(); - } else if (t_oper > Operators::const_flag) { - return const_binary::go(t_oper, *static_cast(t_lhs.get_const_ptr()), *static_cast(t_rhs.get_const_ptr()), t_lhs); - } else { - throw chaiscript::detail::exception::bad_any_cast(); - } + return boolean_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); + } else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { + return binary_go(t_oper, *static_cast(t_lhs.get_ptr()), get_as_aux(t_rhs), t_lhs); + } else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { + return binary_int_go(t_oper, *static_cast(t_lhs.get_ptr()), get_as_aux(t_rhs), t_lhs); + } else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) { + return const_binary_int_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); + } else if (t_oper > Operators::const_flag) { + return const_binary_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); + } else { + throw chaiscript::detail::exception::bad_any_cast(); } - }; + } - template - static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) + template + static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) + -> typename std::enable_if::value || std::is_floating_point::value, Boxed_Value>::type + { + typedef typename std::common_type::type common_type; + if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag) { - const auto &inp_ = t_rhs.get_type_info(); + return boolean_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); + } else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { + return binary_go(t_oper, *static_cast(t_lhs.get_ptr()), get_as_aux(t_rhs), t_lhs); + } else if (t_oper > Operators::const_flag) { + return const_binary_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); + } else { + throw chaiscript::detail::exception::bad_any_cast(); + } + } - if (inp_ == typeid(int)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(double)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(float)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(long double)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(char)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(unsigned int)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(long)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(unsigned long)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::int8_t)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::int16_t)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::int32_t)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::int64_t)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::uint8_t)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::uint16_t)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::uint32_t)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::uint64_t)) { - return Go::go(t_oper, t_lhs, t_rhs); - } else { - throw chaiscript::detail::exception::bad_any_cast(); - } - } + // Unary + template + static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs) + -> typename std::enable_if::value, Boxed_Value>::type + { + if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { + return unary_go(t_oper, *static_cast(t_lhs.get_ptr()), t_lhs); + } else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) { + return const_unary_int_go(t_oper, *static_cast(t_lhs.get_const_ptr())); + } else if (t_oper > Operators::const_flag) { + return const_unary_go(t_oper, *static_cast(t_lhs.get_const_ptr())); + } else { + throw chaiscript::detail::exception::bad_any_cast(); + } + } - static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) + template + static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs) + -> typename std::enable_if::value, Boxed_Value>::type + { + if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { + return unary_go(t_oper, *static_cast(t_lhs.get_ptr()), t_lhs); + } else if (t_oper > Operators::const_flag) { + return const_unary_go(t_oper, *static_cast(t_lhs.get_const_ptr())); + } else { + throw chaiscript::detail::exception::bad_any_cast(); + } + } + + template + inline static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) { - const Type_Info &inp_ = t_lhs.get_type_info(); - - if (inp_ == typeid(int)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(double)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(long double)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(float)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(char)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(unsigned int)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(long)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(unsigned long)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::int8_t)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::int16_t)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::int32_t)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::int64_t)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::uint8_t)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::uint16_t)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::uint32_t)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else if (inp_ == typeid(std::uint64_t)) { - return oper_rhs(t_oper, t_lhs, t_rhs); - } else { - throw chaiscript::detail::exception::bad_any_cast(); + switch (get_common_type(t_rhs)) { + case Common_Types::t_int32: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_uint8: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_int8: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_uint16: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_int16: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_uint32: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_uint64: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_int64: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_double: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_float: + return go(t_oper, t_lhs, t_rhs); + case Common_Types::t_long_double: + return go(t_oper, t_lhs, t_rhs); } + + throw chaiscript::detail::exception::bad_any_cast(); + } + + inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) + { + switch (get_common_type(t_lhs)) { + case Common_Types::t_int32: + return go(t_oper, t_lhs); + case Common_Types::t_uint8: + return go(t_oper, t_lhs); + case Common_Types::t_int8: + return go(t_oper, t_lhs); + case Common_Types::t_uint16: + return go(t_oper, t_lhs); + case Common_Types::t_int16: + return go(t_oper, t_lhs); + case Common_Types::t_uint32: + return go(t_oper, t_lhs); + case Common_Types::t_uint64: + return go(t_oper, t_lhs); + case Common_Types::t_int64: + return go(t_oper, t_lhs); + case Common_Types::t_double: + return go(t_oper, t_lhs); + case Common_Types::t_float: + return go(t_oper, t_lhs); + case Common_Types::t_long_double: + return go(t_oper, t_lhs); + } + + throw chaiscript::detail::exception::bad_any_cast(); + } + + + inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) + { + switch (get_common_type(t_lhs)) { + case Common_Types::t_int32: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_uint8: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_int8: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_uint16: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_int16: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_uint32: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_uint64: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_int64: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_double: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_float: + return oper_rhs(t_oper, t_lhs, t_rhs); + case Common_Types::t_long_double: + return oper_rhs(t_oper, t_lhs, t_rhs); + } + + throw chaiscript::detail::exception::bad_any_cast(); } template - Target get_as_aux() const - { - return static_cast(*static_cast(bv.get_const_ptr())); - } + static inline Target get_as_aux(const Boxed_Value &t_bv) + { + return static_cast(*static_cast(t_bv.get_const_ptr())); + } template static std::string to_string_aux(const Boxed_Value &v) @@ -402,6 +525,14 @@ namespace chaiscript return Boxed_Number(get_as()); } else if (inp_.bare_equal_type_info(typeid(char))) { return Boxed_Number(get_as()); + } else if (inp_.bare_equal_type_info(typeid(unsigned char))) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal_type_info(typeid(wchar_t))) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal_type_info(typeid(char16_t))) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal_type_info(typeid(char32_t))) { + return Boxed_Number(get_as()); } else if (inp_.bare_equal_type_info(typeid(unsigned int))) { return Boxed_Number(get_as()); } else if (inp_.bare_equal_type_info(typeid(long))) { @@ -432,84 +563,62 @@ namespace chaiscript template Target get_as() const { - const Type_Info &inp_ = bv.get_type_info(); - - if (inp_ == typeid(int)) { - return get_as_aux(); - } else if (inp_ == typeid(double)) { - return get_as_aux(); - } else if (inp_ == typeid(float)) { - return get_as_aux(); - } else if (inp_ == typeid(long double)) { - return get_as_aux(); - } else if (inp_ == typeid(char)) { - return get_as_aux(); - } else if (inp_ == typeid(unsigned int)) { - return get_as_aux(); - } else if (inp_ == typeid(long)) { - return get_as_aux(); - } else if (inp_ == typeid(unsigned long)) { - return get_as_aux(); - } else if (inp_ == typeid(std::int8_t)) { - return get_as_aux(); - } else if (inp_ == typeid(std::int16_t)) { - return get_as_aux(); - } else if (inp_ == typeid(std::int32_t)) { - return get_as_aux(); - } else if (inp_ == typeid(std::int64_t)) { - return get_as_aux(); - } else if (inp_ == typeid(std::uint8_t)) { - return get_as_aux(); - } else if (inp_ == typeid(std::uint16_t)) { - return get_as_aux(); - } else if (inp_ == typeid(std::uint32_t)) { - return get_as_aux(); - } else if (inp_ == typeid(std::uint64_t)) { - return get_as_aux(); - } else { - throw chaiscript::detail::exception::bad_any_cast(); + switch (get_common_type(bv)) { + case Common_Types::t_int32: + return get_as_aux(bv); + case Common_Types::t_uint8: + return get_as_aux(bv); + case Common_Types::t_int8: + return get_as_aux(bv); + case Common_Types::t_uint16: + return get_as_aux(bv); + case Common_Types::t_int16: + return get_as_aux(bv); + case Common_Types::t_uint32: + return get_as_aux(bv); + case Common_Types::t_uint64: + return get_as_aux(bv); + case Common_Types::t_int64: + return get_as_aux(bv); + case Common_Types::t_double: + return get_as_aux(bv); + case Common_Types::t_float: + return get_as_aux(bv); + case Common_Types::t_long_double: + return get_as_aux(bv); } + + throw chaiscript::detail::exception::bad_any_cast(); } std::string to_string() const { - const Type_Info &inp_ = bv.get_type_info(); - - if (inp_ == typeid(int)) { - return to_string_aux(bv); - } else if (inp_ == typeid(double)) { - return to_string_aux(bv); - } else if (inp_ == typeid(float)) { - return to_string_aux(bv); - } else if (inp_ == typeid(long double)) { - return to_string_aux(bv); - } else if (inp_ == typeid(char)) { - return to_string_aux(Boxed_Value(get_as_aux())); - } else if (inp_ == typeid(unsigned int)) { - return to_string_aux(bv); - } else if (inp_ == typeid(long)) { - return to_string_aux(bv); - } else if (inp_ == typeid(unsigned long)) { - return to_string_aux(bv); - } else if (inp_ == typeid(std::int8_t)) { - return to_string_aux(Boxed_Value(get_as_aux())); - } else if (inp_ == typeid(std::int16_t)) { - return to_string_aux(bv); - } else if (inp_ == typeid(std::int32_t)) { - return to_string_aux(bv); - } else if (inp_ == typeid(std::int64_t)) { - return to_string_aux(bv); - } else if (inp_ == typeid(std::uint8_t)) { - return to_string_aux(Boxed_Value(get_as_aux())); - } else if (inp_ == typeid(std::uint16_t)) { - return to_string_aux(bv); - } else if (inp_ == typeid(std::uint32_t)) { - return to_string_aux(bv); - } else if (inp_ == typeid(std::uint64_t)) { - return to_string_aux(bv); - } else { - throw chaiscript::detail::exception::bad_any_cast(); + switch (get_common_type(bv)) { + case Common_Types::t_int32: + return std::to_string(get_as()); + case Common_Types::t_uint8: + return std::to_string(get_as()); + case Common_Types::t_int8: + return std::to_string(get_as()); + case Common_Types::t_uint16: + return std::to_string(get_as()); + case Common_Types::t_int16: + return std::to_string(get_as()); + case Common_Types::t_uint32: + return std::to_string(get_as()); + case Common_Types::t_uint64: + return std::to_string(get_as()); + case Common_Types::t_int64: + return std::to_string(get_as()); + case Common_Types::t_double: + return to_string_aux(bv); + case Common_Types::t_float: + return to_string_aux(bv); + case Common_Types::t_long_double: + return to_string_aux(bv); } + + throw chaiscript::detail::exception::bad_any_cast(); } bool operator==(const Boxed_Number &t_rhs) const @@ -544,12 +653,12 @@ namespace chaiscript Boxed_Number operator--() { - return oper(Operators::pre_decrement, this->bv, var(0)); + return oper(Operators::pre_decrement, this->bv); } Boxed_Number operator++() { - return oper(Operators::pre_increment, this->bv, var(0)); + return oper(Operators::pre_increment, this->bv); } Boxed_Number operator+(const Boxed_Number &t_rhs) const @@ -559,12 +668,12 @@ namespace chaiscript Boxed_Number operator+() const { - return oper(Operators::unary_plus, this->bv, Boxed_Value(0)); + return oper(Operators::unary_plus, this->bv); } Boxed_Number operator-() const { - return oper(Operators::unary_minus, this->bv, Boxed_Value(0)); + return oper(Operators::unary_minus, this->bv); } Boxed_Number operator-(const Boxed_Number &t_rhs) const @@ -637,7 +746,7 @@ namespace chaiscript Boxed_Number operator~() const { - return oper(Operators::bitwise_complement, this->bv, Boxed_Value(0)); + return oper(Operators::bitwise_complement, this->bv); } Boxed_Number operator^(const Boxed_Number &t_rhs) const @@ -726,12 +835,12 @@ namespace chaiscript static Boxed_Number pre_decrement(Boxed_Number t_lhs) { - return oper(Operators::pre_decrement, t_lhs.bv, var(0)); + return oper(Operators::pre_decrement, t_lhs.bv); } static Boxed_Number pre_increment(Boxed_Number t_lhs) { - return oper(Operators::pre_increment, t_lhs.bv, var(0)); + return oper(Operators::pre_increment, t_lhs.bv); } static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) @@ -741,12 +850,12 @@ namespace chaiscript static const Boxed_Number unary_plus(const Boxed_Number &t_lhs) { - return oper(Operators::unary_plus, t_lhs.bv, Boxed_Value(0)); + return oper(Operators::unary_plus, t_lhs.bv); } static const Boxed_Number unary_minus(const Boxed_Number &t_lhs) { - return oper(Operators::unary_minus, t_lhs.bv, Boxed_Value(0)); + return oper(Operators::unary_minus, t_lhs.bv); } static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) @@ -862,7 +971,7 @@ namespace chaiscript static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) { - return oper(t_oper, t_lhs, const_var(0)); + return oper(t_oper, t_lhs); } diff --git a/include/chaiscript/dispatchkit/callable_traits.hpp b/include/chaiscript/dispatchkit/callable_traits.hpp new file mode 100644 index 00000000..9954eeab --- /dev/null +++ b/include/chaiscript/dispatchkit/callable_traits.hpp @@ -0,0 +1,96 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_ +#define CHAISCRIPT_CALLABLE_TRAITS_HPP_ + +#include + +namespace chaiscript { + namespace dispatch { + namespace detail { + + template + struct Constructor + { + template + std::shared_ptr operator()(Inner&& ... inner) const { + return std::make_shared(std::forward(inner)...); + } + }; + + template + struct Const_Caller + { + Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {} + + template + Ret operator()(const Class &o, Inner&& ... inner) const { + return (o.*m_func)(std::forward(inner)...); + } + + Ret (Class::*m_func)(Param...) const; + }; + + template + struct Fun_Caller + { + Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {} + + template + Ret operator()(Inner&& ... inner) const { + return (m_func)(std::forward(inner)...); + } + + Ret(*m_func)(Param...); + }; + + template + struct Caller + { + Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {} + + template + Ret operator()(Class &o, Inner&& ... inner) const { + return (o.*m_func)(std::forward(inner)...); + } + + Ret (Class::*m_func)(Param...); + }; + + + template + struct Function_Signature + { + }; + + template + struct Function_Signature + { + typedef Ret Return_Type; + typedef Ret (Signature)(Params...); + }; + + template + struct Function_Signature + { + typedef Ret Return_Type; + typedef Ret (Signature)(Params...); + }; + + + template + struct Callable_Traits + { + typedef typename Function_Signature::Signature Signature; + typedef typename Function_Signature::Return_Type Return_Type; + }; + } + } +} + +#endif + diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 5e7d18d5..43cb7b12 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -22,6 +22,7 @@ #include "../chaiscript_defines.hpp" #include "../chaiscript_threading.hpp" +#include "bad_boxed_cast.hpp" #include "boxed_cast.hpp" #include "boxed_cast_helper.hpp" #include "boxed_value.hpp" @@ -384,19 +385,41 @@ namespace chaiscript namespace detail { + struct Stack_Holder + { + typedef std::vector> Scope; + typedef std::vector StackData; + + Stack_Holder() + : call_depth(0) + { + stacks.reserve(2); + stacks.emplace_back(1); + call_params.emplace_back(); + call_params.back().reserve(2); + } + + std::vector stacks; + + std::vector> call_params; + int call_depth; + }; + /// Main class for the dispatchkit. Handles management /// of the object stack, functions and registered types. class Dispatch_Engine { + public: typedef std::map Type_Name_Map; - typedef std::map Scope; + typedef std::vector> Scope; typedef std::vector StackData; struct State { std::map > m_functions; std::map m_function_objects; + std::map m_boxed_functions; std::map m_global_objects; Type_Name_Map m_types; std::set m_reserved_words; @@ -407,8 +430,7 @@ namespace chaiscript }; Dispatch_Engine() - : m_stack_holder(this), - m_place_holder(std::make_shared()) + : m_stack_holder(this) { } @@ -438,14 +460,18 @@ namespace chaiscript /// Set the value of an object, by name. If the object /// is not available in the current scope it is created - void add(const Boxed_Value &obj, const std::string &name) + void add(Boxed_Value obj, const std::string &name) { validate_object_name(name); auto &stack = get_stack_data(); for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) { - auto itr = stack_elem->find(name); + auto itr = std::find_if(stack_elem->begin(), stack_elem->end(), + [&](const std::pair &o) { + return o.first == name; + }); + if (itr != stack_elem->end()) { itr->second = std::move(obj); @@ -460,12 +486,20 @@ namespace chaiscript /// 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 &name, const Boxed_Value &obj) + void add_object(const std::string &name, Boxed_Value obj) { - if (!get_stack_data().back().insert(std::make_pair(name, obj)).second) + auto &stack_elem = get_stack_data().back(); + + if (std::any_of(stack_elem.begin(), stack_elem.end(), + [&](const std::pair &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 @@ -524,15 +558,27 @@ namespace chaiscript /// Adds a new scope to the stack void new_scope() { - get_stack_data().emplace_back(); - m_stack_holder->call_params.emplace_back(); + new_scope(*m_stack_holder); } /// Pops the current scope from the stack void pop_scope() { - m_stack_holder->call_params.pop_back(); - StackData &stack = get_stack_data(); + pop_scope(*m_stack_holder); + } + + /// Adds a new scope to the stack + void new_scope(Stack_Holder &t_holder) + { + get_stack_data(t_holder).emplace_back(); + t_holder.call_params.emplace_back(); + } + + /// Pops the current scope from the stack + void pop_scope(Stack_Holder &t_holder) + { + t_holder.call_params.pop_back(); + StackData &stack = get_stack_data(t_holder); if (stack.size() > 1) { stack.pop_back(); @@ -543,38 +589,56 @@ namespace chaiscript /// Pushes a new stack on to the list of stacks - void new_stack() + void new_stack(Stack_Holder &t_holder) { // add a new Stack with 1 element - m_stack_holder->stacks.emplace_back(1); + t_holder.stacks.emplace_back(1); } - void pop_stack() + void pop_stack(Stack_Holder &t_holder) { - m_stack_holder->stacks.pop_back(); + t_holder.stacks.pop_back(); } /// Searches the current stack for an object of the given name /// includes a special overload for the _ place holder object to /// ensure that it is always in scope. - Boxed_Value get_object(const std::string &name) const + Boxed_Value get_object(const std::string &name, std::atomic_uint_fast32_t &t_loc) const { - // Is it a placeholder object? - if (name == "_") - { - return m_place_holder; - } + enum class Loc : uint_fast32_t { + located = 0x80000000, + is_local = 0x40000000, + stack_mask = 0x0FFF0000, + loc_mask = 0x0000FFFF + }; - auto &stack = get_stack_data(); + uint_fast32_t loc = t_loc.load(std::memory_order_relaxed); - // Is it in the stack? - for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) + if (loc == 0) { - const auto stackitr = stack_elem->find(name); - if (stackitr != stack_elem->end()) + auto &stack = get_stack_data(); + + // Is it in the stack? + for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) { - return stackitr->second; + for (auto s = stack_elem->begin(); s != stack_elem->end(); ++s ) + { + if (s->first == name) { + t_loc.store( static_cast(std::distance(stack.rbegin(), stack_elem) << 16) + | static_cast(std::distance(stack_elem->begin(), s)) + | static_cast(Loc::located) + | static_cast(Loc::is_local), + std::memory_order_relaxed); + return s->second; + } + } } + + t_loc.store( static_cast(Loc::located), std::memory_order_relaxed); + } else if (loc & static_cast(Loc::is_local)) { + auto &stack = get_stack_data(); + + return stack[stack.size() - 1 - ((loc & static_cast(Loc::stack_mask)) >> 16)][loc & static_cast(Loc::loc_mask)].second; } // Is the value we are looking for a global? @@ -671,13 +735,13 @@ namespace chaiscript // std::cout << "Getting function object: " << t_name << '\n'; chaiscript::detail::threading::shared_lock l(m_mutex); - const auto &funs = get_function_objects_int(); + const auto &funs = get_boxed_functions_int(); auto itr = funs.find(t_name); if (itr != funs.end()) { - return const_var(itr->second); + return itr->second; } else { throw std::range_error("Object not found: " + t_name); } @@ -699,9 +763,9 @@ namespace chaiscript auto &stack = get_stack_data(); if (stack.size() > 1) { - return stack[1]; + return std::map(stack[1].begin(), stack[1].end()); } else { - return stack[0]; + return std::map(stack[0].begin(), stack[0].end()); } } @@ -710,7 +774,7 @@ namespace chaiscript { auto &stack = get_stack_data(); auto &scope = stack.front(); - return scope; + return std::map(scope.begin(), scope.end()); } /// \brief Sets all of the locals for the current thread state. @@ -722,7 +786,7 @@ namespace chaiscript { auto &stack = get_stack_data(); auto &scope = stack.front(); - scope = t_locals; + scope = std::vector>(t_locals.begin(), t_locals.end()); } @@ -843,7 +907,14 @@ namespace chaiscript std::vector remaining_params{l_params.begin() + l_num_params, l_params.end()}; Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); if (!remaining_params.empty() || bv.get_type_info().bare_equal(user_type())) { - return (*boxed_cast(bv))(remaining_params, l_conversions); + auto func = boxed_cast>(bv); + try { + return (*func)(remaining_params, l_conversions); + } catch (const chaiscript::exception::bad_boxed_cast &) { + } catch (const chaiscript::exception::arity_error &) { + } catch (const chaiscript::exception::guard_error &) { + } + throw chaiscript::exception::dispatch_error(remaining_params, std::vector{func}); } else { return bv; } @@ -1061,55 +1132,79 @@ namespace chaiscript m_state = t_state; } + void save_function_params(Stack_Holder &t_s, std::initializer_list 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 &&t_params) + { + for (auto &¶m : t_params) + { + t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(param)); + } + } + + void save_function_params(Stack_Holder &t_s, const std::vector &t_params) + { + t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end()); + } + void save_function_params(std::initializer_list t_params) { - Stack_Holder &s = *m_stack_holder; - s.call_params.back().insert(s.call_params.back().begin(), std::move(t_params)); + save_function_params(*m_stack_holder, std::move(t_params)); } void save_function_params(std::vector &&t_params) { - Stack_Holder &s = *m_stack_holder; - - for (auto &¶m : t_params) - { - s.call_params.back().insert(s.call_params.back().begin(), std::move(param)); - } + save_function_params(*m_stack_holder, std::move(t_params)); } void save_function_params(const std::vector &t_params) { - Stack_Holder &s = *m_stack_holder; - s.call_params.back().insert(s.call_params.back().begin(), t_params.begin(), t_params.end()); + save_function_params(*m_stack_holder, t_params); } - void new_function_call() + void new_function_call(Stack_Holder &t_s) { - Stack_Holder &s = *m_stack_holder; - if (s.call_depth == 0) + if (t_s.call_depth == 0) { m_conversions.enable_conversion_saves(true); } - ++s.call_depth; + ++t_s.call_depth; save_function_params(m_conversions.take_saves()); } - void pop_function_call() + void pop_function_call(Stack_Holder &t_s) { - Stack_Holder &s = *m_stack_holder; - --s.call_depth; + --t_s.call_depth; - assert(s.call_depth >= 0); + assert(t_s.call_depth >= 0); - if (s.call_depth == 0) + if (t_s.call_depth == 0) { - s.call_params.back().clear(); + t_s.call_params.back().clear(); m_conversions.enable_conversion_saves(false); } } + void new_function_call() + { + new_function_call(*m_stack_holder); + } + + void pop_function_call() + { + pop_function_call(*m_stack_holder); + } + + Stack_Holder &get_stack_holder() + { + return *m_stack_holder; + } + private: /// Returns the current stack /// make const/non const versions @@ -1118,11 +1213,26 @@ namespace chaiscript return m_stack_holder->stacks.back(); } + StackData &get_stack_data(Stack_Holder &t_holder) + { + return t_holder.stacks.back(); + } + StackData &get_stack_data() { return m_stack_holder->stacks.back(); } + const std::map &get_boxed_functions_int() const + { + return m_state.m_boxed_functions; + } + + std::map &get_boxed_functions_int() + { + return m_state.m_boxed_functions; + } + const std::map &get_function_objects_int() const { return m_state.m_function_objects; @@ -1175,8 +1285,13 @@ namespace chaiscript const auto lhssize = lhsparamtypes.size(); const auto rhssize = rhsparamtypes.size(); - CHAISCRIPT_CONSTEXPR auto boxed_type = user_type(); - CHAISCRIPT_CONSTEXPR auto boxed_pod_type = user_type(); +#ifdef CHAISCRIPT_HAS_MAGIC_STATICS + static auto boxed_type = user_type(); + static auto boxed_pod_type = user_type(); +#else + auto boxed_type = user_type(); + auto boxed_pod_type = user_type(); +#endif for (size_t i = 1; i < lhssize && i < rhssize; ++i) { @@ -1258,61 +1373,76 @@ namespace chaiscript auto itr = funcs.find(t_name); auto &func_objs = get_function_objects_int(); + auto &boxed_funcs = get_boxed_functions_int(); - if (itr != funcs.end()) - { - auto &vec = itr->second; - for (const auto &func : vec) - { - if ((*t_f) == *(func)) + Proxy_Function new_func = + [&]() -> Proxy_Function { + if (itr != funcs.end()) { - throw chaiscript::exception::name_conflict_error(t_name); + auto &vec = itr->second; + for (const auto &func : vec) + { + if ((*t_f) == *(func)) + { + throw chaiscript::exception::name_conflict_error(t_name); + } + } + + vec.push_back(t_f); + std::stable_sort(vec.begin(), vec.end(), &function_less_than); + return std::make_shared(vec); + } else if (t_f->has_arithmetic_param()) { + // if the function is the only function but it also contains + // arithmetic operators, we must wrap it in a dispatch function + // to allow for automatic arithmetic type conversions + std::vector vec({t_f}); + funcs.insert(std::make_pair(t_name, vec)); + return std::make_shared(std::move(vec)); + } else { + funcs.insert(std::make_pair(t_name, std::vector{t_f})); + return t_f; } - } - - vec.push_back(t_f); - std::stable_sort(vec.begin(), vec.end(), &function_less_than); - func_objs[t_name] = std::make_shared(vec); - } else if (t_f->has_arithmetic_param()) { - // if the function is the only function but it also contains - // arithmetic operators, we must wrap it in a dispatch function - // to allow for automatic arithmetic type conversions - std::vector vec({t_f}); - funcs.insert(std::make_pair(t_name, vec)); - func_objs[t_name] = std::make_shared(std::move(vec)); - } else { - funcs.insert(std::make_pair(t_name, std::vector{t_f})); - func_objs[t_name] = t_f; - } - + }(); + boxed_funcs[t_name] = const_var(new_func); + func_objs[t_name] = std::move(new_func); } mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex; - struct Stack_Holder - { - Stack_Holder() - : call_depth(0) - { - stacks.emplace_back(1); - call_params.emplace_back(); - } - - std::deque stacks; - - std::deque> call_params; - int call_depth; - }; Type_Conversions m_conversions; chaiscript::detail::threading::Thread_Storage m_stack_holder; State m_state; + }; - Boxed_Value m_place_holder; + class Dispatch_State + { + public: + Dispatch_State(Dispatch_Engine &t_engine) + : m_engine(t_engine), + m_stack_holder(t_engine.get_stack_holder()) + { + } + + Dispatch_Engine *operator->() const { + return &m_engine.get(); + } + + Dispatch_Engine &operator*() const { + return m_engine.get(); + } + + Stack_Holder &stack_holder() const { + return m_stack_holder.get(); + } + + private: + std::reference_wrapper m_engine; + std::reference_wrapper m_stack_holder; }; } } diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 9410d150..4054b591 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -31,9 +31,9 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions *t_conversions) { - return boxed_cast(dispatch::dispatch(t_funcs, params, t_conversions)); + return boxed_cast(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()), t_conversions); } }; @@ -44,9 +44,9 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions *t_conversions) { - return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as(); + return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions())).get_as(); } }; @@ -58,9 +58,9 @@ namespace chaiscript struct Function_Caller_Ret { static void call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions *t_conversions) { - dispatch::dispatch(t_funcs, params, t_conversions); + dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()); } }; @@ -70,31 +70,53 @@ namespace chaiscript template struct Build_Function_Caller_Helper { - Build_Function_Caller_Helper(std::vector t_funcs, const Type_Conversions &t_conversions) + Build_Function_Caller_Helper(std::vector t_funcs, const Type_Conversions *t_conversions) : m_funcs(std::move(t_funcs)), m_conversions(t_conversions) { } - Ret operator()(Param...param) + template + Ret operator()(P&& ... param) { return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, { - (std::is_reference::value&&!(std::is_same::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)... + box

(std::forward

(param))... }, m_conversions ); } + template + static auto box(Q&& q) -> typename std::enable_if::value&&!std::is_same::type>::type>::value, Boxed_Value>::type + { + return Boxed_Value(std::ref(std::forward(q))); + } + + template + static auto box(Q&& q) -> typename std::enable_if::value&&!std::is_same::type>::type>::value, Boxed_Value>::type + { + return Boxed_Value(std::forward(q)); + } + + template + static Boxed_Value box(Boxed_Value bv) + { + return bv; + } + + std::vector m_funcs; - Type_Conversions m_conversions; + const Type_Conversions *m_conversions; }; + /// \todo what happens if t_conversions is deleted out from under us?! template std::function build_function_caller_helper(Ret (Params...), const std::vector &funcs, const Type_Conversions *t_conversions) { + /* if (funcs.size() == 1) { std::shared_ptr> pfi = @@ -108,8 +130,9 @@ namespace chaiscript // looks like this either wasn't a Proxy_Function_Impl or the types didn't match // we cannot make any other guesses or assumptions really, so continuing } +*/ - return std::function(Build_Function_Caller_Helper(funcs, t_conversions?*t_conversions:Type_Conversions())); + return std::function(Build_Function_Caller_Helper(funcs, t_conversions)); } } } diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index ed165e02..e3a82545 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include "boxed_number.hpp" @@ -23,7 +22,7 @@ namespace chaiscript { namespace dispatch { - template class Proxy_Function_Impl; + template class Proxy_Function_Callable_Impl; template class Assignable_Proxy_Function_Impl; namespace detail @@ -54,9 +53,7 @@ namespace chaiscript { static Boxed_Value handle(const std::function &f) { return Boxed_Value( - std::shared_ptr( - new dispatch::Proxy_Function_Impl(f) - ) + chaiscript::make_shared>>(f) ); } }; @@ -66,10 +63,8 @@ namespace chaiscript { static Boxed_Value handle(const std::function &f) { return Boxed_Value( - std::shared_ptr( - new Proxy_Function_Impl(f) - ) - ); + chaiscript::make_shared>>(f) + ); } }; @@ -78,12 +73,7 @@ namespace chaiscript { static Boxed_Value handle(const std::shared_ptr> &f) { return Boxed_Value( - std::shared_ptr( - new Assignable_Proxy_Function_Impl( - std::ref(*f), - f - ) - ) + chaiscript::make_shared>(std::ref(*f),f) ); } }; @@ -93,13 +83,8 @@ namespace chaiscript { static Boxed_Value handle(const std::shared_ptr> &f) { return Boxed_Value( - std::shared_ptr( - new Assignable_Proxy_Function_Impl( - std::ref(*f), - f - ) - ) - ); + chaiscript::make_shared>(std::ref(*f),f) + ); } }; @@ -108,13 +93,8 @@ namespace chaiscript { static Boxed_Value handle(const std::shared_ptr> &f) { return Boxed_Value( - std::shared_ptr( - new Assignable_Proxy_Function_Impl( - std::ref(*f), - f - ) - ) - ); + chaiscript::make_shared>(std::ref(*f),f) + ); } }; @@ -123,20 +103,14 @@ namespace chaiscript { static Boxed_Value handle(std::function &f) { return Boxed_Value( - std::shared_ptr( - new Assignable_Proxy_Function_Impl( - std::ref(f), - std::shared_ptr>() - ) - ) - ); + chaiscript::make_shared>(std::ref(f), + std::shared_ptr>()) + ); } static Boxed_Value handle(const std::function &f) { return Boxed_Value( - std::shared_ptr( - new dispatch::Proxy_Function_Impl(f) - ) + chaiscript::make_shared>>(f) ); } }; diff --git a/include/chaiscript/dispatchkit/proxy_constructors.hpp b/include/chaiscript/dispatchkit/proxy_constructors.hpp index 2866d97f..063c5579 100644 --- a/include/chaiscript/dispatchkit/proxy_constructors.hpp +++ b/include/chaiscript/dispatchkit/proxy_constructors.hpp @@ -16,21 +16,14 @@ namespace chaiscript { namespace detail { - /** - * A constructor function, used for creating a new object - * of a given type with a given set of params - */ - template - std::shared_ptr constructor_(Params ... params) - { - return std::make_shared(params...); - } template Proxy_Function build_constructor_(Class (*)(Params...)) { - typedef std::shared_ptr (sig)(Params...); - return Proxy_Function(static_cast(new Proxy_Function_Impl(std::function(&(constructor_))))); + auto call = dispatch::detail::Constructor(); + + return Proxy_Function( + chaiscript::make_shared (Params...), decltype(call)>>(call)); } } } diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 39011cab..1eee0602 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "../chaiscript_defines.hpp" #include "boxed_cast.hpp" @@ -148,7 +149,11 @@ namespace chaiscript Boxed_Value operator()(const std::vector ¶ms, const chaiscript::Type_Conversions &t_conversions) const { - return do_call(params, t_conversions); + if (m_arity < 0 || size_t(m_arity) == params.size()) { + return do_call(params, t_conversions); + } else { + throw exception::arity_error(static_cast(params.size()), m_arity); + } } /// Returns a vector containing all of the types of the parameters the function returns/takes @@ -183,10 +188,10 @@ namespace chaiscript if (m_arity == 0) { return true; - } else if (m_arity > 1 && m_types.size() > 1) { - return compare_first_type(vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions); + } else if (m_arity > 1) { + return compare_type_to_param(m_types[1], vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions); } else { - return compare_first_type(vals[0], t_conversions); + return compare_type_to_param(m_types[1], vals[0], t_conversions); } } else { return false; @@ -301,7 +306,6 @@ namespace chaiscript { public: Dynamic_Proxy_Function( - std::function &)> t_f, int t_arity=-1, AST_NodePtr t_parsenode = AST_NodePtr(), Param_Types t_param_types = Param_Types(), @@ -309,8 +313,7 @@ namespace chaiscript Proxy_Function t_guard = Proxy_Function()) : Proxy_Function_Base(build_param_type_list(t_param_types), t_arity), m_param_types(std::move(t_param_types)), - m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description)), - m_f(std::move(t_f)) + m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description)) { } @@ -349,24 +352,8 @@ namespace chaiscript return m_description; } + protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE - { - if (m_arity < 0 || params.size() == size_t(m_arity)) - { - if (call_match(params, t_conversions) && test_guard(params, t_conversions)) - { - return m_f(params); - } else { - throw exception::guard_error(); - } - - } else { - throw exception::arity_error(static_cast(params.size()), m_arity); - } - } - - private: bool test_guard(const std::vector ¶ms, const Type_Conversions &t_conversions) const { if (m_guard) @@ -383,12 +370,11 @@ namespace chaiscript } } + private: static std::vector build_param_type_list(const Param_Types &t_types) { - std::vector types; - // For the return type - types.push_back(chaiscript::detail::Get_Type_Info::get()); + std::vector types{chaiscript::detail::Get_Type_Info::get()}; for (const auto &t : t_types.types()) { @@ -406,9 +392,58 @@ namespace chaiscript Proxy_Function m_guard; AST_NodePtr m_parsenode; std::string m_description; - std::function &)> m_f; }; + + + template + class Dynamic_Proxy_Function_Impl : public Dynamic_Proxy_Function + { + public: + Dynamic_Proxy_Function_Impl( + Callable t_f, + int t_arity=-1, + AST_NodePtr t_parsenode = AST_NodePtr(), + Param_Types t_param_types = Param_Types(), + std::string t_description = "", + Proxy_Function t_guard = Proxy_Function()) + : Dynamic_Proxy_Function( + t_arity, + std::move(t_parsenode), + std::move(t_param_types), + std::move(t_description), + std::move(t_guard) + ), + m_f(std::move(t_f)) + { + } + + virtual ~Dynamic_Proxy_Function_Impl() {} + + + protected: + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + { + if (call_match(params, t_conversions) && test_guard(params, t_conversions)) + { + return m_f(params); + } else { + throw exception::guard_error(); + } + } + + private: + + Callable m_f; + }; + + template + Proxy_Function make_dynamic_proxy_function(Callable &&c, Arg&& ... a) + { + return chaiscript::make_shared>( + std::forward(c), std::forward(a)...); + } + /// An object used by Bound_Function to represent "_" parameters /// of a binding. This allows for unbound parameters during bind. struct Placeholder_Object @@ -549,48 +584,44 @@ namespace chaiscript virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const = 0; }; - /// The standard typesafe function call implementation of Proxy_Function - /// It takes a std::function<> object and performs runtime - /// type checking of Boxed_Value parameters, in a type safe manner - template - class Proxy_Function_Impl : public Proxy_Function_Impl_Base + + + /// For any callable object + template + class Proxy_Function_Callable_Impl : public Proxy_Function_Impl_Base { public: - Proxy_Function_Impl(std::function f) + Proxy_Function_Callable_Impl(Callable f) : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast(nullptr))), - m_f(std::move(f)), m_dummy_func(nullptr) + m_f(std::move(f)) { } - virtual ~Proxy_Function_Impl() {} + virtual ~Proxy_Function_Callable_Impl() {} virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - return detail::compare_types_cast(m_dummy_func, vals, t_conversions); + return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); } virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE { - return dynamic_cast *>(&t_func) != nullptr; + return dynamic_cast *>(&t_func) != nullptr; } - std::function internal_function() const - { - return m_f; - } protected: virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - return detail::Do_Call::result_type>::go(m_f, params, t_conversions); + typedef typename detail::Function_Signature::Return_Type Return_Type; + return detail::Do_Call::template go(m_f, params, t_conversions); } - private: - std::function m_f; - Func *m_dummy_func; + Callable m_f; }; + class Assignable_Proxy_Function : public Proxy_Function_Impl_Base { public: @@ -613,17 +644,16 @@ namespace chaiscript public: Assignable_Proxy_Function_Impl(std::reference_wrapper> t_f, std::shared_ptr> t_ptr) : Assignable_Proxy_Function(detail::build_param_type_list(static_cast(nullptr))), - m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr)), m_dummy_func(nullptr) + m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr)) { assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get()); - } virtual ~Assignable_Proxy_Function_Impl() {} virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - return detail::compare_types_cast(m_dummy_func, vals, t_conversions); + return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); } virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE @@ -643,14 +673,13 @@ namespace chaiscript protected: virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - return detail::Do_Call::result_type>::go(m_f.get(), params, t_conversions); + return detail::Do_Call::result_type>::template go(m_f.get(), params, t_conversions); } private: std::reference_wrapper> m_f; std::shared_ptr> m_shared_ptr_holder; - Func *m_dummy_func; }; /// Attribute getter Proxy_Function implementation template @@ -697,19 +726,14 @@ namespace chaiscript protected: virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - if (params.size() == 1) + const Boxed_Value &bv = params[0]; + if (bv.is_const()) { - const Boxed_Value &bv = params[0]; - if (bv.is_const()) - { - const Class *o = boxed_cast(bv, &t_conversions); - return detail::Handle_Return::type>::handle(o->*m_attr); - } else { - Class *o = boxed_cast(bv, &t_conversions); - return detail::Handle_Return::type>::handle(o->*m_attr); - } + const Class *o = boxed_cast(bv, &t_conversions); + return detail::Handle_Return::type>::handle(o->*m_attr); } else { - throw exception::arity_error(static_cast(params.size()), 1); + Class *o = boxed_cast(bv, &t_conversions); + return detail::Handle_Return::type>::handle(o->*m_attr); } } @@ -755,49 +779,38 @@ namespace chaiscript bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector &plist, const Type_Conversions &t_conversions) { - if (t_func->get_arity() != static_cast(plist.size())) - { - return false; - } - const std::vector &types = t_func->get_param_types(); + if (t_func->get_arity() == -1) return false; + assert(plist.size() == types.size() - 1); - for (size_t i = 0; i < plist.size(); ++i) - { - if (Proxy_Function_Base::compare_type_to_param(types[i+1], plist[i], t_conversions) - || (types[i+1].is_arithmetic() && plist[i].get_type_info().is_arithmetic())) - { - // types continue to match - } else { - return false; - } - } - - // all types match - return true; + return std::mismatch(plist.begin(), plist.end(), + types.begin()+1, + [&](const Boxed_Value &bv, const Type_Info &ti) { + return Proxy_Function_Base::compare_type_to_param(ti, bv, t_conversions) + || (bv.get_type_info().is_arithmetic() && ti.is_arithmetic()); + } + ) == std::make_pair(plist.end(), types.end()); } - template + template Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector &plist, - const Type_Conversions &t_conversions) + const Type_Conversions &t_conversions, const Funcs &t_funcs) { - InItr orig(begin); - InItr matching_func(end); while (begin != end) { - if (types_match_except_for_arithmetic(*begin, plist, t_conversions)) + if (types_match_except_for_arithmetic(begin->second, plist, t_conversions)) { if (matching_func == end) { matching_func = begin; } else { // handle const members vs non-const member, which is not really ambiguous - const auto &mat_fun_param_types = (*matching_func)->get_param_types(); - const auto &next_fun_param_types = (*begin)->get_param_types(); + const auto &mat_fun_param_types = matching_func->second->get_param_types(); + const auto &next_fun_param_types = begin->second->get_param_types(); if (plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) { matching_func = begin; // keep the new one, the const/non-const matchup is correct @@ -805,7 +818,7 @@ namespace chaiscript // keep the old one, it has a better const/non-const matchup } else { // ambiguous function call - throw exception::dispatch_error(plist, std::vector(orig, end)); + throw exception::dispatch_error(plist, std::vector(t_funcs.begin(), t_funcs.end())); } } } @@ -816,25 +829,30 @@ namespace chaiscript if (matching_func == end) { // no appropriate function to attempt arithmetic type conversion on - throw exception::dispatch_error(plist, std::vector(orig, end)); + throw exception::dispatch_error(plist, std::vector(t_funcs.begin(), t_funcs.end())); } std::vector newplist; - const std::vector &tis = (*matching_func)->get_param_types(); + newplist.reserve(plist.size()); + + const std::vector &tis = matching_func->second->get_param_types(); + std::transform(tis.begin() + 1, tis.end(), + plist.begin(), + std::back_inserter(newplist), + [](const Type_Info &ti, const Boxed_Value ¶m) -> Boxed_Value { + if (ti.is_arithmetic() && param.get_type_info().is_arithmetic()) { + return Boxed_Number(param).get_as(ti).bv; + } else { + return param; + } + } + ); + - for (size_t i = 0; i < plist.size(); ++i) - { - if (tis[i+1].is_arithmetic() - && plist[i].get_type_info().is_arithmetic()) { - newplist.push_back(Boxed_Number(plist[i]).get_as(tis[i+1]).bv); - } else { - newplist.push_back(plist[i]); - } - } try { - return (*(*matching_func))(newplist, t_conversions); + return (*(matching_func->second))(newplist, t_conversions); } catch (const exception::bad_boxed_cast &) { //parameter failed to cast } catch (const exception::arity_error &) { @@ -843,7 +861,7 @@ namespace chaiscript //guard failed to allow the function to execute } - throw exception::dispatch_error(plist, std::vector(orig, end)); + throw exception::dispatch_error(plist, std::vector(t_funcs.begin(), t_funcs.end())); } } @@ -857,18 +875,18 @@ namespace chaiscript Boxed_Value dispatch(const Funcs &funcs, const std::vector &plist, const Type_Conversions &t_conversions) { - //std::cout << "starting dispatch: " << funcs.size() << '\n'; - std::multimap ordered_funcs; + std::vector> ordered_funcs; + ordered_funcs.reserve(funcs.size()); for (const auto &func : funcs) { - size_t numdiffs = 0; const auto arity = func->get_arity(); if (arity == -1) { - numdiffs = plist.size(); + ordered_funcs.emplace_back(plist.size(), func.get()); } else if (arity == static_cast(plist.size())) { + size_t numdiffs = 0; for (size_t i = 0; i < plist.size(); ++i) { if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info())) @@ -876,31 +894,32 @@ namespace chaiscript ++numdiffs; } } - } else { - continue; + ordered_funcs.emplace_back(numdiffs, func.get()); } - - ordered_funcs.insert(std::make_pair(numdiffs, func.get())); } - for (const auto &func : ordered_funcs ) + + for (size_t i = 0; i <= plist.size(); ++i) { - try { - if (func.first == 0 || func.second->filter(plist, t_conversions)) - { - return (*(func.second))(plist, t_conversions); + for (const auto &func : ordered_funcs ) + { + try { + if (func.first == i && func.second->filter(plist, t_conversions)) + { + return (*(func.second))(plist, t_conversions); + } + } catch (const exception::bad_boxed_cast &) { + //parameter failed to cast, try again + } catch (const exception::arity_error &) { + //invalid num params, try again + } catch (const exception::guard_error &) { + //guard failed to allow the function to execute, + //try again } - } catch (const exception::bad_boxed_cast &) { - //parameter failed to cast, try again - } catch (const exception::arity_error &) { - //invalid num params, try again - } catch (const exception::guard_error &) { - //guard failed to allow the function to execute, - //try again } } - return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions); + return detail::dispatch_with_conversions(ordered_funcs.cbegin(), ordered_funcs.cend(), plist, t_conversions, funcs); } } } diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index b90c8d63..130d3c1e 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -16,6 +16,7 @@ #include "boxed_value.hpp" #include "handle_return.hpp" #include "type_info.hpp" +#include "callable_traits.hpp" namespace chaiscript { class Type_Conversions; @@ -65,6 +66,10 @@ namespace chaiscript } +#ifdef CHAISCRIPT_GCC_4_6 + /// \todo REMOVE THIS WHEN WE DROP G++4.6 + + // Forward declaration template struct Try_Cast; @@ -97,7 +102,7 @@ namespace chaiscript template bool compare_types_cast(Ret (*)(Params...), const std::vector ¶ms, const Type_Conversions &t_conversions) - { + { try { Try_Cast::do_try(params, 0, t_conversions); } catch (const exception::bad_boxed_cast &) { @@ -111,8 +116,8 @@ namespace chaiscript struct Call_Func { - template - static Ret do_call(const std::function &f, + template + static Ret do_call(const Callable &f, const std::vector ¶ms, const Type_Conversions &t_conversions, InnerParams &&... innerparams) { return Call_Func::do_call(f, params, t_conversions, std::forward(innerparams)..., params[sizeof...(Params) - count]); @@ -126,8 +131,8 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4100) /// Disable unreferenced formal parameter warning, which only shows up in MSVC I don't think there's any way around it \todo evaluate this #endif - template - static Ret do_call(const std::function &f, + template + static Ret do_call(const Callable &f, const std::vector &, const Type_Conversions &t_conversions, InnerParams &&... innerparams) { return f(boxed_cast(std::forward(innerparams), &t_conversions)...); @@ -143,8 +148,8 @@ namespace chaiscript * if any unboxing fails the execution of the function fails and * the bad_boxed_cast is passed up to the caller. */ - template - Ret call_func(const std::function &f, + template + Ret call_func(const chaiscript::dispatch::detail::Function_Signature &, const Callable &f, const std::vector ¶ms, const Type_Conversions &t_conversions) { if (params.size() == sizeof...(Params)) @@ -155,6 +160,82 @@ namespace chaiscript throw exception::arity_error(static_cast(params.size()), sizeof...(Params)); } + + +#else + + template + struct Indexes + { + }; + + template + struct Make_Indexes + { + typedef typename Make_Indexes::indexes indexes; + }; + + template + struct Make_Indexes<0, I...> + { + typedef Indexes indexes; + }; + + + + /** + * Used by Proxy_Function_Impl to determine if it is equivalent to another + * Proxy_Function_Impl object. This function is primarily used to prevent + * registration of two functions with the exact same signatures + */ + template + bool compare_types_cast(Indexes, Ret (*)(Params...), + const std::vector ¶ms, const Type_Conversions &t_conversions) + { + try { + (void)params; (void)t_conversions; + (void)std::initializer_list{(boxed_cast(params[I], &t_conversions), 0)...}; + return true; + } catch (const exception::bad_boxed_cast &) { + return false; + } + + } + + template + bool compare_types_cast(Ret (*f)(Params...), + const std::vector ¶ms, const Type_Conversions &t_conversions) + { + typedef typename Make_Indexes::indexes indexes; + return compare_types_cast(indexes(), f, params, t_conversions); + } + + + template + Ret call_func(const chaiscript::dispatch::detail::Function_Signature &, Indexes, const Callable &f, + const std::vector ¶ms, const Type_Conversions &t_conversions) + { + (void)params; (void)t_conversions; + return f(boxed_cast(params[I], &t_conversions)...); + } + + + /** + * Used by Proxy_Function_Impl to perform typesafe execution of a function. + * The function attempts to unbox each parameter to the expected type. + * if any unboxing fails the execution of the function fails and + * the bad_boxed_cast is passed up to the caller. + */ + template + Ret call_func(const chaiscript::dispatch::detail::Function_Signature &sig, const Callable &f, + const std::vector ¶ms, const Type_Conversions &t_conversions) + { + typedef typename Make_Indexes::indexes indexes; + return call_func(sig, indexes(), f, params, t_conversions); + } + +#endif + } } @@ -170,20 +251,20 @@ namespace chaiscript template struct Do_Call { - template - static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) + template + static Boxed_Value go(const Callable &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) { - return Handle_Return::handle(call_func(fun, params, t_conversions)); + return Handle_Return::handle(call_func(Function_Signature(), fun, params, t_conversions)); } }; template<> struct Do_Call { - template - static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) + template + static Boxed_Value go(const Callable &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) { - call_func(fun, params, t_conversions); + call_func(Function_Signature(), fun, params, t_conversions); return Handle_Return::handle(); } }; diff --git a/include/chaiscript/dispatchkit/register_function.hpp b/include/chaiscript/dispatchkit/register_function.hpp index ccfdb498..598dd8b0 100644 --- a/include/chaiscript/dispatchkit/register_function.hpp +++ b/include/chaiscript/dispatchkit/register_function.hpp @@ -7,7 +7,6 @@ #ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_ #define CHAISCRIPT_REGISTER_FUNCTION_HPP_ -#include #include #include "bind_first.hpp" @@ -15,55 +14,6 @@ namespace chaiscript { - namespace dispatch - { - namespace detail - { - template - struct FunctionSignature - { - }; - - template - struct FunctionSignature > - { - typedef Sig Signature; - }; - - template - std::function to_function(Ret (*func)(Args...)) - { - return std::function(func); - } - - template - std::function to_function(Ret (Class::*func)(Args...)) - { -#ifdef CHAISCRIPT_MSVC - /// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for - /// std::function for member function pointers seems to be broken in MSVC - return std::function(std::mem_fn(func)); -#else - return std::function(func); -#endif - } - - template - std::function to_function(Ret (Class::*func)(Args...) const) - { -#if defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_LIBCPP) - /// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for - /// std::function for member function pointers seems to be broken in MSVC - return std::function([func](const Class &o, Args... args)->Ret { - return (o.*func)(std::forward(args)...); - }); -#else - return std::function(func); -#endif - } - - } - } /// \brief Creates a new Proxy_Function object from a free function, member function or data member /// \param[in] t Function / member to expose @@ -88,22 +38,39 @@ namespace chaiscript template Proxy_Function fun(const T &t) { + typedef typename dispatch::detail::Callable_Traits::Signature Signature; + return Proxy_Function( - chaiscript::make_shared::Signature>>(dispatch::detail::to_function(t))); + chaiscript::make_shared>(t)); + } + + template + Proxy_Function fun(Ret (*func)(Param...)) + { + auto fun_call = dispatch::detail::Fun_Caller(func); + + return Proxy_Function( + chaiscript::make_shared>(fun_call)); + } template - Proxy_Function fun(Ret (Class::*func)(Param...) const) + Proxy_Function fun(Ret (Class::*t_func)(Param...) const) { + auto call = dispatch::detail::Const_Caller(t_func); + return Proxy_Function( - chaiscript::make_shared::Signature>>(dispatch::detail::to_function(func))); + chaiscript::make_shared>(call)); } template - Proxy_Function fun(Ret (Class::*func)(Param...)) + Proxy_Function fun(Ret (Class::*t_func)(Param...)) { + auto call = dispatch::detail::Caller(t_func); + return Proxy_Function( - chaiscript::make_shared::Signature>>(dispatch::detail::to_function(func))); + chaiscript::make_shared>(call)); + } @@ -114,22 +81,6 @@ namespace chaiscript } - /// \brief Creates a new Proxy_Function object from a std::function object - /// \param[in] f std::function to expose to ChaiScript - /// - /// \b Example: - /// \code - /// std::function f = get_some_function(); - /// chaiscript::ChaiScript chai; - /// chai.add(fun(f), "some_function"); - /// \endcode - /// - /// \sa \ref adding_functions - template - Proxy_Function fun(const std::function &f) - { - return Proxy_Function(chaiscript::make_shared>(f)); - } /// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 72d23150..602d4d9b 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -92,6 +92,11 @@ namespace chaiscript return m_from; } + virtual bool bidir() const + { + return true; + } + virtual ~Type_Conversion_Base() {} protected: @@ -107,6 +112,62 @@ namespace chaiscript }; + template + class Static_Caster + { + public: + static Boxed_Value cast(const Boxed_Value &t_from) + { + if (t_from.get_type_info().bare_equal(chaiscript::user_type())) + { + if (t_from.is_pointer()) + { + // Dynamic cast out the contained boxed value, which we know is the type we want + if (t_from.is_const()) + { + return Boxed_Value( + [&]()->std::shared_ptr{ + if (auto data = std::static_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr))) + { + return data; + } else { + throw std::bad_cast(); + } + }() + ); + } else { + return Boxed_Value( + [&]()->std::shared_ptr{ + if (auto data = std::static_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr))) + { + return data; + } else { + throw std::bad_cast(); + } + }() + ); + } + } else { + // Pull the reference out of the contained boxed value, which we know is the type we want + if (t_from.is_const()) + { + const From &d = detail::Cast_Helper::cast(t_from, nullptr); + const To &data = static_cast(d); + return Boxed_Value(std::cref(data)); + } else { + From &d = detail::Cast_Helper::cast(t_from, nullptr); + To &data = static_cast(d); + return Boxed_Value(std::ref(data)); + } + } + } else { + throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); + } + } + + }; + + template class Dynamic_Caster { @@ -168,8 +229,10 @@ namespace chaiscript throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); } } + }; + template class Dynamic_Conversion_Impl : public Type_Conversion_Base { @@ -186,10 +249,36 @@ namespace chaiscript virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE { - return Dynamic_Caster::cast(t_derived); + return Static_Caster::cast(t_derived); } }; + template + class Static_Conversion_Impl : public Type_Conversion_Base + { + public: + Static_Conversion_Impl() + : Type_Conversion_Base(chaiscript::user_type(), chaiscript::user_type()) + { + } + + virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE + { + throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), "Unable to cast down inheritance hierarchy with non-polymorphic types"); + } + + virtual bool bidir() const CHAISCRIPT_OVERRIDE + { + return false; + } + + virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE + { + return Static_Caster::cast(t_derived); + } + }; + + template class Type_Conversion_Impl : public Type_Conversion_Base @@ -212,6 +301,12 @@ namespace chaiscript return m_func(t_from); } + virtual bool bidir() const CHAISCRIPT_OVERRIDE + { + return false; + } + + private: Callable m_func; }; @@ -242,7 +337,7 @@ namespace chaiscript Type_Conversions(const Type_Conversions &t_other) : m_mutex(), m_conversions(t_other.get_conversions()), - m_convertableTypes(), + m_convertableTypes(t_other.m_convertableTypes), m_num_types(m_conversions.size()), m_thread_cache(this), m_conversion_saves(this) @@ -288,7 +383,7 @@ namespace chaiscript const auto &types = thread_cache(); if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) { - return has_conversion(to, from) || has_conversion(from, to); + return has_conversion(to, from); } else { return false; } @@ -338,7 +433,7 @@ namespace chaiscript bool has_conversion(const Type_Info &to, const Type_Info &from) const { chaiscript::detail::threading::shared_lock l(m_mutex); - return find(to, from) != m_conversions.end(); + return find_bidir(to, from) != m_conversions.end(); } std::shared_ptr get_conversion(const Type_Info &to, const Type_Info &from) const @@ -356,6 +451,19 @@ namespace chaiscript } private: + std::set >::const_iterator find_bidir( + const Type_Info &to, const Type_Info &from) const + { + return std::find_if(m_conversions.begin(), m_conversions.end(), + [&to, &from](const std::shared_ptr &conversion) -> bool + { + return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from)) + || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from)); +; + } + ); + } + std::set >::const_iterator find( const Type_Info &to, const Type_Info &from) const { @@ -417,17 +525,26 @@ namespace chaiscript /// \endcode /// template - Type_Conversion base_class() + Type_Conversion base_class(typename std::enable_if::value && std::is_polymorphic::value>::type* = nullptr) { //Can only be used with related polymorphic types //may be expanded some day to support conversions other than child -> parent static_assert(std::is_base_of::value, "Classes are not related by inheritance"); - static_assert(std::is_polymorphic::value, "Base class must be polymorphic"); - static_assert(std::is_polymorphic::value, "Derived class must be polymorphic"); return chaiscript::make_shared>(); } + template + Type_Conversion base_class(typename std::enable_if::value || !std::is_polymorphic::value>::type* = nullptr) + { + //Can only be used with related polymorphic types + //may be expanded some day to support conversions other than child -> parent + static_assert(std::is_base_of::value, "Classes are not related by inheritance"); + + return chaiscript::make_shared>(); + } + + template Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, const Callable &t_func) @@ -458,6 +575,24 @@ namespace chaiscript return chaiscript::make_shared>(user_type(), user_type(), func); } + template + Type_Conversion vector_conversion() + { + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); + + To vec; + + for (const Boxed_Value &bv : from_vec) { + vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); + } + + return Boxed_Value(std::move(vec)); + }; + + return chaiscript::make_shared>(user_type>(), user_type(), func); + } + } diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index de61ab6f..0d5c5f38 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -62,7 +62,7 @@ namespace chaiscript CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT { - return ti.m_type_info == m_type_info + return ti.m_type_info == m_type_info || (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info); } @@ -87,7 +87,7 @@ namespace chaiscript CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; } CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; } CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; } - CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef || m_bare_type_info == nullptr; } + CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef; } CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; } std::string name() const @@ -100,7 +100,7 @@ namespace chaiscript } } - std::string bare_name() const + std::string bare_name() const { if (m_bare_type_info) { @@ -134,12 +134,14 @@ namespace chaiscript { typedef T type; - CHAISCRIPT_CONSTEXPR static Type_Info get() + static Type_Info get() { - return Type_Info(std::is_const::type>::type>::value, std::is_reference::value, std::is_pointer::value, + return Type_Info(std::is_const::type>::type>::value, + std::is_reference::value, std::is_pointer::value, std::is_void::value, - std::is_arithmetic::value && !std::is_same::type, bool>::value, - &typeid(T), + (std::is_arithmetic::value || std::is_arithmetic::type>::value) + && !std::is_same::type>::type, bool>::value, + &typeid(T), &typeid(typename Bare_Type::type)); } }; @@ -149,11 +151,11 @@ namespace chaiscript { typedef T type; - CHAISCRIPT_CONSTEXPR static Type_Info get() + static Type_Info get() { return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, std::is_void::value, - std::is_arithmetic::value && !std::is_same::type, bool>::value, + std::is_arithmetic::value && !std::is_same::type>::type, bool>::value, &typeid(std::shared_ptr ), &typeid(typename Bare_Type::type)); } @@ -164,11 +166,11 @@ namespace chaiscript { typedef T type; - CHAISCRIPT_CONSTEXPR static Type_Info get() + static Type_Info get() { return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, std::is_void::value, - std::is_arithmetic::value && !std::is_same::type, bool>::value, + std::is_arithmetic::value && !std::is_same::type>::type, bool>::value, &typeid(const std::shared_ptr &), &typeid(typename Bare_Type::type)); } @@ -179,11 +181,11 @@ namespace chaiscript { typedef T type; - CHAISCRIPT_CONSTEXPR static Type_Info get() + static Type_Info get() { return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, std::is_void::value, - std::is_arithmetic::value && !std::is_same::type, bool>::value, + std::is_arithmetic::value && !std::is_same::type>::type, bool>::value, &typeid(std::reference_wrapper ), &typeid(typename Bare_Type::type)); } @@ -194,11 +196,11 @@ namespace chaiscript { typedef T type; - CHAISCRIPT_CONSTEXPR static Type_Info get() + static Type_Info get() { return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, std::is_void::value, - std::is_arithmetic::value && !std::is_same::type, bool>::value, + std::is_arithmetic::value && !std::is_same::type>::type, bool>::value, &typeid(const std::reference_wrapper &), &typeid(typename Bare_Type::type)); } @@ -216,7 +218,7 @@ namespace chaiscript /// chaiscript::Type_Info ti = chaiscript::user_type(i); /// \endcode template - CHAISCRIPT_CONSTEXPR Type_Info user_type(const T &/*t*/) + Type_Info user_type(const T &/*t*/) { return detail::Get_Type_Info::get(); } @@ -231,7 +233,7 @@ namespace chaiscript /// chaiscript::Type_Info ti = chaiscript::user_type(); /// \endcode template - CHAISCRIPT_CONSTEXPR Type_Info user_type() + Type_Info user_type() { return detail::Get_Type_Info::get(); } diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index d2a5e6f9..3a46c96c 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -276,10 +276,13 @@ namespace chaiscript template static std::string format_location(const T &t) { - std::ostringstream oss; - oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")"; - - return oss.str(); + if (t) { + std::ostringstream oss; + oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")"; + return oss.str(); + } else { + return "(internal)"; + } } @@ -470,13 +473,13 @@ namespace chaiscript oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " << this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n'; - for (size_t j = 0; j < this->children.size(); ++j) { - oss << this->children[j]->to_string(t_prepend + " "); + for (auto & elem : this->children) { + oss << elem->to_string(t_prepend + " "); } return oss.str(); } - Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) const + Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const { try { return eval_internal(t_e); @@ -512,7 +515,7 @@ namespace chaiscript { } - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const { throw std::runtime_error("Undispatched ast_node (internal error)"); } @@ -554,21 +557,20 @@ namespace chaiscript Scope_Push_Pop(const Scope_Push_Pop &) = delete; Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete; - Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) - : m_de(t_de) + Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) + : m_ds(t_ds) { - m_de.new_scope(); + m_ds.get()->new_scope(m_ds.get().stack_holder()); } ~Scope_Push_Pop() { - m_de.pop_scope(); + m_ds.get()->pop_scope(m_ds.get().stack_holder()); } private: - - chaiscript::detail::Dispatch_Engine &m_de; + std::reference_wrapper m_ds; }; /// Creates a new function call and pops it on destruction @@ -577,31 +579,30 @@ namespace chaiscript Function_Push_Pop(const Function_Push_Pop &) = delete; Function_Push_Pop& operator=(const Function_Push_Pop &) = delete; - Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) - : m_de(t_de) + Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) + : m_ds(t_ds) { - m_de.new_function_call(); + m_ds.get()->new_function_call(m_ds.get().stack_holder()); } ~Function_Push_Pop() { - m_de.pop_function_call(); + m_ds.get()->pop_function_call(m_ds.get().stack_holder()); } void save_params(const std::vector &t_params) { - m_de.save_function_params(t_params); + m_ds.get()->save_function_params(t_params); } void save_params(std::initializer_list t_params) { - m_de.save_function_params(std::move(t_params)); + m_ds.get()->save_function_params(std::move(t_params)); } private: - - chaiscript::detail::Dispatch_Engine &m_de; + std::reference_wrapper m_ds; }; /// Creates a new scope then pops it on destruction @@ -610,21 +611,20 @@ namespace chaiscript Stack_Push_Pop(const Stack_Push_Pop &) = delete; Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete; - Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) - : m_de(t_de) + Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) + : m_ds(t_ds) { - m_de.new_stack(); + m_ds.get()->new_stack(m_ds.get().stack_holder()); } ~Stack_Push_Pop() { - m_de.pop_stack(); + m_ds.get()->pop_stack(m_ds.get().stack_holder()); } private: - - chaiscript::detail::Dispatch_Engine &m_de; + std::reference_wrapper m_ds; }; } } diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 0592ec9b..a6a604ab 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -37,14 +37,13 @@ #ifdef CHAISCRIPT_WINDOWS #define VC_EXTRA_LEAN #define WIN32_LEAN_AND_MEAN -#include +#include #endif #endif #include "../dispatchkit/exception_specification.hpp" #include "chaiscript_parser.hpp" -#include "chaiscript_prelude.chai" namespace chaiscript { @@ -356,57 +355,57 @@ namespace chaiscript add(t_lib); } - m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_system, std::ref(m_engine)), "dump_system"); - m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_object, std::ref(m_engine)), "dump_object"); - m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, std::ref(m_engine)), "is_type"); - m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, std::ref(m_engine)), "type_name"); - m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists"); - m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions"); - m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects"); - m_engine.add(chaiscript::make_shared( + m_engine.add(fun([this](){ m_engine.dump_system(); }), "dump_system"); + m_engine.add(fun([this](const Boxed_Value &t_bv){ m_engine.dump_object(t_bv); }), "dump_object"); + m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type){ return m_engine.is_type(t_bv, t_type); }), "is_type"); + m_engine.add(fun([this](const Boxed_Value &t_bv){ return m_engine.type_name(t_bv); }), "type_name"); + m_engine.add(fun([this](const std::string &t_f){ return m_engine.function_exists(t_f); }), "function_exists"); + m_engine.add(fun([this](){ return m_engine.get_function_objects(); }), "get_functions"); + m_engine.add(fun([this](){ return m_engine.get_scripting_objects(); }), "get_objects"); + + m_engine.add( + dispatch::make_dynamic_proxy_function( [this](const std::vector &t_params) { return m_engine.call_exists(t_params); - }), "call_exists"); + }) + , "call_exists"); // m_engine.add(fun &)>(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 &t_params) { return t_fun(t_params, this->m_engine.conversions()); }), "call"); - m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name"); + m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name"); - m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type, std::ref(m_engine)), "type"); - m_engine.add(fun([this](const std::string &t_type_name){ return this->m_engine.get_type(t_type_name, true); }), "type"); + m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type"); + m_engine.add(fun([this](const std::string &t_type_name){ return m_engine.get_type(t_type_name, true); }), "type"); - m_engine.add(fun &)>( + m_engine.add(fun( [=](const Type_Info &t_from, const Type_Info &t_to, const std::function &t_func) { m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func)); } ), "add_type_conversion"); - typedef std::string (ChaiScript::*load_mod_1)(const std::string&); - typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); - m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); - m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); + m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return load_module(t_module, t_file); }), "load_module"); + m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module"); - m_engine.add(fun(&ChaiScript::use, this), "use"); - m_engine.add(fun(&ChaiScript::internal_eval_file, this), "eval_file"); - m_engine.add(fun(&ChaiScript::internal_eval, this), "eval"); - m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval"); + m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use"); + m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file"); + m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval"); + m_engine.add(fun([this](const AST_NodePtr &t_ast){ return internal_eval_ast(t_ast); }), "eval"); m_engine.add(fun(&ChaiScript::version_major), "version_major"); m_engine.add(fun(&ChaiScript::version_minor), "version_minor"); m_engine.add(fun(&ChaiScript::version_patch), "version_patch"); m_engine.add(fun(&ChaiScript::version), "version"); - m_engine.add(fun(&ChaiScript::add_global_const, this), "add_global_const"); - m_engine.add(fun(&ChaiScript::add_global, this), "add_global"); + m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const"); + m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); - do_eval(ChaiScript_Prelude::chaiscript_prelude(), "standard prelude"); } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 2e8a9221..c14a156a 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -45,7 +45,8 @@ namespace chaiscript { /// 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 &t_param_names, const std::vector &t_vals, const std::map &t_locals=std::map()) { - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + chaiscript::detail::Dispatch_State state(t_ss); + chaiscript::eval::detail::Scope_Push_Pop spp(state); for (const auto &local : t_locals) { t_ss.add_object(local.first, local.second); @@ -56,7 +57,7 @@ namespace chaiscript } try { - return t_node->eval(t_ss); + return t_node->eval(state); } catch (detail::Return_Value &rv) { return std::move(rv.retval); } @@ -71,7 +72,7 @@ namespace chaiscript { } virtual ~Binary_Operator_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &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, this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)); @@ -83,7 +84,7 @@ namespace chaiscript } protected: - Boxed_Value do_oper(chaiscript::detail::Dispatch_Engine &t_ss, + Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss, Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const { try { @@ -101,11 +102,11 @@ namespace chaiscript chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); fpp.save_params({t_lhs, t_rhs}); chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); - return t_ss.call_function(t_oper_string, t_lhs, t_rhs); + return t_ss->call_function(t_oper_string, t_lhs, t_rhs); } } catch(const exception::dispatch_error &e){ - throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, t_ss); + throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss); } } @@ -119,7 +120,7 @@ namespace chaiscript AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)), m_value(std::move(t_bv)) { } virtual ~Int_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ return m_value; } @@ -134,7 +135,7 @@ namespace chaiscript AST_Node(std::move(t_ast_node_text), AST_Node_Type::Float, std::move(t_loc)), m_value(std::move(t_bv)) { } virtual ~Float_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ return m_value; } @@ -147,17 +148,17 @@ namespace chaiscript public: Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) : AST_Node(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc)), - m_value(get_value(t_ast_node_text)) + m_value(get_value(t_ast_node_text)), m_loc(0) { } virtual ~Id_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { if (!m_value.is_undef()) { return m_value; } else { try { - return t_ss.get_object(this->text); + return t_ss->get_object(this->text, m_loc); } catch (std::exception &) { throw exception::eval_error("Can not find object: " + this->text); @@ -170,21 +171,22 @@ namespace chaiscript { if (t_text == "true") { return const_var(true); - } - else if (t_text == "false") { + } else if (t_text == "false") { return const_var(false); - } - else if (t_text == "Infinity") { + } else if (t_text == "Infinity") { return const_var(std::numeric_limits::infinity()); - } - else if (t_text == "NaN") { + } else if (t_text == "NaN") { return const_var(std::numeric_limits::quiet_NaN()); + } else if (t_text == "_") { + return Boxed_Value(std::make_shared()); } else { return Boxed_Value(); } } Boxed_Value m_value; + + mutable std::atomic_uint_fast32_t m_loc; }; struct Char_AST_Node : public AST_Node { @@ -219,7 +221,7 @@ namespace chaiscript Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { } virtual ~Fun_Call_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &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); std::vector params; @@ -235,16 +237,16 @@ namespace chaiscript try { chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); - return (*t_ss.boxed_cast(fn))(params, t_ss.conversions()); + return (*t_ss->boxed_cast(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); + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss); } catch(const exception::bad_boxed_cast &){ try { - Const_Proxy_Function f = t_ss.boxed_cast(fn); + Const_Proxy_Function f = t_ss->boxed_cast(fn); // handle the case where there is only 1 function to try to call and dispatch fails on it - throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, t_ss); + throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss); } catch (const exception::bad_boxed_cast &) { throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function."); } @@ -282,29 +284,6 @@ namespace chaiscript }; - struct Fun_Lookup_AST_Node : public AST_Node { - public: - Fun_Lookup_AST_Node(const std::string &t_fun_name) - : AST_Node(t_fun_name, 0, Parse_Location("")) - { - } - - virtual ~Fun_Lookup_AST_Node() {} - - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { - try { - Boxed_Value bv = t_ss.get_object(text); - t_ss.add_object(text, bv); - std::cout << " Saved fun lookup: " << text << '\n'; - return bv; - } catch (...) { - return Boxed_Value(); - } - } - }; - - - /// Used in the context of in-string ${} evals, so that no new scope is created @@ -315,10 +294,11 @@ namespace chaiscript { assert(children.size() == 2); } virtual ~Inplace_Fun_Call_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ - std::vector params; + 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 params; + params.reserve(this->children[1]->children.size()); for (const auto &child : this->children[1]->children) { params.push_back(child->eval(t_ss)); } @@ -328,18 +308,18 @@ namespace chaiscript try { Boxed_Value bv = this->children[0]->eval(t_ss); try { - fn = t_ss.boxed_cast(bv); + fn = t_ss->boxed_cast(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()); + 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); + 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); + 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 + "'"); @@ -438,17 +418,17 @@ namespace chaiscript return retval; } - static std::pair get_arg_type(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss) + static std::pair get_arg_type(const AST_NodePtr &t_node, const chaiscript::detail::Dispatch_State &t_ss) { if (t_node->children.size() < 2) { return std::pair(); } else { - return std::pair(t_node->children[0]->text, t_ss.get_type(t_node->children[0]->text, false)); + return std::pair(t_node->children[0]->text, t_ss->get_type(t_node->children[0]->text, false)); } } - static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss) { + static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, const chaiscript::detail::Dispatch_State &t_ss) { std::vector> retval; for (const auto &child : t_node->children) @@ -470,7 +450,7 @@ namespace chaiscript Operators::Opers m_oper; virtual ~Equation_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &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); Boxed_Value rhs = this->children[2]->eval(t_ss); Boxed_Value lhs = this->children[0]->eval(t_ss); @@ -503,21 +483,21 @@ namespace chaiscript } else { if (!rhs.is_return_value()) { - rhs = t_ss.call_function("clone", rhs); + rhs = t_ss->call_function("clone", rhs); } rhs.reset_return_value(); } } try { - return t_ss.call_function(this->children[1]->text, std::move(lhs), rhs); + return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs); } 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); } } catch(const exception::dispatch_error &e){ - throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, t_ss); + throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, *t_ss); } } else if (this->children[1]->text == ":=") { @@ -529,9 +509,9 @@ namespace chaiscript } else { try { - return t_ss.call_function(this->children[1]->text, std::move(lhs), rhs); + return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs); } 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); } } @@ -544,7 +524,7 @@ namespace chaiscript Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { } virtual ~Global_Decl_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { const std::string &idname = [&]()->const std::string &{ @@ -556,7 +536,7 @@ namespace chaiscript }(); try { - return t_ss.add_global_no_throw(Boxed_Value(), idname); + return t_ss->add_global_no_throw(Boxed_Value(), idname); } catch (const exception::reserved_word_error &) { throw exception::eval_error("Reserved word used as global '" + idname + "'"); @@ -571,7 +551,7 @@ namespace chaiscript Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { } virtual ~Var_Decl_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { if (this->children[0]->identifier == AST_Node_Type::Reference) { return this->children[0]->eval(t_ss); @@ -580,7 +560,7 @@ namespace chaiscript try { Boxed_Value bv; - t_ss.add_object(idname, bv); + t_ss->add_object(idname, bv); return bv; } catch (const exception::reserved_word_error &) { @@ -605,7 +585,7 @@ namespace chaiscript Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { } virtual ~Array_Call_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &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); std::vector params{children[0]->eval(t_ss), children[1]->eval(t_ss)}; @@ -613,10 +593,10 @@ namespace chaiscript try { chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); fpp.save_params(params); - return t_ss.call_function("[]", params); + return t_ss->call_function("[]", params); } 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 ); } } @@ -646,7 +626,7 @@ namespace chaiscript children[2]->children[0]->text:children[2]->text) { } virtual ~Dot_Access_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &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); Boxed_Value retval = children[0]->eval(t_ss); @@ -664,15 +644,15 @@ namespace chaiscript try { chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); - t_ss.add_object("this", retval); - retval = t_ss.call_member(m_fun_name, std::move(params), has_function_params); + 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){ if (e.functions.empty()) { throw exception::eval_error("'" + m_fun_name + "' is not a function."); } else { - throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, t_ss); + throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, *t_ss); } } catch(detail::Return_Value &rv) { @@ -681,10 +661,10 @@ namespace chaiscript if (this->children[2]->identifier == AST_Node_Type::Array_Call) { try { - retval = t_ss.call_function("[]", retval, this->children[2]->children[1]->eval(t_ss)); + retval = t_ss->call_function("[]", retval, this->children[2]->children[1]->eval(t_ss)); } 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); } } @@ -702,7 +682,7 @@ namespace chaiscript m_value(const_var(text)) { } virtual ~Quoted_String_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE { return m_value; } @@ -723,7 +703,7 @@ namespace chaiscript m_value(const_var(char(text.at(0)))) { } virtual ~Single_Quoted_String_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ return m_value; } @@ -744,7 +724,7 @@ namespace chaiscript virtual ~Lambda_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ const auto captures = [&]()->std::map{ std::map named_captures; @@ -759,13 +739,17 @@ namespace chaiscript const auto param_types = Arg_List_AST_Node::get_arg_types(this->children[1], t_ss); const auto &lambda_node = this->children.back(); + std::reference_wrapper engine(*t_ss); - return Boxed_Value(chaiscript::make_shared( - [&t_ss, lambda_node, param_names, captures](const std::vector &t_params) - { - return detail::eval_function(t_ss, lambda_node, param_names, t_params, captures); - }, - static_cast(numparams), lambda_node, param_types)); + return Boxed_Value( + dispatch::make_dynamic_proxy_function( + [engine, lambda_node, param_names, captures](const std::vector &t_params) + { + return detail::eval_function(engine, lambda_node, param_names, t_params, captures); + }, + static_cast(numparams), lambda_node, param_types + ) + ); } private: @@ -779,7 +763,7 @@ namespace chaiscript AST_Node(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { } virtual ~Block_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); const auto num_children = children.size(); @@ -797,7 +781,7 @@ namespace chaiscript AST_Node(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc), std::move(t_children)) { } virtual ~Def_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ std::vector t_param_names; size_t numparams = 0; AST_NodePtr guardnode; @@ -822,25 +806,29 @@ namespace chaiscript } } - std::shared_ptr guard; + std::reference_wrapper engine(*t_ss); + std::shared_ptr guard; if (guardnode) { - guard = std::make_shared - ([&t_ss, guardnode, t_param_names](const std::vector &t_params) - { - return detail::eval_function(t_ss, guardnode, t_param_names, t_params); - }, static_cast(numparams), guardnode); + guard = dispatch::make_dynamic_proxy_function( + [engine, guardnode, t_param_names](const std::vector &t_params) + { + return detail::eval_function(engine, guardnode, t_param_names, t_params); + }, + static_cast(numparams), guardnode); } try { const std::string & l_function_name = this->children[0]->text; const std::string & l_annotation = this->annotation?this->annotation->text:""; const auto & func_node = this->children.back(); - t_ss.add(chaiscript::make_shared - ([&t_ss, guardnode, func_node, t_param_names](const std::vector &t_params) - { - return detail::eval_function(t_ss, func_node, t_param_names, t_params); - }, static_cast(numparams), this->children.back(), - param_types, l_annotation, guard), l_function_name); + t_ss->add( + dispatch::make_dynamic_proxy_function( + [engine, guardnode, func_node, t_param_names](const std::vector &t_params) + { + return detail::eval_function(engine, func_node, t_param_names, t_params); + }, + static_cast(numparams), this->children.back(), + param_types, l_annotation, guard), l_function_name); } catch (const exception::reserved_word_error &e) { throw exception::eval_error("Reserved word used as function name '" + e.word() + "'"); @@ -857,7 +845,7 @@ namespace chaiscript While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { } virtual ~While_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); try { @@ -883,12 +871,12 @@ namespace chaiscript Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { } virtual ~Class_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); /// \todo do this better // 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); @@ -902,7 +890,7 @@ namespace chaiscript AST_Node(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) { assert(children.size() == 3); } virtual ~Ternary_Cond_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { if (get_bool_condition(children[0]->eval(t_ss))) { return children[1]->eval(t_ss); } @@ -918,7 +906,7 @@ namespace chaiscript If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) { } virtual ~If_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ if (get_bool_condition(children[0]->eval(t_ss))) { return children[1]->eval(t_ss); @@ -951,7 +939,7 @@ namespace chaiscript { assert(children.size() == 4); } virtual ~For_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); try { @@ -983,7 +971,7 @@ namespace chaiscript Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { } virtual ~Switch_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { bool breaking = false; size_t currentCase = 1; bool hasMatched = false; @@ -997,7 +985,7 @@ namespace chaiscript 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. try { - if (hasMatched || boxed_cast(t_ss.call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) { + if (hasMatched || boxed_cast(t_ss->call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) { this->children[currentCase]->eval(t_ss); hasMatched = true; } @@ -1027,7 +1015,7 @@ namespace chaiscript { assert(children.size() == 2); /* how many children does it have? */ } virtual ~Case_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); children[1]->eval(t_ss); @@ -1042,7 +1030,7 @@ namespace chaiscript AST_Node(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children)) { assert(children.size() == 1); } virtual ~Default_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); children[0]->eval(t_ss); @@ -1057,12 +1045,17 @@ namespace chaiscript Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { } virtual ~Inline_Array_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { try { std::vector vec; if (!children.empty()) { for (const auto &child : children[0]->children) { - vec.push_back(t_ss.call_function("clone", child->eval(t_ss))); + auto obj = child->eval(t_ss); + if (!obj.is_return_value()) { + vec.push_back(t_ss->call_function("clone", obj)); + } else { + vec.push_back(std::move(obj)); + } } } return const_var(std::move(vec)); @@ -1083,19 +1076,23 @@ namespace chaiscript Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { } virtual ~Inline_Map_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ try { std::map retval; for (const auto &child : children[0]->children) { - Boxed_Value bv = t_ss.call_function("clone", child->children[1]->eval(t_ss)); - retval[t_ss.boxed_cast(child->children[0]->eval(t_ss))] = std::move(bv); + auto obj = child->children[1]->eval(t_ss); + if (!obj.is_return_value()) { + obj = t_ss->call_function("clone", obj); + } + + retval[t_ss->boxed_cast(child->children[0]->eval(t_ss))] = std::move(obj); } return const_var(std::move(retval)); } catch (const exception::dispatch_error &e) { - throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, t_ss); + throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, *t_ss); } } @@ -1106,7 +1103,7 @@ namespace chaiscript Return_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) { } virtual ~Return_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ if (!this->children.empty()) { throw detail::Return_Value(children[0]->eval(t_ss)); } @@ -1122,12 +1119,23 @@ namespace chaiscript File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { } virtual ~File_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { - const auto num_children = children.size(); - for (size_t i = 0; i < num_children-1; ++i) { - children[i]->eval(t_ss); + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { + try { + const auto num_children = children.size(); + + if (num_children > 0) { + for (size_t i = 0; i < num_children-1; ++i) { + children[i]->eval(t_ss); + } + return children.back()->eval(t_ss); + } else { + return Boxed_Value(); + } + } catch (const detail::Continue_Loop &) { + throw exception::eval_error("Unexpected `continue` statement outside of a loop"); + } catch (const detail::Break_Loop &) { + throw exception::eval_error("Unexpected `break` statement outside of a loop"); } - return children.back()->eval(t_ss); } }; @@ -1137,10 +1145,10 @@ namespace chaiscript AST_Node(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children)) { assert(children.size() == 1); } - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ try { Boxed_Value bv; - t_ss.add_object(this->children[0]->text, bv); + t_ss->add_object(this->children[0]->text, bv); return bv; } catch (const exception::reserved_word_error &) { @@ -1159,22 +1167,22 @@ namespace chaiscript { } virtual ~Prefix_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ Boxed_Value bv(children[1]->eval(t_ss)); try { // short circuit arithmetic operations - if (m_oper != Operators::invalid && bv.get_type_info().is_arithmetic()) + if (m_oper != Operators::invalid && m_oper != Operators::bitwise_and && bv.get_type_info().is_arithmetic()) { - return Boxed_Number::do_oper(m_oper, std::move(bv)); + return Boxed_Number::do_oper(m_oper, bv); } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); fpp.save_params({bv}); - return t_ss.call_function(children[0]->text, std::move(bv)); + return t_ss->call_function(children[0]->text, std::move(bv)); } } 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); } } @@ -1187,7 +1195,7 @@ namespace chaiscript Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { } virtual ~Break_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ throw detail::Break_Loop(); } }; @@ -1197,7 +1205,7 @@ namespace chaiscript Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { } virtual ~Continue_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ throw detail::Continue_Loop(); } }; @@ -1210,7 +1218,7 @@ namespace chaiscript { } virtual ~Noop_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ // It's a no-op, that evaluates to "true" return m_value; } @@ -1238,14 +1246,14 @@ namespace chaiscript Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { } virtual ~Inline_Range_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ try { - return t_ss.call_function("generate_range", + return t_ss->call_function("generate_range", children[0]->children[0]->children[0]->eval(t_ss), children[0]->children[0]->children[1]->eval(t_ss)); } 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); } } @@ -1264,7 +1272,7 @@ namespace chaiscript AST_Node(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { } virtual ~Try_AST_Node() {} - Boxed_Value handle_exception(chaiscript::detail::Dispatch_Engine &t_ss, const Boxed_Value &t_except) const + Boxed_Value handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const { Boxed_Value retval; @@ -1286,9 +1294,9 @@ namespace chaiscript if (dispatch::Param_Types( std::vector>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)} - ).match(std::vector{t_except}, t_ss.conversions())) + ).match(std::vector{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) { //Variable capture, no guards @@ -1325,7 +1333,7 @@ namespace chaiscript return retval; } - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ Boxed_Value retval; chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); @@ -1340,9 +1348,14 @@ namespace chaiscript } throw; } + catch (const std::runtime_error &e) { + retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); + } + catch (const std::out_of_range &e) { + retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); + } catch (const std::exception &e) { retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); - } catch (Boxed_Value &e) { retval = handle_exception(t_ss, e); @@ -1383,11 +1396,11 @@ namespace chaiscript Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc), std::move(t_children)) { } virtual ~Method_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ AST_NodePtr guardnode; - const auto d = t_ss.get_parent_locals(); + const auto d = t_ss->get_parent_locals(); const auto itr = d.find("_current_class_name"); const auto class_offset = (itr != d.end())?-1:0; const std::string & class_name = (itr != d.end())?std::string(boxed_cast(itr->second)):this->children[0]->text; @@ -1415,39 +1428,48 @@ namespace chaiscript const size_t numparams = t_param_names.size(); - std::shared_ptr guard; + std::shared_ptr guard; + std::reference_wrapper engine(*t_ss); if (guardnode) { - guard = std::make_shared - (std::bind(chaiscript::eval::detail::eval_function, - std::ref(t_ss), guardnode, - t_param_names, std::placeholders::_1, std::map()), static_cast(numparams), guardnode); + guard = dispatch::make_dynamic_proxy_function( + [engine, t_param_names, guardnode](const std::vector &t_params) { + return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params, std::map()); + }, + static_cast(numparams), guardnode); } try { const std::string & l_annotation = annotation?annotation->text:""; - const std::string & function_name = children[static_cast(1 + class_offset)]->text; + auto node = children.back(); if (function_name == class_name) { param_types.push_front(class_name, Type_Info()); - t_ss.add(std::make_shared(class_name, std::make_shared(std::bind(chaiscript::eval::detail::eval_function, - std::ref(t_ss), children.back(), t_param_names, std::placeholders::_1, std::map()), - static_cast(numparams), children.back(), param_types, l_annotation, guard)), + + t_ss->add( + std::make_shared(class_name, + dispatch::make_dynamic_proxy_function( + [engine, t_param_names, node](const std::vector &t_params) { + return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map()); + }, + static_cast(numparams), node, param_types, l_annotation, guard + ) + ), function_name); } else { - // if the type is unknown, then this generates a function that looks up the type // at runtime. Defining the type first before this is called is better - auto type = t_ss.get_type(class_name, false); + auto type = t_ss->get_type(class_name, false); param_types.push_front(class_name, type); - t_ss.add( - std::make_shared(class_name, - std::make_shared(std::bind(chaiscript::eval::detail::eval_function, - std::ref(t_ss), children.back(), - t_param_names, std::placeholders::_1, std::map()), static_cast(numparams), children.back(), - param_types, l_annotation, guard), type), function_name); + t_ss->add(std::make_shared(class_name, + dispatch::make_dynamic_proxy_function( + [engine, t_param_names, node](const std::vector &t_params) { + return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map()); + }, + static_cast(numparams), node, param_types, l_annotation, guard), type), + function_name); } } catch (const exception::reserved_word_error &e) { @@ -1465,23 +1487,22 @@ namespace chaiscript Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : AST_Node(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { } virtual ~Attr_Decl_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE { - const auto &d = t_ss.get_parent_locals(); + const auto &d = t_ss->get_parent_locals(); const auto itr = d.find("_current_class_name"); const auto class_offset = (itr != d.end())?-1:0; std::string class_name = (itr != d.end())?std::string(boxed_cast(itr->second)):this->children[0]->text; try { - t_ss.add( + std::string attr_name = this->children[static_cast(1 + class_offset)]->text; + + t_ss->add( std::make_shared( std::move(class_name), - fun(std::function( - std::bind(static_cast(&dispatch::Dynamic_Object::get_attr), - std::placeholders::_1, - this->children[static_cast(1 + class_offset)]->text - )) - ), + fun([attr_name](dispatch::Dynamic_Object &t_obj) { + return t_obj.get_attr(attr_name); + }), true ), this->children[static_cast(1 + class_offset)]->text); @@ -1505,7 +1526,7 @@ namespace chaiscript { assert(children.size() == 3); } virtual ~Logical_And_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ return const_var(get_bool_condition(children[0]->eval(t_ss)) && get_bool_condition(children[2]->eval(t_ss))); } @@ -1522,7 +1543,7 @@ namespace chaiscript AST_Node(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children)) { assert(children.size() == 3); } virtual ~Logical_Or_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ return const_var(get_bool_condition(children[0]->eval(t_ss)) || get_bool_condition(children[2]->eval(t_ss))); } diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 59367139..ddc484fb 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -7,8 +7,6 @@ #ifndef CHAISCRIPT_PARSER_HPP_ #define CHAISCRIPT_PARSER_HPP_ -#include -#include #include #include #include @@ -16,6 +14,8 @@ #include #include #include +#include + #include "../dispatchkit/boxed_value.hpp" #include "chaiscript_common.hpp" @@ -67,6 +67,7 @@ namespace chaiscript m_multiline_comment_end("*/"), m_singleline_comment("//") { + m_match_stack.reserve(2); setup_operators(); } @@ -193,6 +194,7 @@ namespace chaiscript /// Returns the front-most AST node AST_NodePtr ast() const { + if (m_match_stack.empty()) throw exception::eval_error("Attempted to access AST of failed parse."); return m_match_stack.front(); } @@ -215,28 +217,6 @@ namespace chaiscript } - static void optimize_fun_lookups(AST_NodePtr &p) - { - for (auto &c : p->children) - { - - if (c->identifier == AST_Node_Type::Def - || c->identifier == AST_Node_Type::Method - || c->identifier == AST_Node_Type::Lambda) { - std::vector children_to_add; - auto counts = count_fun_calls(c, false); - for (const auto &count : counts) { - // std::cout << " Fun Call Count: " << count.first << " " << count.second << '\n'; - if (count.second > 1) { - children_to_add.push_back(chaiscript::make_shared(count.first)); - } - } - c->children.back()->children.insert(c->children.back()->children.begin(), children_to_add.begin(), children_to_add.end()); - } - optimize_fun_lookups(c); - } - } - static void optimize_blocks(AST_NodePtr &p) { @@ -281,12 +261,11 @@ namespace chaiscript return count; } - AST_NodePtr optimized_ast(bool t_optimize_blocks = false, bool t_optimize_returns = true, bool t_optimize_fun_lookups = false) { - AST_NodePtr p = m_match_stack.front(); + AST_NodePtr optimized_ast(bool t_optimize_blocks = false, bool t_optimize_returns = true) { + AST_NodePtr p = ast(); //Note, optimize_blocks is currently broken; it breaks stack management if (t_optimize_blocks) { optimize_blocks(p); } if (t_optimize_returns) { optimize_returns(p); } - if (t_optimize_fun_lookups) { optimize_fun_lookups(p); } return p; } @@ -1230,37 +1209,32 @@ namespace chaiscript } /// Reads an end-of-line group from input, without skipping initial whitespace - bool Eol_() { + bool Eol_(const bool t_eos = false) { bool retval = false; if (has_more_input() && (Symbol_("\r\n") || Char_('\n'))) { retval = true; ++m_line; m_col = 1; - } else if (has_more_input() && Char_(';')) { + } else if (has_more_input() && !t_eos && Char_(';')) { retval = true; } return retval; } - /// Reads (and potentially captures) an end-of-line group from input - bool Eol(const bool t_capture = false) { + /// Reads until the end of the current statement + bool Eos() { SkipWS(); - if (!t_capture) { - return Eol_(); - } else { - const auto start = m_input_pos; - const auto prev_col = m_col; - const auto prev_line = m_line; - if (Eol_()) { - m_match_stack.push_back(make_node(std::string(start, m_input_pos), prev_line, prev_col)); - return true; - } else { - return false; - } - } + return Eol_(true); + } + + /// Reads (and potentially captures) an end-of-line group from input + bool Eol() { + SkipWS(); + + return Eol_(); } /// Reads a comma-separated list of values from input. Id's only, no types allowed @@ -1463,7 +1437,7 @@ namespace chaiscript } } - while (Eol()) {} + while (Eos()) {} if (Char(':')) { if (!Operator()) { diff --git a/include/chaiscript/language/chaiscript_prelude.chai b/include/chaiscript/language/chaiscript_prelude.chai index 88835c5f..0fe2a5a6 100644 --- a/include/chaiscript/language/chaiscript_prelude.chai +++ b/include/chaiscript/language/chaiscript_prelude.chai @@ -127,18 +127,6 @@ def even(x) } -# Pushes the second value onto the container first value while making a clone of the value -def push_back(container, x) : call_exists(push_back_ref, container, x) -{ - container.push_back_ref(clone(x)) -} - -# Pushes the second value onto the front of the container first value while making a clone of the value -def push_front(container, x) : call_exists(push_front_ref, container, x) -{ - container.push_front_ref(clone(x)) -} - # Inserts the third value at the position of the second value into the container of the first # while making a clone. def insert_at(container, pos, x) diff --git a/include/chaiscript/language/chaiscript_prelude_docs.hpp b/include/chaiscript/language/chaiscript_prelude_docs.hpp index 7480858c..25d32d10 100644 --- a/include/chaiscript/language/chaiscript_prelude_docs.hpp +++ b/include/chaiscript/language/chaiscript_prelude_docs.hpp @@ -718,14 +718,14 @@ Object drop_while(Range c, Function f); Object reduce(Range c, Function f); -/// \brief Takes elements from Range c that match function f, return them. +/// \brief Takes elements from Container c that match function f, return them. /// /// Example: /// \code /// eval> filter([1, 2, 3, 4], odd) /// [1, 3] /// \endcode -Object filter(Range c, Function f); +Object filter(Container c, Function f); /// \brief Joins the elements of the Range c into a string, delimiting each with the delim string. diff --git a/readme.md b/readme.md index f4446e7e..75e470a9 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,11 @@ -Master Status: [![Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript) [![Coverage Status](https://coveralls.io/repos/ChaiScript/ChaiScript/badge.png?branch=master)](https://coveralls.io/r/ChaiScript/ChaiScript?branch=master) +Master Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=master)](http://codecov.io/github/ChaiScript/ChaiScript?branch=master) -Develop Status: [![Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=develop)](https://travis-ci.org/ChaiScript/ChaiScript) [![Coverage Status](https://coveralls.io/repos/ChaiScript/ChaiScript/badge.png?branch=develop)](https://coveralls.io/r/ChaiScript/ChaiScript?branch=develop) +Develop Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=develop)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw/branch/develop?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript/branch/develop) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=develop)](http://codecov.io/github/ChaiScript/ChaiScript?branch=develop) + + Coverity Scan Build Status + ChaiScript diff --git a/releasenotes.md b/releasenotes.md index 854b74c1..c78376d8 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,6 +1,33 @@ Notes: ======= -Current Version: 5.7.0 +Current Version: 5.7.1 + +### Changes since 5.7.0 +* Build time reduction +* Build size reduction +* Performance increases +* Fixed ~20 crash-bugs found with fuzzy testing #194 + * Let unhandled exceptions propogate to user + * Report eval_error when break statement is not in loop + * Fix handling of 0 length scripts closes #193 + * Don't crash on arity mismatch - Specifically affects the case where no overloads exist for a given function + * Fix error printing for `bind` calls + * Handle unexpected continue statement + * Check arity during bind + * Don't allow arith conversion on variadic function + * Correct `bind` parameter match count + * Add in expected Boxed_Value exception cases + * Check access to AST, don't allow `;` in func def + * Don't attempt arithmetic unary & call + * Don't crash on 0 param call to `bind` + * Catch errors during member function dispatch + * Properly handle type of const bool & +* Automatic deduction of lambda type signatures +* Work with non-polymorphic parent/child conversions +* Move to codecov for coverage reporting +* Add `.at` method for Map objects +* Various corrections for support of move-only objects + ### Changes since 5.6.0 diff --git a/src/main.cpp b/src/main.cpp index 3a72df1b..372adf74 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -297,6 +297,8 @@ int main(int argc, char *argv[]) chai.add(chaiscript::fun(&get_eval_error), "get_eval_error"); chai.add(chaiscript::fun(&now), "now"); + bool eval_error_ok = false; + bool boxed_exception_ok = false; for (int i = 0; i < argc; ++i) { if ( i == 0 && argc > 1 ) { @@ -324,9 +326,15 @@ int main(int argc, char *argv[]) arg += line + '\n' ; } } else if ( arg == "-v" || arg == "--version" ) { - arg = "version()" ; + arg = "print(version())" ; } else if ( arg == "-h" || arg == "--help" ) { arg = "help(-1)"; + } else if ( arg == "-e" || arg == "--evalerrorok" ) { + eval_error_ok = true; + continue; + } else if ( arg == "--exception" ) { + boxed_exception_ok = true; + continue; } else if ( arg == "-i" || arg == "--interactive" ) { mode = eInteractive ; } else if ( arg.find('-') == 0 ) { @@ -352,12 +360,23 @@ int main(int argc, char *argv[]) catch (const chaiscript::exception::eval_error &ee) { std::cout << ee.pretty_print(); std::cout << '\n'; - return EXIT_FAILURE; + + if (!eval_error_ok) { + return EXIT_FAILURE; + } } - catch (std::exception &e) { - std::cout << e.what() << '\n'; - return EXIT_FAILURE; + catch (const chaiscript::Boxed_Value &e) { + std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n'; + + if (!boxed_exception_ok) { + return EXIT_FAILURE; + } } + +// catch (std::exception &e) { +// std::cout << e.what() << '\n'; +// return EXIT_FAILURE; +// } } return EXIT_SUCCESS; diff --git a/src/stl_extra.cpp b/src/stl_extra.cpp index 6f0c5e48..e391b180 100644 --- a/src/stl_extra.cpp +++ b/src/stl_extra.cpp @@ -23,7 +23,11 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra() { - return chaiscript::bootstrap::standard_library::list_type >("List"); + + auto module = chaiscript::bootstrap::standard_library::list_type >("List"); + module->add(chaiscript::bootstrap::standard_library::vector_type >("u16vector")); + module->add(chaiscript::vector_conversion>()); + return module; } #ifdef __llvm__ diff --git a/src/test_module.cpp b/src/test_module.cpp index c5da4c96..ebccf736 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -34,6 +34,11 @@ class TestBaseType int mdarray[2][3][5]; std::function func_member; + void set_string_val(std::string &t_str) + { + t_str = "42"; + } + private: TestBaseType &operator=(const TestBaseType &) = delete; }; @@ -52,6 +57,7 @@ class Type2 return m_bt.val; } + const char *get_str() const { return m_str.c_str(); @@ -171,6 +177,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::fun(&TestBaseType::val), "val"); m->add(chaiscript::fun(&TestBaseType::const_val), "const_val"); m->add(chaiscript::fun(&TestBaseType::base_only_func), "base_only_func"); + m->add(chaiscript::fun(&TestBaseType::set_string_val), "set_string_val"); #ifndef CHAISCRIPT_MSVC_12 // we cannot support these in MSVC_12 because of a bug in the implementation of diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index dbed26fd..c856e9aa 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -37,8 +37,7 @@ TEST_CASE("C++11 Lambdas Can Be Registered") // in an std::function or provide the signature chaiscript::ChaiScript chai; - // provide the signature - chai.add(chaiscript::fun([] { return "hello"; } ), "f1"); + chai.add(chaiscript::fun([]()->std::string { return "hello"; } ), "f1"); // wrap chai.add(chaiscript::fun(std::function([] { return "world"; } )), "f2"); @@ -723,3 +722,24 @@ TEST_CASE("Object lifetime test 2") CHECK(_script.eval("to_string(test2.x)") == "10"); } + + + + +///// Non-polymorphic base class conversions +class Non_Poly_Base {}; +class Non_Poly_Derived : public Non_Poly_Base {}; +int myfunction(Non_Poly_Base *) +{ + return 2; +} + +TEST_CASE("Test Derived->Base with non-polymorphic classes") +{ + chaiscript::ChaiScript chai; + chai.add(chaiscript::base_class()); + Non_Poly_Derived d; + chai.add(chaiscript::var(&d), "d"); + chai.add(chaiscript::fun(&myfunction), "myfunction"); + CHECK(chai.eval("myfunction(d)") == 2); +} diff --git a/unittests/fuzzy_tests-2015-07-16.tar.bz2 b/unittests/fuzzy_tests-2015-07-16.tar.bz2 new file mode 100644 index 00000000..d150daae Binary files /dev/null and b/unittests/fuzzy_tests-2015-07-16.tar.bz2 differ diff --git a/unittests/map_access.chai b/unittests/map_access.chai index d544036d..1b2d73f1 100644 --- a/unittests/map_access.chai +++ b/unittests/map_access.chai @@ -1,2 +1,19 @@ auto x = ["bob":2, "fred":3] assert_equal(3, x["fred"]) + + +try { + auto m = ["bob":2, "fred":3]; + m.at("tom"); + assert_true(false); +} catch (out_of_range e) { + print("out_of_range") + assert_true(true); +} catch (e) { + print("other") + dump_object(e); + assert_true(false); +} + + +assert_equal(["bob":2, "fred":3].at("fred"), 3); diff --git a/unittests/non_const_param.chai b/unittests/non_const_param.chai new file mode 100644 index 00000000..fa385db7 --- /dev/null +++ b/unittests/non_const_param.chai @@ -0,0 +1,8 @@ +load_module("test_module") + +var t2 = TestBaseType(); + +var s = "5"; +t2.set_string_val(s); +assert_equal(s, "42") + diff --git a/unittests/type_info_test.cpp b/unittests/type_info_test.cpp index 5e165814..9b9fd92a 100644 --- a/unittests/type_info_test.cpp +++ b/unittests/type_info_test.cpp @@ -5,33 +5,58 @@ #include #include -void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void, - bool t_is_undef) +#ifdef CHAISCRIPT_MSVC +#pragma warning(push) +#pragma warning(disable : 4190 4640 28251 4702 6330) +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#endif + +#ifdef __llvm__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wfloat-equal" +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + + + + +#define CATCH_CONFIG_MAIN + +#include "catch.hpp" + + +TEST_CASE("Type_Info objects generate expected results") { - if (ti.is_const() == t_is_const - && ti.is_pointer() == t_is_pointer - && ti.is_reference() == t_is_reference - && ti.is_void() == t_is_void - && ti.is_undef() == t_is_undef) + const auto test_type = [](const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void, + bool t_is_undef, bool t_is_arithmetic) { - return; - } else { - exit(EXIT_FAILURE); - } -} + CHECK(ti.is_const() == t_is_const); + CHECK(ti.is_pointer() == t_is_pointer); + CHECK(ti.is_reference() == t_is_reference); + CHECK(ti.is_void() == t_is_void); + CHECK(ti.is_undef() == t_is_undef); + CHECK(ti.is_arithmetic() == t_is_arithmetic); + }; - -int main() -{ - test_type(chaiscript::user_type(), false, false, false, true, false); - test_type(chaiscript::user_type(), true, false, false, false, false); - test_type(chaiscript::user_type(), true, false, true, false, false); - test_type(chaiscript::user_type(), false, false, false, false, false); - test_type(chaiscript::user_type(), false, true, false, false, false); - test_type(chaiscript::user_type(), true, true, false, false, false); - test_type(chaiscript::Type_Info(), false, false, false, false, true); + SECTION("void") { test_type(chaiscript::user_type(), false, false, false, true, false, false); } + SECTION("const int") { test_type(chaiscript::user_type(), true, false, false, false, false, true); } + SECTION("const int &") { test_type(chaiscript::user_type(), true, false, true, false, false, true); } + SECTION("int") { test_type(chaiscript::user_type(), false, false, false, false, false, true); } + SECTION("int *") { test_type(chaiscript::user_type(), false, true, false, false, false, false); } + SECTION("const int *") { test_type(chaiscript::user_type(), true, true, false, false, false, false); } + SECTION("const bool &") { test_type(chaiscript::user_type(), true, false, true, false, false, false); } + SECTION("default") { test_type(chaiscript::Type_Info(), false, false, false, false, true, false); } std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << '\n'; - - return EXIT_SUCCESS; } + + + diff --git a/unittests/vector_push_back.chai b/unittests/vector_push_back.chai index 82ba4b44..eea34b78 100644 --- a/unittests/vector_push_back.chai +++ b/unittests/vector_push_back.chai @@ -3,3 +3,11 @@ x.push_back(3) assert_equal(3, x.size()) assert_equal(3, x.back()) assert_equal(1, x.front()) + + +load_module("stl_extra") + +auto uint16v = u16vector(); +uint16v.push_back(1u); +assert_equal(1, uint16v.front()); +