diff --git a/.decent_ci-Linux.yaml b/.decent_ci-Linux.yaml new file mode 100644 index 0000000..a2d597f --- /dev/null +++ b/.decent_ci-Linux.yaml @@ -0,0 +1,13 @@ +compilers: + - name: "clang" + version: "3.5" + cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON + - name: "gcc" + version: "4.8" + cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON + - name: "gcc" + version: "4.6" + cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON + - name: cppcheck + compiler_extra_flags: --enable=all -I include --inline-suppr + diff --git a/.decent_ci-MacOS.yaml b/.decent_ci-MacOS.yaml new file mode 100644 index 0000000..b68ed8e --- /dev/null +++ b/.decent_ci-MacOS.yaml @@ -0,0 +1,7 @@ +compilers: + - name: clang + cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA + - name: clang + build_type: Debug + cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA + diff --git a/.decent_ci-Windows.yaml b/.decent_ci-Windows.yaml new file mode 100644 index 0000000..1f6c033 --- /dev/null +++ b/.decent_ci-Windows.yaml @@ -0,0 +1,20 @@ +compilers: + - name: Visual Studio + version: 14 + cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA% + compiler_extra_flags: /ANALYZE + - name: Visual Studio + version: 14 + architecture: Win64 + cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA% + compiler_extra_flags: /ANALYZE + - name: Visual Studio + version: 12 + cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA% + compiler_extra_flags: /ANALYZE + - name: Visual Studio + version: 12 + architecture: Win64 + cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA% + compiler_extra_flags: /ANALYZE + diff --git a/.decent_ci.yaml b/.decent_ci.yaml new file mode 100644 index 0000000..e917c17 --- /dev/null +++ b/.decent_ci.yaml @@ -0,0 +1,4 @@ +results_repository : ChaiScript/ChaiScript-BuildResults +results_path : _posts +results_base_url : https://chaiscript.github.io/ChaiScript-BuildResults +aging_pull_requests_notification: true diff --git a/CMakeLists.txt b/CMakeLists.txt index cefe9ec..be2bb2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,11 +36,38 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address") endif() + option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE) + if(ENABLE_MEMORY_SANITIZER) + add_definitions(-fsanitize=memory -g) + set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory") + endif() + option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE) if(ENABLE_UNDEFINED_SANITIZER) add_definitions(-fsanitize=undefined -g) set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined") endif() + + option(ENABLE_LTO "Enable Link Time Optimization" FALSE) + + if (ENABLE_LTO) + add_definitions(-flto) + set(LINKER_FLAGS "${LINKER_FLAGS} -flto") + endif() + + option(PROFILE_GENERATE "Generate profile data" FALSE) + if (PROFILE_GENERATE) + add_definitions(-fprofile-generate) + set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate") + endif() + + option(PROFILE_USE "Use profile data" FALSE) + if (PROFILE_USE) + add_definitions(-fprofile-use) + set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use") + endif() + + endif() list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}") @@ -54,7 +81,7 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") set(CPACK_PACKAGE_VERSION_MAJOR 5) -set(CPACK_PACKAGE_VERSION_MINOR 4) +set(CPACK_PACKAGE_VERSION_MINOR 5) set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") @@ -154,7 +181,7 @@ endif() include_directories(include) -set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) +set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) @@ -203,6 +230,8 @@ if(BUILD_SAMPLES) target_link_libraries(example ${LIBS}) add_executable(memory_leak_test samples/memory_leak_test.cpp) target_link_libraries(memory_leak_test ${LIBS}) + add_executable(inheritance samples/inheritance.cpp) + target_link_libraries(inheritance ${LIBS}) endif() diff --git a/contrib/codeanalysis/runcppcheck.sh b/contrib/codeanalysis/runcppcheck.sh index 5e79737..54e9a82 100755 --- a/contrib/codeanalysis/runcppcheck.sh +++ b/contrib/codeanalysis/runcppcheck.sh @@ -4,9 +4,9 @@ pushd .. wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2 tar -xvf cppcheck-1.66.tar.bz2 cd cppcheck-1.66 -make -j2 +CXX=g++-4.8 make -j2 popd -../cppcheck-1.65/cppcheck --enable=all -I include --inline-suppr --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output +../cppcheck-1.66/cppcheck --enable=all -I include --inline-suppr --suppress=missingIncludeSystem --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output echo -n '{ "body": " ' > output.json echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index d541365..4acabcf 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -75,7 +75,7 @@ /// /// @subsection compiling Compiling ChaiScript Applications /// -/// ChaiScript is a header only library with only one dependecy: The +/// ChaiScript is a header only library with only one dependency: The /// operating system provided dynamic library loader, which has to be specified on some platforms. /// /// @subsubsection compilinggcc Compiling with GCC @@ -112,7 +112,7 @@ /// /// @subsubsection evalmethod Method 'eval' /// -/// The eval method is somewhat more verbose and can be used to get typesafely return values +/// The eval method is somewhat more verbose and can be used to get type safely return values /// from the script. /// /// ~~~~~~~~{.cpp} @@ -311,7 +311,7 @@ /// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr, /// std::shared_ptr, std::reference_wrapper, std::reference_wrapper and value types automatically. /// -/// If a chaiscript::var object was created in C++ from a pointer, it cannot be convered to a shared_ptr (this would add invalid reference counting). +/// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference counting). /// Const may be added, but never removed. /// /// The take away is that you can pretty much expect function calls to Just Work when you need them to. diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 59e302e..d441224 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -45,7 +45,7 @@ namespace chaiscript { static const int version_major = 5; - static const int version_minor = 4; + static const int version_minor = 5; static const int version_patch = 0; } diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index ce76175..7c403b7 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -28,7 +28,7 @@ namespace chaiscript { virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {} - /// \brief Description of what error occured + /// \brief Description of what error occurred virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE { return m_what.c_str(); @@ -52,6 +52,7 @@ namespace chaiscript { Data &operator=(const Data &) = delete; virtual ~Data() {} + virtual void *data() = 0; const std::type_info &type() const { @@ -65,7 +66,7 @@ namespace chaiscript { template struct Data_Impl : Data { - Data_Impl(T t_type) + explicit Data_Impl(T t_type) : Data(typeid(T)), m_data(std::move(t_type)) { @@ -104,12 +105,19 @@ namespace chaiscript { } } - template - Any(const ValueType &t_value) - : m_data(std::unique_ptr(new Data_Impl(t_value))) +#if _MSC_VER != 1800 + Any(Any &&) = default; + Any &operator=(Any &&t_any) = default; +#endif + + template::type>::value>::type> + explicit Any(ValueType &&t_value) + : m_data(std::unique_ptr(new Data_Impl::type>(std::forward(t_value)))) { } + Any & operator=(const Any &t_any) { Any copy(t_any); @@ -117,13 +125,6 @@ namespace chaiscript { return *this; } - template - Any & operator=(const ValueType &t_value) - { - m_data = std::unique_ptr(new Data_Impl(t_value)); - return *this; - } - template ToType &cast() const { diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index 3040b71..648eb41 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -10,6 +10,7 @@ #include #include +#include "../chaiscript_defines.hpp" #include "type_info.hpp" namespace chaiscript { @@ -28,14 +29,14 @@ namespace chaiscript class bad_boxed_cast : public std::bad_cast { public: - bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to, + bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, std::string t_what) CHAISCRIPT_NOEXCEPT - : from(t_from), to(&t_to), m_what(std::move(t_what)) + : from(std::move(t_from)), to(&t_to), m_what(std::move(t_what)) { } - bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT - : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast") + 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") { } @@ -46,7 +47,7 @@ namespace chaiscript virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {} - /// \brief Description of what error occured + /// \brief Description of what error occurred virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE { return m_what.c_str(); diff --git a/include/chaiscript/dispatchkit/bind_first.hpp b/include/chaiscript/dispatchkit/bind_first.hpp index 16f95b0..6a3adda 100644 --- a/include/chaiscript/dispatchkit/bind_first.hpp +++ b/include/chaiscript/dispatchkit/bind_first.hpp @@ -14,79 +14,20 @@ namespace chaiscript namespace detail { - template - struct Placeholder - { - }; - - template<> - struct Placeholder<1> - { - static decltype(std::placeholders::_1) value() { return std::placeholders::_1; } - }; - - template<> - struct Placeholder<2> - { - static decltype(std::placeholders::_2) value() { return std::placeholders::_2; } - }; - - template<> - struct Placeholder<3> - { - static decltype(std::placeholders::_3) value() { return std::placeholders::_3; } - }; - - template<> - struct Placeholder<4> - { - static decltype(std::placeholders::_4) value() { return std::placeholders::_4; } - }; - - template<> - struct Placeholder<5> - { - static decltype(std::placeholders::_5) value() { return std::placeholders::_5; } - }; - - template<> - struct Placeholder<6> - { - static decltype(std::placeholders::_6) value() { return std::placeholders::_6; } - }; - - template<> - struct Placeholder<7> - { - static decltype(std::placeholders::_7) value() { return std::placeholders::_7; } - }; - - template<> - struct Placeholder<8> - { - static decltype(std::placeholders::_8) value() { return std::placeholders::_8; } - }; - - template<> - struct Placeholder<9> - { - static decltype(std::placeholders::_9) value() { return std::placeholders::_9; } - }; - - template<> - struct Placeholder<10> - { - static decltype(std::placeholders::_10) value() { return std::placeholders::_10; } - }; - + struct Placeholder + { + static std::tuple placeholder() { + return std::tuple(std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5,std::placeholders::_6,std::placeholders::_7,std::placeholders::_8,std::placeholders::_9,std::placeholders::_10); + } + }; template struct Bind_First { template - static std::function bind(F f, InnerParams ... innerparams) + static std::function bind(F&& f, InnerParams ... innerparams) { - return Bind_First::bind(f, innerparams..., Placeholder::value()); + return Bind_First::bind(std::forward(f), innerparams..., std::get(Placeholder::placeholder())); } }; @@ -94,37 +35,42 @@ namespace chaiscript struct Bind_First<0, maxcount, Sig> { template - static std::function bind(F f, InnerParams ... innerparams) + static std::function bind(F&& f, InnerParams ... innerparams) { - return std::bind(f, innerparams...); + return std::bind(std::forward(f), innerparams...); } }; template - std::function bind_first(Ret (*f)(P1, Param...), O o) + std::function bind_first(Ret (*f)(P1, Param...), O&& o) { - return Bind_First::bind(f, o); + return Bind_First::bind(f, std::forward(o)); } template - std::function bind_first(Ret (Class::*f)(Param...), O o) + std::function bind_first(Ret (Class::*f)(Param...), O&& o) { - return Bind_First::bind(f, o); + return Bind_First::bind(f, std::forward(o)); } template - std::function bind_first(Ret (Class::*f)(Param...) const, O o) + std::function bind_first(Ret (Class::*f)(Param...) const, O&& o) { - return Bind_First::bind(f, o); + return Bind_First::bind(f, std::forward(o)); } template - std::function bind_first(const std::function &f, O o) + std::function bind_first(const std::function &f, O&& o) { - return Bind_First::bind(f, o); + return Bind_First::bind(f, std::forward(o)); } + template + std::function bind_first(std::function &&f, O&& o) + { + return Bind_First::bind(std::move(f), std::forward(o)); + } } } diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 32aa939..98648da 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -24,7 +24,7 @@ #include "boxed_number.hpp" #include "boxed_value.hpp" #include "dispatchkit.hpp" -#include "dynamic_cast_conversion.hpp" +#include "type_conversions.hpp" #include "dynamic_object.hpp" #include "operators.hpp" #include "proxy_constructors.hpp" @@ -46,13 +46,9 @@ namespace chaiscript /// \param[in] v Boxed_Number to copy into the new object /// \returns The newly created object. template - std::shared_ptr construct_pod(Boxed_Number v) + std::shared_ptr construct_pod(const Boxed_Number &v) { - std::shared_ptr p(new P1()); - Boxed_Value bv(p); - Boxed_Number nb(bv); - nb = v; - return p; + return std::make_shared(v.get_as()); } } @@ -113,9 +109,7 @@ namespace chaiscript } - /** - * to_string function for internal use. Uses ostream operator<< - */ + /// to_string function for internal use. Uses ostream operator<< template std::string to_string(Input i) { @@ -124,10 +118,8 @@ namespace chaiscript return ss.str(); } - /** - * Internal function for converting from a string to a value - * uses ostream operator >> to perform the conversion - */ + /// 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) { @@ -136,12 +128,10 @@ namespace chaiscript ss >> t; return t; } - - - /** - * Add all common functions for a POD type. All operators, and - * common conversions - */ + + + /// Add all common functions for a POD type. All operators, and + /// common conversions template ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module())) { @@ -155,22 +145,18 @@ namespace chaiscript } - /** - * "clone" function for a shared_ptr type. This is used in the case - * where you do not want to make a deep copy of an object during cloning - * but want to instead maintain the shared_ptr. It is needed internally - * for handling of Proxy_Function object (that is, - * function variables. - */ + /// "clone" function for a shared_ptr type. This is used in the case + /// where you do not want to make a deep copy of an object during cloning + /// but want to instead maintain the shared_ptr. It is needed internally + /// for handling of Proxy_Function object (that is, + /// function variables. template std::shared_ptr shared_ptr_clone(const std::shared_ptr &p) { return p; } - /** - * Specific version of shared_ptr_clone just for Proxy_Functions - */ + /// Specific version of shared_ptr_clone just for Proxy_Functions template std::shared_ptr::type> shared_ptr_unconst_clone(const std::shared_ptr::type> &p) @@ -180,11 +166,9 @@ namespace chaiscript - /** - * Assignment function for shared_ptr objects, does not perform a copy of the - * object pointed to, instead maintains the shared_ptr concept. - * Similar to shared_ptr_clone. Used for Proxy_Function. - */ + /// Assignment function for shared_ptr objects, does not perform a copy of the + /// object pointed to, instead maintains the shared_ptr concept. + /// Similar to shared_ptr_clone. Used for Proxy_Function. template Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr &rhs) { @@ -198,10 +182,8 @@ namespace chaiscript } } - /** - * Class consisting of only static functions. All default bootstrapping occurs - * from this class. - */ + /// Class consisting of only static functions. All default bootstrapping occurs + /// from this class. class Bootstrap { private: @@ -229,9 +211,7 @@ namespace chaiscript } - /** - * Add all arithmetic operators for PODs - */ + /// Add all arithmetic operators for PODs static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module())) { m->add(fun(&Boxed_Number::equals), "=="); @@ -271,11 +251,8 @@ namespace chaiscript } - /** - * Create a bound function object. The first param is the function to bind - * the remaining parameters are the args to bind into the - * result - */ + /// Create a bound function object. The first param is the function to bind + /// the remaining parameters are the args to bind into the result static Boxed_Value bind_function(const std::vector ¶ms) { if (params.size() < 2) @@ -285,7 +262,7 @@ namespace chaiscript Const_Proxy_Function f = boxed_cast(params[0]); - return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f, + return Boxed_Value(Const_Proxy_Function(std::make_shared(f, std::vector(params.begin() + 1, params.end())))); } @@ -330,9 +307,7 @@ namespace chaiscript return e.what(); } - /** - * Boolean specialization of internal to_string function - */ + /// Boolean specialization of internal to_string function static std::string bool_to_string(bool b) { if (b) @@ -362,9 +337,7 @@ namespace chaiscript static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) { - std::shared_ptr pf - = std::dynamic_pointer_cast(t_pf); - if (pf) + if (auto pf = std::dynamic_pointer_cast(t_pf)) { if (pf->get_parse_tree()) { @@ -379,9 +352,7 @@ namespace chaiscript static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) { - std::shared_ptr pf - = std::dynamic_pointer_cast(t_pf); - if (pf) + if (auto pf = std::dynamic_pointer_cast(t_pf)) { if (pf->get_parse_tree()) { @@ -504,8 +475,7 @@ namespace chaiscript m->add(fun(&print), "print_string"); m->add(fun(&println), "println_string"); - m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&bind_function, std::placeholders::_1))), - "bind"); + m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(&bind_function)), "bind"); m->add(fun(&shared_ptr_unconst_clone), "clone"); m->add(fun(&ptr_assign::type>), "="); @@ -526,11 +496,11 @@ namespace chaiscript "eval_error", { }, { {fun(&chaiscript::exception::eval_error::reason), "reason"}, - {fun(std::function (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) { + {fun(std::function (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector { std::vector retval; std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(), std::back_inserter(retval), - &chaiscript::var>); + &chaiscript::var>); return retval; })), "call_stack"} } ); @@ -554,7 +524,7 @@ namespace chaiscript {fun(&AST_Node::start), "start"}, {fun(&AST_Node::end), "end"}, {fun(&AST_Node::to_string), "to_string"}, - {fun(std::function (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) { + {fun(std::function (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) -> std::vector { std::vector retval; std::transform(t_node.children.begin(), t_node.children.end(), std::back_inserter(retval), diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 6797e5d..acb8344 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -278,9 +278,9 @@ namespace chaiscript template ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module())) { - m->add(fun( std::function( [](const ContainerType *a) { return a->size(); } ) ), "size"); - m->add(fun( std::function( [](const ContainerType *a) { return a->empty(); } ) ), "empty"); - m->add(fun( std::function( [](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; } @@ -493,24 +493,26 @@ namespace chaiscript if (typeid(VectorType) == typeid(std::vector)) { - m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \ - if ( rhs.size() != this.size() ) { \ - return false; \ - } else { \ - auto r1 = range(this); \ - auto r2 = range(rhs); \ - while (!r1.empty()) \ - { \ - if (!eq(r1.front(), r2.front())) \ - { \ - return false; \ - } \ - r1.pop_front(); \ - r2.pop_front(); \ - } \ - return true; \ - } \ - }"); + m->eval(R"( + def Vector::`==`(rhs) : type_match(rhs, this) { + if ( rhs.size() != this.size() ) { + return false; + } else { + auto r1 = range(this); + auto r2 = range(rhs); + while (!r1.empty()) + { + if (!eq(r1.front(), r2.front())) + { + return false; + } + r1.pop_front(); + r2.pop_front(); + } + true; + } + } )" + ); } return m; diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index c055ac4..1fc5755 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -14,11 +14,11 @@ #include "bad_boxed_cast.hpp" #include "boxed_cast_helper.hpp" #include "boxed_value.hpp" -#include "dynamic_cast_conversion.hpp" +#include "type_conversions.hpp" #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace detail { namespace exception { class bad_any_cast; @@ -72,7 +72,7 @@ namespace chaiscript /// assert(i == 5); /// \endcode template - typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions = nullptr) + typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr) { try { return detail::Cast_Helper::cast(bv, t_conversions); @@ -86,18 +86,18 @@ namespace chaiscript #pragma warning(disable : 4127) #endif - if (std::is_polymorphic::type>::value && t_conversions) + if (t_conversions && t_conversions->convertable_type()) { try { // std::cout << "trying an up conversion " << typeid(Type).name() << std::endl; // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // either way, we are not responsible if it doesn't work - return detail::Cast_Helper::cast(t_conversions->boxed_dynamic_cast(bv), t_conversions); + return detail::Cast_Helper::cast(t_conversions->boxed_type_conversion(bv), t_conversions); } catch (...) { try { // std::cout << "trying a down conversion " << typeid(Type).name() << std::endl; // try going the other way - down the inheritance graph - return detail::Cast_Helper::cast(t_conversions->boxed_dynamic_down_cast(bv), t_conversions); + return detail::Cast_Helper::cast(t_conversions->boxed_type_down_conversion(bv), t_conversions); } catch (const chaiscript::detail::exception::bad_any_cast &) { throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); } diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index a9c3c84..3222fd1 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -17,37 +17,32 @@ namespace chaiscript { - class Dynamic_Cast_Conversions; + class Type_Conversions; namespace detail { // Cast_Helper_Inner helper classes - /** - * Generic Cast_Helper_Inner, for casting to any type - */ + template + T* throw_if_null(T *t) + { + if (t) return t; + throw std::runtime_error("Attempted to dereference null Boxed_Value"); + } + + /// Generic Cast_Helper_Inner, for casting to any type template struct Cast_Helper_Inner { typedef typename std::reference_wrapper::type > Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { - if (ob.is_ref()) + if (ob.get_type_info().bare_equal_type_info(typeid(Result))) { - if (!ob.get_type_info().is_const()) - { - return std::cref((ob.get().cast >()).get()); - } else { - return ob.get().cast >(); - } + return *(static_cast(throw_if_null(ob.get_const_ptr()))); } else { - if (!ob.get_type_info().is_const()) - { - return std::cref(*(ob.get().cast >())); - } else { - return std::cref(*(ob.get().cast >())); - } + throw chaiscript::detail::exception::bad_any_cast(); } } }; @@ -57,23 +52,18 @@ namespace chaiscript { }; - /** - * Cast_Helper_Inner for casting to a const & type - */ + /// Cast_Helper_Inner for casting to a const & type template struct Cast_Helper_Inner : Cast_Helper_Inner { }; - /** - * Cast_Helper_Inner for casting to a const * type - */ + /// Cast_Helper_Inner for casting to a const * type template struct Cast_Helper_Inner { typedef const Result * Result_Type; - - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (ob.is_ref()) { @@ -94,15 +84,12 @@ namespace chaiscript } }; - /** - * Cast_Helper_Inner for casting to a * type - */ + /// Cast_Helper_Inner for casting to a * type template struct Cast_Helper_Inner { typedef Result * Result_Type; - - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (ob.is_ref()) { @@ -113,49 +100,43 @@ namespace chaiscript } }; - /** - * Cast_Helper_Inner for casting to a & type - */ + + /// Cast_Helper_Inner for casting to a & type template struct Cast_Helper_Inner { typedef Result& Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + 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().bare_equal_type_info(typeid(Result))) { - return ob.get().cast >(); + return *(static_cast(throw_if_null(ob.get_ptr()))); } else { - Result &r = *(ob.get().cast >()); - return r; + throw chaiscript::detail::exception::bad_any_cast(); } } }; - /** - * Cast_Helper_Inner for casting to a std::shared_ptr<> type - */ + /// Cast_Helper_Inner for casting to a std::shared_ptr<> type template struct Cast_Helper_Inner > { typedef typename std::shared_ptr Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { return ob.get().cast >(); } }; - /** - * Cast_Helper_Inner for casting to a std::shared_ptr type - */ + /// Cast_Helper_Inner for casting to a std::shared_ptr type template struct Cast_Helper_Inner > { typedef typename std::shared_ptr Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (!ob.get_type_info().is_const()) { @@ -166,9 +147,7 @@ namespace chaiscript } }; - /** - * Cast_Helper_Inner for casting to a const std::shared_ptr<> & type - */ + /// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type template struct Cast_Helper_Inner > : Cast_Helper_Inner > { @@ -180,9 +159,7 @@ namespace chaiscript }; - /** - * Cast_Helper_Inner for casting to a const std::shared_ptr & type - */ + /// Cast_Helper_Inner for casting to a const std::shared_ptr & type template struct Cast_Helper_Inner > : Cast_Helper_Inner > { @@ -195,38 +172,32 @@ namespace chaiscript - /** - * Cast_Helper_Inner for casting to a Boxed_Value type - */ + /// Cast_Helper_Inner for casting to a Boxed_Value type template<> struct Cast_Helper_Inner { typedef const Boxed_Value & Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { return ob; } }; - /** - * Cast_Helper_Inner for casting to a Boxed_Value & type - */ + /// Cast_Helper_Inner for casting to a Boxed_Value & type template<> struct Cast_Helper_Inner { typedef Boxed_Value& Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { return const_cast(ob); } }; - /** - * Cast_Helper_Inner for casting to a const Boxed_Value & type - */ + /// Cast_Helper_Inner for casting to a const Boxed_Value & type template<> struct Cast_Helper_Inner : Cast_Helper_Inner { @@ -238,9 +209,7 @@ namespace chaiscript }; - /** - * Cast_Helper_Inner for casting to a std::reference_wrapper type - */ + /// Cast_Helper_Inner for casting to a std::reference_wrapper type template struct Cast_Helper_Inner > : Cast_Helper_Inner { @@ -271,15 +240,13 @@ namespace chaiscript { }; - /** - * The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner - */ + /// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner template struct Cast_Helper { typedef typename Cast_Helper_Inner::Result_Type Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) { return Cast_Helper_Inner::cast(ob, t_conversions); } diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index f3d2838..557a20a 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -19,7 +19,7 @@ #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; } // namespace chaiscript namespace chaiscript @@ -233,7 +233,7 @@ namespace chaiscript template static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) { - const Type_Info &inp_ = t_rhs.get_type_info(); + const auto &inp_ = t_rhs.get_type_info(); if (inp_ == typeid(int)) { return Go::go(t_oper, t_lhs, t_rhs); @@ -334,10 +334,10 @@ namespace chaiscript { } - Boxed_Number(const Boxed_Value &v) - : bv(v) + Boxed_Number(Boxed_Value v) + : bv(std::move(v)) { - validate_boxed_number(v); + validate_boxed_number(bv); } template explicit Boxed_Number(T t) @@ -826,31 +826,25 @@ namespace chaiscript namespace detail { - /** - * Cast_Helper for converting from Boxed_Value to Boxed_Number - */ + /// Cast_Helper for converting from Boxed_Value to Boxed_Number template<> struct Cast_Helper { typedef Boxed_Number Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { return Boxed_Number(ob); } }; - /** - * Cast_Helper for converting from Boxed_Value to Boxed_Number - */ + /// Cast_Helper for converting from Boxed_Value to Boxed_Number template<> struct Cast_Helper : Cast_Helper { }; - /** - * Cast_Helper for converting from Boxed_Value to Boxed_Number - */ + /// Cast_Helper for converting from Boxed_Value to Boxed_Number template<> struct Cast_Helper : Cast_Helper { diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 861a2f7..c73358c 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -13,6 +13,7 @@ #include #include "../chaiscript_threading.hpp" +#include "../chaiscript_defines.hpp" #include "any.hpp" #include "type_info.hpp" @@ -35,10 +36,10 @@ namespace chaiscript struct Data { Data(const Type_Info &ti, - const chaiscript::detail::Any &to, + chaiscript::detail::Any to, bool tr, const void *t_void_ptr) - : m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?nullptr:const_cast(t_void_ptr)), m_const_data_ptr(t_void_ptr), + : m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast(t_void_ptr)), m_const_data_ptr(t_void_ptr), m_is_ref(tr) { } @@ -61,9 +62,11 @@ namespace chaiscript Data(const Data &) = delete; - ~Data() - { - } +#if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER != 1800) + Data(Data &&) = default; + Data &operator=(Data &&rhs) = default; +#endif + Type_Info m_type_info; chaiscript::detail::Any m_obj; @@ -102,32 +105,53 @@ namespace chaiscript ); } + template + static std::shared_ptr get(std::shared_ptr &&obj) + { + auto ptr = obj.get(); + return std::make_shared( + detail::Get_Type_Info::get(), + chaiscript::detail::Any(std::move(obj)), + false, + ptr + ); + } + template static std::shared_ptr get(T *t) { return get(std::ref(*t)); } + template + static std::shared_ptr get(const T *t) + { + return get(std::cref(*t)); + } + + template static std::shared_ptr get(std::reference_wrapper obj) { + auto p = &obj.get(); return std::make_shared( detail::Get_Type_Info::get(), - chaiscript::detail::Any(obj), + chaiscript::detail::Any(std::move(obj)), true, - &obj.get() + p ); } template - static std::shared_ptr get(const T& t) + static std::shared_ptr get(T t) { - auto p = std::make_shared(t); + auto p = std::make_shared(std::move(t)); + auto ptr = p.get(); return std::make_shared( detail::Get_Type_Info::get(), - chaiscript::detail::Any(p), + chaiscript::detail::Any(std::move(p)), false, - p.get() + ptr ); } @@ -145,27 +169,26 @@ namespace chaiscript public: /// Basic Boxed_Value constructor - template - explicit Boxed_Value(T t) - : m_data(Object_Data::get(t)) + template::type>::value>::type> + explicit Boxed_Value(T &&t) + : m_data(Object_Data::get(std::forward(t))) { } - /// Copy constructor - each copy shares the same data pointer - Boxed_Value(const Boxed_Value &t_so) - : m_data(t_so.m_data) - { - } - /// Unknown-type constructor Boxed_Value() : m_data(Object_Data::get()) { } - ~Boxed_Value() - { - } +#if !defined(_MSC_VER) || _MSC_VER != 1800 + Boxed_Value(Boxed_Value&&) = default; + Boxed_Value& operator=(Boxed_Value&&) = default; +#endif + + Boxed_Value(const Boxed_Value&) = default; + Boxed_Value& operator=(const Boxed_Value&) = default; void swap(Boxed_Value &rhs) { @@ -180,61 +203,53 @@ namespace chaiscript return *this; } - /// shared data assignment, same as copy construction - Boxed_Value &operator=(const Boxed_Value &rhs) - { - Boxed_Value temp(rhs); - swap(temp); - return *this; - } - - const Type_Info &get_type_info() const + const Type_Info &get_type_info() const CHAISCRIPT_NOEXCEPT { return m_data->m_type_info; } /// return true if the object is uninitialized - bool is_undef() const + bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_data->m_type_info.is_undef(); } - bool is_const() const + bool is_const() const CHAISCRIPT_NOEXCEPT { return m_data->m_type_info.is_const(); } - bool is_type(const Type_Info &ti) const + bool is_type(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT { return m_data->m_type_info.bare_equal(ti); } - bool is_null() const + bool is_null() const CHAISCRIPT_NOEXCEPT { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); } - const chaiscript::detail::Any & get() const + const chaiscript::detail::Any & get() const CHAISCRIPT_NOEXCEPT { return m_data->m_obj; } - bool is_ref() const + bool is_ref() const CHAISCRIPT_NOEXCEPT { return m_data->m_is_ref; } - bool is_pointer() const + bool is_pointer() const CHAISCRIPT_NOEXCEPT { return !is_ref(); } - void *get_ptr() const + void *get_ptr() const CHAISCRIPT_NOEXCEPT { return m_data->m_data_ptr; } - const void *get_const_ptr() const + const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT { return m_data->m_const_data_ptr; } @@ -260,7 +275,7 @@ namespace chaiscript /// \returns true if the two Boxed_Values share the same internal type - static bool type_match(Boxed_Value l, Boxed_Value r) + static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT { return l.get_type_info() == r.get_type_info(); } @@ -297,7 +312,7 @@ namespace chaiscript template Boxed_Value const_var_impl(const T &t) { - return Boxed_Value(std::shared_ptr::type >(new T(t))); + return Boxed_Value(std::make_shared::type >(t)); } /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 8c4a7f5..9d78507 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -27,7 +27,7 @@ #include "boxed_cast.hpp" #include "boxed_cast_helper.hpp" #include "boxed_value.hpp" -#include "dynamic_cast_conversion.hpp" +#include "type_conversions.hpp" #include "dynamic_object.hpp" #include "proxy_constructors.hpp" #include "proxy_functions.hpp" @@ -53,9 +53,7 @@ namespace chaiscript { namespace exception { - /** - * Exception thrown in the case that an object name is invalid because it is a reserved word - */ + /// Exception thrown in the case that an object name is invalid because it is a reserved word class reserved_word_error : public std::runtime_error { public: @@ -75,18 +73,16 @@ namespace chaiscript std::string m_word; }; - /** - * Exception thrown in the case that an object name is invalid because it contains illegal characters - */ + /// Exception thrown in the case that an object name is invalid because it contains illegal characters class illegal_name_error : public std::runtime_error { public: - illegal_name_error(const std::string &t_name) throw() + illegal_name_error(const std::string &t_name) CHAISCRIPT_NOEXCEPT : std::runtime_error("Reserved name not allowed in object name: " + t_name), m_name(t_name) { } - virtual ~illegal_name_error() throw() {} + virtual ~illegal_name_error() CHAISCRIPT_NOEXCEPT {} std::string name() const { @@ -98,18 +94,16 @@ namespace chaiscript }; - /** - * Exception thrown in the case that an object name is invalid because it already exists in current context - */ + /// Exception thrown in the case that an object name is invalid because it already exists in current context class name_conflict_error : public std::runtime_error { public: - name_conflict_error(const std::string &t_name) throw() + name_conflict_error(const std::string &t_name) CHAISCRIPT_NOEXCEPT : std::runtime_error("Name already exists in current context " + t_name), m_name(t_name) { } - virtual ~name_conflict_error() throw() {} + virtual ~name_conflict_error() CHAISCRIPT_NOEXCEPT {} std::string name() const { @@ -122,9 +116,7 @@ namespace chaiscript }; - /** - * Exception thrown in the case that a non-const object was added as a shared object - */ + /// Exception thrown in the case that a non-const object was added as a shared object class global_non_const : public std::runtime_error { public: @@ -143,37 +135,37 @@ namespace chaiscript class Module { public: - Module &add(const Type_Info &ti, const std::string &name) + Module &add(Type_Info ti, std::string name) { - m_typeinfos.push_back(std::make_pair(ti, name)); + m_typeinfos.emplace_back(std::move(ti), std::move(name)); return *this; } - Module &add(const Dynamic_Cast_Conversion &d) + Module &add(Type_Conversion d) { - m_conversions.push_back(d); + m_conversions.push_back(std::move(d)); return *this; } - Module &add(const Proxy_Function &f, const std::string &name) + Module &add(Proxy_Function f, std::string name) { - m_funcs.push_back(std::make_pair(f, name)); + m_funcs.emplace_back(std::move(f), std::move(name)); return *this; } - Module &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) + Module &add_global_const(Boxed_Value t_bv, std::string t_name) { if (!t_bv.is_const()) { throw chaiscript::exception::global_non_const(); } - m_globals.push_back(std::make_pair(t_bv, t_name)); + m_globals.emplace_back(std::move(t_bv), std::move(t_name)); return *this; } - //Add a bit of chaiscript to eval during module implementation + //Add a bit of ChaiScript to eval during module implementation Module &eval(const std::string &str) { m_evals.push_back(str); @@ -205,21 +197,21 @@ namespace chaiscript std::vector > m_funcs; std::vector > m_globals; std::vector m_evals; - std::vector m_conversions; + std::vector m_conversions; template - static void apply(InItr begin, InItr end, T &t) + static void apply(InItr begin, const InItr end, T &t) { - while (begin != end) - { - try { - t.add(begin->first, begin->second); - } catch (const chaiscript::exception::name_conflict_error &) { - /// \todo Should we throw an error if there's a name conflict - /// while applying a module? - } - ++begin; - } + for_each(begin, end, [&t](typename std::iterator_traits::reference obj) + { + try { + t.add(obj.first, obj.second); + } catch (const chaiscript::exception::name_conflict_error &) { + /// \todo Should we throw an error if there's a name conflict + /// while applying a module? + } + } + ); } template @@ -258,24 +250,22 @@ namespace chaiscript namespace detail { - /** - * A Proxy_Function implementation that is able to take - * a vector of Proxy_Functions and perform a dispatch on them. It is - * used specifically in the case of dealing with Function object variables - */ + /// A Proxy_Function implementation that is able to take + /// a vector of Proxy_Functions and perform a dispatch on them. It is + /// used specifically in the case of dealing with Function object variables class Dispatch_Function : public dispatch::Proxy_Function_Base { public: - Dispatch_Function(const std::vector &t_funcs) - : Proxy_Function_Base(build_type_infos(t_funcs)), - m_funcs(t_funcs) + Dispatch_Function(std::vector t_funcs) + : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)), + m_funcs(std::move(t_funcs)) { } virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE { try { - const Dispatch_Function &dispatchfun = dynamic_cast(rhs); + const auto &dispatchfun = dynamic_cast(rhs); return m_funcs == dispatchfun.m_funcs; } catch (const std::bad_cast &) { return false; @@ -290,52 +280,30 @@ namespace chaiscript } - virtual int get_arity() const CHAISCRIPT_OVERRIDE + static int calculate_arity(const std::vector &t_funcs) { - typedef std::vector function_vec; - - auto begin = m_funcs.begin(); - const function_vec::const_iterator end = m_funcs.end(); - - if (begin != end) - { - int arity = (*begin)->get_arity(); - - ++begin; - - while (begin != end) - { - if (arity != (*begin)->get_arity()) - { - // The arities in the list do not match, so it's unspecified - return -1; - } - - ++begin; - } - - return arity; + if (t_funcs.empty()) { + return -1; } - return -1; // unknown arity + const auto arity = t_funcs.front()->get_arity(); + + for (const auto &func : t_funcs) + { + if (arity != func->get_arity()) + { + // The arities in the list do not match, so it's unspecified + return -1; + } + } + + return arity; } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - auto begin = m_funcs.begin(); - auto end = m_funcs.end(); - - while (begin != end) - { - if ((*begin)->call_match(vals, t_conversions)) - { - return true; - } else { - ++begin; - } - } - - return false; + return std::any_of(m_funcs.cbegin(), m_funcs.cend(), + [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); }); } virtual std::string annotation() const CHAISCRIPT_OVERRIDE @@ -344,9 +312,9 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params, t_conversions); + return dispatch::dispatch(m_funcs, params, t_conversions); } private: @@ -354,10 +322,8 @@ namespace chaiscript static std::vector build_type_infos(const std::vector &t_funcs) { - typedef std::vector function_vec; - - auto begin = t_funcs.begin(); - const function_vec::const_iterator end = t_funcs.end(); + auto begin = t_funcs.cbegin(); + const auto &end = t_funcs.cend(); if (begin != end) { @@ -399,23 +365,20 @@ namespace chaiscript return std::vector(); } - }; + }; } namespace detail { - /** - * Main class for the dispatchkit. Handles management - * of the object stack, functions and registered types. - */ + /// 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::deque StackData; - typedef std::shared_ptr Stack; + typedef std::vector StackData; struct State { @@ -430,8 +393,7 @@ namespace chaiscript Dispatch_Engine() : m_stack_holder(this), - m_place_holder(std::shared_ptr(new dispatch::Placeholder_Object())) - + m_place_holder(std::make_shared()) { } @@ -446,67 +408,56 @@ namespace chaiscript return chaiscript::boxed_cast(bv, &m_conversions); } - /** - * Add a new conversion for upcasting to a base class - */ - void add(const Dynamic_Cast_Conversion &d) + /// Add a new conversion for upcasting to a base class + void add(const Type_Conversion &d) { m_conversions.add_conversion(d); } - /** - * Add a new named Proxy_Function to the system - */ + /// Add a new named Proxy_Function to the system void add(const Proxy_Function &f, const std::string &name) { validate_object_name(name); add_function(f, name); } - /** - * Set the value of an object, by name. If the object - * is not available in the current scope it is created - */ + /// 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) { validate_object_name(name); - StackData &stack = get_stack_data(); + auto &stack = get_stack_data(); - for (int i = static_cast(stack.size())-1; i >= 0; --i) + for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) { - std::map::const_iterator itr = stack[i].find(name); - if (itr != stack[i].end()) + auto itr = stack_elem->find(name); + if (itr != stack_elem->end()) { - stack[i][name] = obj; + itr->second = std::move(obj); return; } } - add_object(name, obj); + add_object(name, std::move(obj)); } - /** - * Adds a named object to the current scope - */ + /// Adds a named object to the current scope void add_object(const std::string &name, const Boxed_Value &obj) const { - StackData &stack = get_stack_data(); + auto &stack = get_stack_data(); validate_object_name(name); - Scope &scope = stack.back(); - auto itr = scope.find(name); - if (itr != stack.back().end()) + auto &scope = stack.back(); + if (scope.find(name) != scope.end()) { throw chaiscript::exception::name_conflict_error(name); } else { - stack.back().insert(std::make_pair(name, obj)); + scope.insert(std::make_pair(name, obj)); } } - /** - * Adds a new global shared object, between all the threads - */ + /// Adds a new global shared object, between all the threads void add_global_const(const Boxed_Value &obj, const std::string &name) { validate_object_name(name); @@ -526,9 +477,7 @@ namespace chaiscript } - /** - * Adds a new global (non-const) shared object, between all the threads - */ + /// Adds a new global (non-const) shared object, between all the threads void add_global(const Boxed_Value &obj, const std::string &name) { validate_object_name(name); @@ -544,18 +493,13 @@ namespace chaiscript } - /** - * Adds a new scope to the stack - */ + /// Adds a new scope to the stack void new_scope() { - StackData &stack = get_stack_data(); - stack.push_back(Scope()); + get_stack_data().emplace_back(); } - /** - * Pops the current scope from the stack - */ + /// Pops the current scope from the stack void pop_scope() { StackData &stack = get_stack_data(); @@ -571,9 +515,8 @@ namespace chaiscript /// Pushes a new stack on to the list of stacks void new_stack() { - Stack s(new Stack::element_type()); - s->push_back(Scope()); - m_stack_holder->stacks.push_back(s); + // add a new Stack with 1 element + m_stack_holder->stacks.emplace_back(1); } void pop_stack() @@ -581,17 +524,9 @@ namespace chaiscript m_stack_holder->stacks.pop_back(); } - /// \returns the current stack - Stack get_stack() const - { - return m_stack_holder->stacks.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. - */ + /// 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 { // Is it a placeholder object? @@ -600,13 +535,13 @@ namespace chaiscript return m_place_holder; } - StackData &stack = get_stack_data(); + auto &stack = get_stack_data(); // Is it in the stack? - for (int i = static_cast(stack.size())-1; i >= 0; --i) + for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) { - std::map::const_iterator stackitr = stack[i].find(name); - if (stackitr != stack[i].end()) + const auto stackitr = stack_elem->find(name); + if (stackitr != stack_elem->end()) { return stackitr->second; } @@ -616,7 +551,7 @@ namespace chaiscript { chaiscript::detail::threading::shared_lock l(m_global_object_mutex); - auto itr = m_state.m_global_objects.find(name); + const auto itr = m_state.m_global_objects.find(name); if (itr != m_state.m_global_objects.end()) { return itr->second; @@ -627,9 +562,7 @@ namespace chaiscript return get_function_object(name); } - /** - * Registers a new named type - */ + /// Registers a new named type void add(const Type_Info &ti, const std::string &name) { add_global_const(const_var(ti), name + "_type"); @@ -639,14 +572,12 @@ namespace chaiscript m_state.m_types.insert(std::make_pair(name, ti)); } - /** - * Returns the type info for a named type - */ + /// Returns the type info for a named type Type_Info get_type(const std::string &name) const { chaiscript::detail::threading::shared_lock l(m_mutex); - auto itr = m_state.m_types.find(name); + const auto itr = m_state.m_types.find(name); if (itr != m_state.m_types.end()) { @@ -656,11 +587,9 @@ namespace chaiscript throw std::range_error("Type Not Known"); } - /** - * Returns the registered name of a known type_info object - * compares the "bare_type_info" for the broadest possible - * match - */ + /// Returns the registered name of a known type_info object + /// compares the "bare_type_info" for the broadest possible + /// match std::string get_type_name(const Type_Info &ti) const { chaiscript::detail::threading::shared_lock l(m_mutex); @@ -676,9 +605,7 @@ namespace chaiscript return ti.bare_name(); } - /** - * Return all registered types - */ + /// Return all registered types std::vector > get_types() const { chaiscript::detail::threading::shared_lock l(m_mutex); @@ -686,26 +613,22 @@ namespace chaiscript return std::vector >(m_state.m_types.begin(), m_state.m_types.end()); } - /** - * Return a function by name - */ - std::vector< Proxy_Function > - get_function(const std::string &t_name) const + /// Return a function by name + std::vector< Proxy_Function > get_function(const std::string &t_name) const + { + chaiscript::detail::threading::shared_lock l(m_mutex); + + const auto &funs = get_functions_int(); + + auto itr = funs.find(t_name); + + if (itr != funs.end()) { - chaiscript::detail::threading::shared_lock l(m_mutex); - - const std::map > &funs = get_functions_int(); - - auto itr - = funs.find(t_name); - - if (itr != funs.end()) - { - return itr->second; - } else { - return std::vector(); - } + return itr->second; + } else { + return std::vector(); } + } /// \returns a function object (Boxed_Value wrapper) if it exists /// \throws std::range_error if it does not @@ -713,7 +636,7 @@ namespace chaiscript { chaiscript::detail::threading::shared_lock l(m_mutex); - const std::map &funs = get_function_objects_int(); + const auto &funs = get_function_objects_int(); auto itr = funs.find(t_name); @@ -725,14 +648,12 @@ namespace chaiscript } } - /** - * Return true if a function exists - */ + /// Return true if a function exists bool function_exists(const std::string &name) const { chaiscript::detail::threading::shared_lock l(m_mutex); - const std::map > &functions = get_functions_int(); + const auto &functions = get_functions_int(); return functions.find(name) != functions.end(); } @@ -740,7 +661,7 @@ namespace chaiscript /// the current scope. std::map get_parent_locals() const { - StackData &stack = get_stack_data(); + auto &stack = get_stack_data(); if (stack.size() > 1) { return stack[1]; @@ -752,8 +673,8 @@ namespace chaiscript /// \returns All values in the local thread state, added through the add() function std::map get_locals() const { - StackData &stack = get_stack_data(); - Scope &scope = stack.front(); + auto &stack = get_stack_data(); + auto &scope = stack.front(); return scope; } @@ -764,8 +685,8 @@ namespace chaiscript /// Any existing locals are removed and the given set of variables is added void set_locals(const std::map &t_locals) { - StackData &stack = get_stack_data(); - Scope &scope = stack.front(); + auto &stack = get_stack_data(); + auto &scope = stack.front(); scope = t_locals; } @@ -779,12 +700,11 @@ namespace chaiscript Stack_Holder &s = *m_stack_holder; // We don't want the current context, but one up if it exists - StackData &stack = (s.stacks.size()==1)?(*(s.stacks.back())):(*s.stacks[s.stacks.size()-2]); + StackData &stack = (s.stacks.size()==1)?(s.stacks.back()):(s.stacks[s.stacks.size()-2]); std::map retval; // note: map insert doesn't overwrite existing values, which is why this works - for (auto itr = stack.rbegin(); itr != stack.rend(); ++itr) { retval.insert(itr->begin(), itr->end()); @@ -808,7 +728,7 @@ namespace chaiscript { chaiscript::detail::threading::shared_lock l(m_mutex); - const std::map &funs = get_function_objects_int(); + const auto &funs = get_function_objects_int(); std::map objs; @@ -821,22 +741,20 @@ namespace chaiscript } - /** - * Get a vector of all registered functions - */ + /// Get a vector of all registered functions std::vector > get_functions() const { chaiscript::detail::threading::shared_lock l(m_mutex); std::vector > rets; - const std::map > &functions = get_functions_int(); + const auto &functions = get_functions_int(); for (const auto & function : functions) { for (const auto & internal_func : function.second) { - rets.push_back(std::make_pair(function.first, internal_func)); + rets.emplace_back(function.first, internal_func); } } @@ -850,16 +768,14 @@ namespace chaiscript m_state.m_reserved_words.insert(name); } - const Dynamic_Cast_Conversions &conversions() const + const Type_Conversions &conversions() const { return m_conversions; } Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const { - std::vector functions = get_function(t_name); - - return dispatch::dispatch(functions.begin(), functions.end(), params, m_conversions); + return dispatch::dispatch(get_function(t_name), params, m_conversions); } Boxed_Value call_function(const std::string &t_name) const @@ -867,40 +783,29 @@ namespace chaiscript return call_function(t_name, std::vector()); } - Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1) const + Boxed_Value call_function(const std::string &t_name, Boxed_Value p1) const { - std::vector params; - params.push_back(p1); - return call_function(t_name, params); + return call_function(t_name, std::vector({std::move(p1)})); } - Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1, const Boxed_Value &p2) const + Boxed_Value call_function(const std::string &t_name, Boxed_Value p1, Boxed_Value p2) const { - std::vector params; - params.push_back(p1); - params.push_back(p2); - return call_function(t_name, params); + return call_function(t_name, std::vector({std::move(p1), std::move(p2)})); } - /** - * Dump object info to stdout - */ + /// Dump object info to stdout void dump_object(const Boxed_Value &o) const { std::cout << (o.is_const()?"const ":"") << type_name(o) << std::endl; } - /** - * Dump type info to stdout - */ + /// Dump type info to stdout void dump_type(const Type_Info &type) const { std::cout << (type.is_const()?"const ":"") << get_type_name(type); } - /** - * Dump function to stdout - */ + /// Dump function to stdout void dump_function(const std::pair &f) const { std::vector params = f.second->get_param_types(); @@ -928,25 +833,21 @@ namespace chaiscript std::cout << ") " << std::endl; } - /** - * Returns true if a call can be made that consists of the first parameter - * (the function) with the remaining parameters as its arguments. - */ + /// Returns true if a call can be made that consists of the first parameter + /// (the function) with the remaining parameters as its arguments. Boxed_Value call_exists(const std::vector ¶ms) { - if (params.size() < 1) + if (params.empty()) { throw chaiscript::exception::arity_error(static_cast(params.size()), 1); } - Const_Proxy_Function f = this->boxed_cast(params[0]); + const Const_Proxy_Function &f = this->boxed_cast(params[0]); return Boxed_Value(f->call_match(std::vector(params.begin() + 1, params.end()), m_conversions)); } - /** - * Dump all system info to stdout - */ + /// Dump all system info to stdout void dump_system() const { std::cout << "Registered Types: " << std::endl; @@ -973,9 +874,7 @@ namespace chaiscript std::cout << std::endl; } - /** - * return true if the Boxed_Value matches the registered type by name - */ + /// return true if the Boxed_Value matches the registered type by name bool is_type(const Boxed_Value &r, const std::string &user_typename) const { try { @@ -1016,6 +915,22 @@ namespace chaiscript m_state = t_state; } + void save_function_params(std::initializer_list t_params) + { + Stack_Holder &s = *m_stack_holder; + s.call_params.insert(s.call_params.begin(), 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.insert(s.call_params.begin(), std::move(param)); + } + } + void save_function_params(const std::vector &t_params) { Stack_Holder &s = *m_stack_holder; @@ -1024,7 +939,15 @@ namespace chaiscript void new_function_call() { + Stack_Holder &s = *m_stack_holder; + if (s.call_depth == 0) + { + m_conversions.enable_conversion_saves(true); + } + ++m_stack_holder->call_depth; + + save_function_params(m_conversions.take_saves()); } void pop_function_call() @@ -1039,17 +962,16 @@ namespace chaiscript /// \todo Critical: this needs to be smarter, memory can expand quickly /// in tight loops involving function calls s.call_params.clear(); + m_conversions.enable_conversion_saves(false); } } private: - /** - * Returns the current stack - * make const/non const versions - */ + /// Returns the current stack + /// make const/non const versions StackData &get_stack_data() const { - return *(m_stack_holder->stacks.back()); + return m_stack_holder->stacks.back(); } const std::map &get_function_objects_int() const @@ -1074,17 +996,17 @@ namespace chaiscript static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) { - const std::vector lhsparamtypes = lhs->get_param_types(); - const std::vector rhsparamtypes = rhs->get_param_types(); + const auto &lhsparamtypes = lhs->get_param_types(); + const auto &rhsparamtypes = rhs->get_param_types(); - const size_t lhssize = lhsparamtypes.size(); - const size_t rhssize = rhsparamtypes.size(); + const auto lhssize = lhsparamtypes.size(); + const auto rhssize = rhsparamtypes.size(); - const Type_Info boxed_type = user_type(); - const Type_Info boxed_pod_type = user_type(); + CHAISCRIPT_CONSTEXPR auto boxed_type = user_type(); + CHAISCRIPT_CONSTEXPR auto boxed_pod_type = user_type(); - std::shared_ptr dynamic_lhs(std::dynamic_pointer_cast(lhs)); - std::shared_ptr dynamic_rhs(std::dynamic_pointer_cast(rhs)); + auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); + auto dynamic_rhs(std::dynamic_pointer_cast(rhs)); if (dynamic_lhs && dynamic_rhs) { @@ -1112,11 +1034,10 @@ namespace chaiscript } - for (size_t i = 1; i < lhssize && i < rhssize; ++i) { - const Type_Info lt = lhsparamtypes[i]; - const Type_Info rt = rhsparamtypes[i]; + const Type_Info < = lhsparamtypes[i]; + const Type_Info &rt = rhsparamtypes[i]; if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) { @@ -1167,9 +1088,7 @@ namespace chaiscript } - /** - * Throw a reserved_word exception if the name is not allowed - */ + /// Throw a reserved_word exception if the name is not allowed void validate_object_name(const std::string &name) const { if (name.find("::") != std::string::npos) { @@ -1184,29 +1103,24 @@ namespace chaiscript } } - /** - * Implementation detail for adding a function. - * \throws exception::name_conflict_error if there's a function matching the given one being added - */ + /// Implementation detail for adding a function. + /// \throws exception::name_conflict_error if there's a function matching the given one being added void add_function(const Proxy_Function &t_f, const std::string &t_name) { chaiscript::detail::threading::unique_lock l(m_mutex); - std::map > &funcs = get_functions_int(); + auto &funcs = get_functions_int(); - auto itr - = funcs.find(t_name); + auto itr = funcs.find(t_name); - std::map &func_objs = get_function_objects_int(); + auto &func_objs = get_function_objects_int(); if (itr != funcs.end()) { - std::vector &vec = itr->second; - for (std::vector::const_iterator itr2 = vec.begin(); - itr2 != vec.end(); - ++itr2) + auto &vec = itr->second; + for (const auto &func : vec) { - if ((*t_f) == *(*itr2)) + if ((*t_f) == *(func)) { throw chaiscript::exception::name_conflict_error(t_name); } @@ -1214,19 +1128,16 @@ namespace chaiscript vec.push_back(t_f); std::stable_sort(vec.begin(), vec.end(), &function_less_than); - func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec)); + 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; - vec.push_back(t_f); + std::vector vec({t_f}); funcs.insert(std::make_pair(t_name, vec)); - func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec)); + func_objs[t_name] = std::make_shared(std::move(vec)); } else { - std::vector vec; - vec.push_back(t_f); - funcs.insert(std::make_pair(t_name, vec)); + funcs.insert(std::make_pair(t_name, std::vector{t_f})); func_objs[t_name] = t_f; } @@ -1241,18 +1152,16 @@ namespace chaiscript Stack_Holder() : call_depth(0) { - Stack s(new StackData()); - s->push_back(Scope()); - stacks.push_back(s); + stacks.emplace_back(1); } - std::deque stacks; + std::deque stacks; std::list call_params; int call_depth; - }; + }; - Dynamic_Cast_Conversions m_conversions; + Type_Conversions m_conversions; chaiscript::detail::threading::Thread_Storage m_stack_holder; diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp deleted file mode 100644 index 7c46542..0000000 --- a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp +++ /dev/null @@ -1,294 +0,0 @@ -// This file is distributed under the BSD License. -// See "license.txt" for details. -// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2014, Jason Turner (jason@emptycrate.com) -// http://www.chaiscript.com - -#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ -#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ - -#include -#include -#include -#include -#include -#include - -#include "../chaiscript_threading.hpp" -#include "bad_boxed_cast.hpp" -#include "boxed_cast_helper.hpp" -#include "boxed_value.hpp" -#include "type_info.hpp" - -namespace chaiscript -{ - namespace exception - { - class bad_boxed_dynamic_cast : public bad_boxed_cast - { - public: - bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, - const std::string &t_what) CHAISCRIPT_NOEXCEPT - : bad_boxed_cast(t_from, t_to, t_what) - { - } - - bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT - : bad_boxed_cast(t_from, t_to) - { - } - - bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT - : bad_boxed_cast(w) - { - } - - virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {} - }; - } - - namespace detail - { - class Dynamic_Conversion - { - public: - virtual Boxed_Value convert(const Boxed_Value &derived) const = 0; - virtual Boxed_Value convert_down(const Boxed_Value &base) const = 0; - - const Type_Info &base() const - { - return m_base; - } - const Type_Info &derived() const - { - return m_derived; - } - - protected: - Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived) - : m_base(t_base), m_derived(t_derived) - { - } - - virtual ~Dynamic_Conversion() {} - - private: - Type_Info m_base; - Type_Info m_derived; - - }; - - template - class Dynamic_Caster - { - public: - static Boxed_Value cast(const Boxed_Value &t_from) - { - if (t_from.get_type_info().bare_equal(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()) - { - std::shared_ptr data - = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr)); - if (!data) - { - throw std::bad_cast(); - } - - return Boxed_Value(data); - } else { - std::shared_ptr data - = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr)); - - if (!data) - { - throw std::bad_cast(); - } - - return Boxed_Value(data); - } - } 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 = dynamic_cast(d); - return Boxed_Value(std::cref(data)); - } else { - From &d = detail::Cast_Helper::cast(t_from, nullptr); - To &data = dynamic_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_Conversion_Impl : public Dynamic_Conversion - { - public: - Dynamic_Conversion_Impl() - : Dynamic_Conversion(user_type(), user_type()) - { - } - - virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE - { - return Dynamic_Caster::cast(t_base); - } - - virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE - { - return Dynamic_Caster::cast(t_derived); - } - }; - } - - class Dynamic_Cast_Conversions - { - public: - Dynamic_Cast_Conversions() - { - } - - Dynamic_Cast_Conversions(const Dynamic_Cast_Conversions &t_other) - : m_conversions(t_other.get_conversions()) - { - } - - void add_conversion(const std::shared_ptr &conversion) - { - chaiscript::detail::threading::unique_lock l(m_mutex); - m_conversions.insert(conversion); - } - - template - bool dynamic_cast_converts() const - { - return dynamic_cast_converts(user_type(), user_type()); - } - - bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const - { - return has_conversion(base, derived) || has_conversion(derived, base); - } - - template - Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const - { - try { - return get_conversion(user_type(), derived.get_type_info())->convert(derived); - } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion"); - } catch (const std::bad_cast &) { - throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation"); - } - } - - template - Boxed_Value boxed_dynamic_down_cast(const Boxed_Value &base) const - { - try { - return get_conversion(base.get_type_info(), user_type())->convert_down(base); - } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "No known conversion"); - } catch (const std::bad_cast &) { - throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "Unable to perform dynamic_cast operation"); - } - } - - - bool has_conversion(const Type_Info &base, const Type_Info &derived) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - return find(base, derived) != m_conversions.end(); - } - - std::shared_ptr get_conversion(const Type_Info &base, const Type_Info &derived) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - - auto itr = - find(base, derived); - - if (itr != m_conversions.end()) - { - return *itr; - } else { - throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name()); - } - } - - private: - std::set >::const_iterator find( - const Type_Info &base, const Type_Info &derived) const - { - for (auto itr = m_conversions.begin(); - itr != m_conversions.end(); - ++itr) - { - if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived)) - { - return itr; - } - } - - return m_conversions.end(); - } - - std::set > get_conversions() const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - - return m_conversions; - } - - mutable chaiscript::detail::threading::shared_mutex m_mutex; - std::set > m_conversions; - }; - - typedef std::shared_ptr Dynamic_Cast_Conversion; - - /// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you - /// want automatic conversions up your inheritance hierarchy. - /// - /// Create a new base class registration for applying to a module or to the chaiscript engine - /// Currently, due to limitations in module loading on Windows, and for the sake of portability, - /// if you have a type that is introduced in a loadable module and is used by multiple modules - /// (through a tertiary dll that is shared between the modules, static linking the new type - /// into both loadable modules would not be portable), you need to register the base type - /// relationship in all modules that use the newly added type in a polymorphic way. - /// - /// Example: - /// \code - /// class Base - /// {}; - /// class Derived : public Base - /// {}; - /// - /// chaiscript::ChaiScript chai; - /// chai.add(chaiscript::base_class()); - /// \endcode - /// - template - Dynamic_Cast_Conversion base_class() - { - //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 std::shared_ptr(new detail::Dynamic_Conversion_Impl()); - } - -} - - -#endif diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index beb1c8e..69c24d5 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -23,7 +23,7 @@ #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace dispatch { class Proxy_Function_Base; } // namespace dispatch @@ -64,18 +64,16 @@ namespace chaiscript namespace detail { - /** - * A Proxy_Function implementation designed for calling a function - * that is automatically guarded based on the first param based on the - * param's type name - */ + /// A Proxy_Function implementation designed for calling a function + /// that is automatically guarded based on the first param based on the + /// param's type name class Dynamic_Object_Function : public Proxy_Function_Base { public: Dynamic_Object_Function( std::string t_type_name, const Proxy_Function &t_func) - : Proxy_Function_Base(t_func->get_param_types()), + : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()), m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type()) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) @@ -86,7 +84,7 @@ namespace chaiscript std::string t_type_name, const Proxy_Function &t_func, const Type_Info &t_ti) - : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)), + : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()), m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type()) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) @@ -96,11 +94,11 @@ namespace chaiscript virtual ~Dynamic_Object_Function() {} Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; + Dynamic_Object_Function(Dynamic_Object_Function &) = delete; virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE { - const Dynamic_Object_Function *df = dynamic_cast(&f); - if (df) + if (const auto *df = dynamic_cast(&f)) { return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); } else { @@ -108,7 +106,7 @@ namespace chaiscript } } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) { @@ -123,12 +121,6 @@ namespace chaiscript return {m_func}; } - - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return m_func->get_arity(); - } - virtual std::string annotation() const CHAISCRIPT_OVERRIDE { return m_func->annotation(); @@ -136,7 +128,7 @@ namespace chaiscript protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) { @@ -146,7 +138,7 @@ namespace chaiscript } } - virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); } @@ -164,7 +156,7 @@ namespace chaiscript } bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, - const std::shared_ptr &ti, const Dynamic_Cast_Conversions &t_conversions) const + const std::unique_ptr &ti, const Type_Conversions &t_conversions) const { if (bv.get_type_info().bare_equal(m_doti)) { @@ -186,7 +178,7 @@ namespace chaiscript } bool dynamic_object_typename_match(const std::vector &bvs, const std::string &name, - const std::shared_ptr &ti, const Dynamic_Cast_Conversions &t_conversions) const + const std::unique_ptr &ti, const Type_Conversions &t_conversions) const { if (bvs.size() > 0) { @@ -198,7 +190,7 @@ namespace chaiscript std::string m_type_name; Proxy_Function m_func; - std::shared_ptr m_ti; + std::unique_ptr m_ti; const Type_Info m_doti; @@ -217,7 +209,7 @@ namespace chaiscript Dynamic_Object_Constructor( std::string t_type_name, const Proxy_Function &t_func) - : Proxy_Function_Base(build_type_list(t_func->get_param_types())), + : Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1), m_type_name(std::move(t_type_name)), m_func(t_func) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) @@ -250,33 +242,24 @@ namespace chaiscript } } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - std::vector new_vals; - new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name))); + std::vector new_vals{Boxed_Value(Dynamic_Object(m_type_name))}; new_vals.insert(new_vals.end(), vals.begin(), vals.end()); return m_func->call_match(new_vals, t_conversions); } - - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - // "this" is not considered part of the arity - return m_func->get_arity() - 1; - } - virtual std::string annotation() const CHAISCRIPT_OVERRIDE { return m_func->annotation(); } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - std::vector new_params; - chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name)); - new_params.push_back(bv); + auto bv = var(Dynamic_Object(m_type_name)); + std::vector new_params{bv}; new_params.insert(new_params.end(), params.begin(), params.end()); (*m_func)(new_params, t_conversions); diff --git a/include/chaiscript/dispatchkit/exception_specification.hpp b/include/chaiscript/dispatchkit/exception_specification.hpp index 4645c75..e323484 100644 --- a/include/chaiscript/dispatchkit/exception_specification.hpp +++ b/include/chaiscript/dispatchkit/exception_specification.hpp @@ -23,6 +23,7 @@ namespace chaiscript { namespace detail { + /// \todo make this a variadic template struct Exception_Handler_Base { virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0; diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index 8b6c9ff..a434f07 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -18,7 +18,7 @@ namespace chaiscript { class Boxed_Value; -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace detail { template struct Cast_Helper; } // namespace detail @@ -28,66 +28,56 @@ namespace chaiscript { namespace dispatch { - /** - * Build a function caller that knows how to dispatch on a set of functions - * example: - * std::function f = - * build_function_caller(dispatchkit.get_function("print")); - * \returns A std::function object for dispatching - * \param[in] funcs the set of functions to dispatch on. - */ + /// Build a function caller that knows how to dispatch on a set of functions + /// example: + /// std::function f = + /// build_function_caller(dispatchkit.get_function("print")); + /// \returns A std::function object for dispatching + /// \param[in] funcs the set of functions to dispatch on. template std::function - functor(const std::vector &funcs, const Dynamic_Cast_Conversions *t_conversions) + functor(const std::vector &funcs, const Type_Conversions *t_conversions) { FunctionType *p=nullptr; return detail::build_function_caller_helper(p, funcs, t_conversions); } - /** - * Build a function caller for a particular Proxy_Function object - * useful in the case that a function is being pass out from scripting back - * into code - * example: - * void my_function(Proxy_Function f) - * { - * std::function local_f = - * build_function_caller(f); - * } - * \returns A std::function object for dispatching - * \param[in] func A function to execute. - */ + /// Build a function caller for a particular Proxy_Function object + /// useful in the case that a function is being pass out from scripting back + /// into code + /// example: + /// void my_function(Proxy_Function f) + /// { + /// std::function local_f = + /// build_function_caller(f); + /// } + /// \returns A std::function object for dispatching + /// \param[in] func A function to execute. template std::function - functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions) + functor(Const_Proxy_Function func, const Type_Conversions *t_conversions) { - std::vector funcs; - funcs.push_back(func); - return functor(funcs, t_conversions); + return functor(std::vector({func}), t_conversions); } - /** - * Helper for automatically unboxing a Boxed_Value that contains a function object - * and creating a typesafe C++ function caller from it. - */ + /// Helper for automatically unboxing a Boxed_Value that contains a function object + /// and creating a typesafe C++ function caller from it. template std::function - functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions) + functor(const Boxed_Value &bv, const Type_Conversions *t_conversions) { return functor(boxed_cast(bv, t_conversions), t_conversions); } } namespace detail{ - /** - * Cast helper to handle automatic casting to const std::function & - */ + /// Cast helper to handle automatic casting to const std::function & template struct Cast_Helper &> { typedef std::function Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { @@ -98,15 +88,13 @@ namespace chaiscript } }; - /** - * Cast helper to handle automatic casting to std::function - */ + /// Cast helper to handle automatic casting to std::function template struct Cast_Helper > { typedef std::function Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { @@ -117,15 +105,13 @@ namespace chaiscript } }; - /** - * Cast helper to handle automatic casting to const std::function - */ + /// Cast helper to handle automatic casting to const std::function template struct Cast_Helper > { typedef std::function Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index e6cd465..ee1d1bd 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -17,7 +17,7 @@ #include "boxed_cast.hpp" #include "boxed_number.hpp" #include "boxed_value.hpp" -#include "dynamic_cast_conversion.hpp" +#include "type_conversions.hpp" #include "proxy_functions.hpp" namespace chaiscript @@ -26,15 +26,13 @@ namespace chaiscript { namespace detail { - /** - * Internal helper class for handling the return - * value of a build_function_caller - */ + /// Internal helper class for handling the return + /// value of a build_function_caller template struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { return boxed_cast(dispatch::dispatch(t_funcs, params, t_conversions)); } @@ -47,7 +45,7 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as(); } @@ -61,7 +59,7 @@ namespace chaiscript struct Function_Caller_Ret { static void call(const std::vector &t_funcs, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { dispatch::dispatch(t_funcs, params, t_conversions); } @@ -73,7 +71,7 @@ namespace chaiscript template struct Build_Function_Caller_Helper { - Build_Function_Caller_Helper(std::vector t_funcs, const Dynamic_Cast_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) { @@ -81,7 +79,7 @@ namespace chaiscript Ret operator()(Param...param) { - return Function_Caller_Ret::value>::call(m_funcs, { + 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)... }, m_conversions @@ -90,13 +88,13 @@ namespace chaiscript } std::vector m_funcs; - Dynamic_Cast_Conversions m_conversions; + Type_Conversions m_conversions; }; template - std::function build_function_caller_helper(Ret (Params...), const std::vector &funcs, const Dynamic_Cast_Conversions *t_conversions) + std::function build_function_caller_helper(Ret (Params...), const std::vector &funcs, const Type_Conversions *t_conversions) { if (funcs.size() == 1) { @@ -112,7 +110,7 @@ namespace chaiscript // we cannot make any other guesses or assumptions really, so continuing } - return std::function(Build_Function_Caller_Helper(funcs, t_conversions?*t_conversions:Dynamic_Cast_Conversions())); + return std::function(Build_Function_Caller_Helper(funcs, t_conversions?*t_conversions:Type_Conversions())); } } } diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index cc24fdf..8f2ebfe 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -48,6 +48,15 @@ namespace chaiscript } }; + template + struct Handle_Return + { + static Boxed_Value handle(const Ret *p) + { + return Boxed_Value(p); + } + }; + template struct Handle_Return &> { diff --git a/include/chaiscript/dispatchkit/operators.hpp b/include/chaiscript/dispatchkit/operators.hpp index ed64b2c..353035e 100644 --- a/include/chaiscript/dispatchkit/operators.hpp +++ b/include/chaiscript/dispatchkit/operators.hpp @@ -8,6 +8,7 @@ #define CHAISCRIPT_OPERATORS_HPP_ #include "../chaiscript_defines.hpp" +#include "register_function.hpp" namespace chaiscript { @@ -15,442 +16,446 @@ namespace chaiscript { namespace operators { - template - Ret assign(L l, R r) - { - return (l = r); - } + namespace detail + { + /// \todo make this return a decltype once we drop gcc 4.6 + template + auto assign(L l, R r) -> L& + { + return (l = r); + } - template - Ret assign_bitwise_and(L l, R r) - { - return (l &= r); - } + template + auto assign_bitwise_and(L l, R r) -> decltype((l &= r)) + { + return (l &= r); + } - template - Ret assign_xor(L l, R r) - { - return (l ^= r); - } + template + auto assign_xor(L l, R r) -> decltype((l^=r)) + { + return (l ^= r); + } - template - Ret assign_bitwise_or(L l, R r) - { - return (l |= r); - } + template + auto assign_bitwise_or(L l, R r) -> decltype((l |= r)) + { + return (l |= r); + } - template - Ret assign_difference(L l, R r) - { - return (l -= r); - } + template + auto assign_difference(L l, R r) -> decltype(( l -= r)) + { + return (l -= r); + } - template - Ret assign_left_shift(L l, R r) - { - return (l <<= r); - } + template + auto assign_left_shift(L l, R r) -> decltype(( l <<= r)) + { + return (l <<= r); + } - template - Ret assign_product(L l, R r) - { - return (l *= r); - } + template + auto assign_product(L l, R r) -> decltype(( l *= r )) + { + return (l *= r); + } - template - Ret assign_quotient(L l, R r) - { - return (l /= r); - } + template + auto assign_quotient(L l, R r) -> decltype(( l /= r )) + { + return (l /= r); + } - template - Ret assign_remainder(L l, R r) - { - return (l %= r); - } + template + auto assign_remainder(L l, R r) -> decltype(( l %= r )) + { + return (l %= r); + } - template - Ret assign_right_shift(L l, R r) - { - return (l >>= r); - } + template + auto assign_right_shift(L l, R r) -> decltype(( l >>= r)) + { + return (l >>= r); + } - template - Ret assign_sum(L l, R r) - { - return (l += r); - } + /// \todo make this return a decltype once we drop gcc 4.6 + template + auto assign_sum(L l, R r) -> L& + { + return (l += r); + } - template - Ret prefix_decrement(L l) - { - return (--l); - } + template + auto prefix_decrement(L l) -> decltype(( --l )) + { + return (--l); + } - template - Ret prefix_increment(L l) - { - return (++l); - } + template + auto prefix_increment(L l) -> decltype(( ++l )) + { + return (++l); + } - template - Ret equal(L l, R r) - { - return (l == r); - } + template + auto equal(L l, R r) -> decltype(( l == r )) + { + return (l == r); + } - template - Ret greater_than(L l, R r) - { - return (l > r); - } + template + auto greater_than(L l, R r) -> decltype(( l > r )) + { + return (l > r); + } - template - Ret greater_than_equal(L l, R r) - { - return (l >= r); - } + template + auto greater_than_equal(L l, R r) -> decltype(( l >= r )) + { + return (l >= r); + } - template - Ret less_than(L l, R r) - { - return (l < r); - } + template + auto less_than(L l, R r) -> decltype(( l < r )) + { + return (l < r); + } - template - Ret less_than_equal(L l, R r) - { - return (l <= r); - } + template + auto less_than_equal(L l, R r) -> decltype(( l <= r )) + { + return (l <= r); + } - template - Ret logical_compliment(L l) - { - return (!l); - } + template + auto logical_compliment(L l) -> decltype(( !l )) + { + return (!l); + } - template - Ret not_equal(L l, R r) - { - return (l != r); - } + template + auto not_equal(L l, R r) -> decltype(( l != r )) + { + return (l != r); + } - template - Ret addition(L l, R r) - { - return (l + r); - } + template + auto addition(L l, R r) -> decltype(( l + r )) + { + return (l + r); + } - template - Ret unary_plus(L l) - { - return (+l); - } + template + auto unary_plus(L l) -> decltype(( +l )) + { + return (+l); + } - template - Ret subtraction(L l, R r) - { - return (l - r); - } + template + auto subtraction(L l, R r) -> decltype(( l - r )) + { + return (l - r); + } - template - Ret unary_minus(L l) - { + template + auto unary_minus(L l) -> decltype(( -l )) + { #ifdef CHAISCRIPT_MSVC #pragma warning(push) #pragma warning(disable : 4146) - return (-l); + return (-l); #pragma warning(pop) #else - return (-l); + return (-l); #endif - } + } - template - Ret bitwise_and(L l, R r) - { - return (l & r); - } + template + auto bitwise_and(L l, R r) -> decltype(( l & r )) + { + return (l & r); + } - template - Ret bitwise_compliment(L l) - { - return (~l); - } + template + auto bitwise_compliment(L l) -> decltype(( ~l )) + { + return (~l); + } - template - Ret bitwise_xor(L l, R r) - { - return (l ^ r); - } + template + auto bitwise_xor(L l, R r) -> decltype(( l ^ r )) + { + return (l ^ r); + } - template - Ret bitwise_or(L l, R r) - { - return (l | r); - } + template + auto bitwise_or(L l, R r) -> decltype(( l | r )) + { + return (l | r); + } - template - Ret division(L l, R r) - { - return (l / r); - } + template + auto division(L l, R r) -> decltype(( l / r )) + { + return (l / r); + } - template - Ret left_shift(L l, R r) - { - return l << r; - } + template + auto left_shift(L l, R r) -> decltype(( l << r )) + { + return l << r; + } - template - Ret multiplication(L l, R r) - { - return l * r; - } + template + auto multiplication(L l, R r) -> decltype(( l * r )) + { + return l * r; + } - template - Ret remainder(L l, R r) - { - return (l % r); - } - - template - Ret right_shift(L l, R r) - { - return (l >> r); - } + template + auto remainder(L l, R r) -> decltype(( l % r )) + { + return (l % r); + } + template + auto right_shift(L l, R r) -> decltype(( l >> r )) + { + return (l >> r); + } + } template ModulePtr assign(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign), "="); + m->add(chaiscript::fun(&detail::assign), "="); return m; } template ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_bitwise_and), "&="); + m->add(chaiscript::fun(&detail::assign_bitwise_and), "&="); return m; } template ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_xor), "^="); + m->add(chaiscript::fun(&detail::assign_xor), "^="); return m; } template ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_bitwise_or), "|="); + m->add(chaiscript::fun(&detail::assign_bitwise_or), "|="); return m; } template ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_difference), "-="); + m->add(chaiscript::fun(&detail::assign_difference), "-="); return m; } template ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_left_shift), "<<="); + m->add(chaiscript::fun(&detail::assign_left_shift), "<<="); return m; } template ModulePtr assign_product(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_product), "*="); + m->add(chaiscript::fun(&detail::assign_product), "*="); return m; } template ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_quotient), "/="); + m->add(chaiscript::fun(&detail::assign_quotient), "/="); return m; } template ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_remainder), "%="); + m->add(chaiscript::fun(&detail::assign_remainder), "%="); return m; } template ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_right_shift), ">>="); + m->add(chaiscript::fun(&detail::assign_right_shift), ">>="); return m; } template ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&assign_sum), "+="); + m->add(chaiscript::fun(&detail::assign_sum), "+="); return m; } template ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&prefix_decrement), "--"); + m->add(chaiscript::fun(&detail::prefix_decrement), "--"); return m; } template ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&prefix_increment), "++"); + m->add(chaiscript::fun(&detail::prefix_increment), "++"); return m; } template ModulePtr equal(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&equal), "=="); + m->add(chaiscript::fun(&detail::equal), "=="); return m; } template ModulePtr greater_than(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&greater_than), ">"); + m->add(chaiscript::fun(&detail::greater_than), ">"); return m; } template ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&greater_than_equal), ">="); + m->add(chaiscript::fun(&detail::greater_than_equal), ">="); return m; } template ModulePtr less_than(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&less_than), "<"); + m->add(chaiscript::fun(&detail::less_than), "<"); return m; } template ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&less_than_equal), "<="); + m->add(chaiscript::fun(&detail::less_than_equal), "<="); return m; } template ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&logical_compliment), "!"); + m->add(chaiscript::fun(&detail::logical_compliment), "!"); return m; } template ModulePtr not_equal(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(¬_equal), "!="); + m->add(chaiscript::fun(&detail::not_equal), "!="); return m; } template ModulePtr addition(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&addition), "+"); + m->add(chaiscript::fun(&detail::addition), "+"); return m; } template ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&unary_plus), "+"); + m->add(chaiscript::fun(&detail::unary_plus), "+"); return m; } template ModulePtr subtraction(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&subtraction), "-"); + m->add(chaiscript::fun(&detail::subtraction), "-"); return m; } template ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&unary_minus), "-"); + m->add(chaiscript::fun(&detail::unary_minus), "-"); return m; } template ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&bitwise_and), "&"); + m->add(chaiscript::fun(&detail::bitwise_and), "&"); return m; } template ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&bitwise_compliment), "~"); + m->add(chaiscript::fun(&detail::bitwise_compliment), "~"); return m; } template ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&bitwise_xor), "^"); + m->add(chaiscript::fun(&detail::bitwise_xor), "^"); return m; } template ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&bitwise_or), "|"); + m->add(chaiscript::fun(&detail::bitwise_or), "|"); return m; } template ModulePtr division(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&division), "/"); + m->add(chaiscript::fun(&detail::division), "/"); return m; } template ModulePtr left_shift(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&left_shift), "<<"); + m->add(chaiscript::fun(&detail::left_shift), "<<"); return m; } template ModulePtr multiplication(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&multiplication), "*"); + m->add(chaiscript::fun(&detail::multiplication), "*"); return m; } template ModulePtr remainder(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&remainder), "%"); + m->add(chaiscript::fun(&detail::remainder), "%"); return m; } template ModulePtr right_shift(ModulePtr m = ModulePtr(new Module())) { - m->add(fun(&right_shift), ">>"); + m->add(chaiscript::fun(&detail::right_shift), ">>"); return m; } } diff --git a/include/chaiscript/dispatchkit/proxy_constructors.hpp b/include/chaiscript/dispatchkit/proxy_constructors.hpp index 0c56f95..64d2a93 100644 --- a/include/chaiscript/dispatchkit/proxy_constructors.hpp +++ b/include/chaiscript/dispatchkit/proxy_constructors.hpp @@ -21,7 +21,7 @@ namespace chaiscript template std::shared_ptr constructor_(Params ... params) { - return std::shared_ptr(new Class(params...)); + return std::make_shared(params...); } template diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 4f9f471..fba9b4f 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -26,7 +26,7 @@ #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace exception { class bad_boxed_cast; struct arity_error; @@ -55,7 +55,7 @@ namespace chaiscript public: virtual ~Proxy_Function_Base() {} - Boxed_Value operator()(const std::vector ¶ms, const chaiscript::Dynamic_Cast_Conversions &t_conversions) const + Boxed_Value operator()(const std::vector ¶ms, const chaiscript::Type_Conversions &t_conversions) const { Boxed_Value bv = do_call(params, t_conversions); return bv; @@ -63,12 +63,12 @@ namespace chaiscript /// Returns a vector containing all of the types of the parameters the function returns/takes /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned - /// value containes exactly 1 Type_Info object: the return type + /// value contains exactly 1 Type_Info object: the return type /// \returns the types of all parameters. const std::vector &get_param_types() const { return m_types; } virtual bool operator==(const Proxy_Function_Base &) const = 0; - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0; + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const = 0; bool has_arithmetic_param() const { @@ -82,15 +82,13 @@ namespace chaiscript //! Return true if the function is a possible match //! to the passed in values - bool filter(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const + bool filter(const std::vector &vals, const Type_Conversions &t_conversions) const { - int arity = get_arity(); - - if (arity < 0) + if (m_arity < 0) { return true; - } else if (size_t(arity) == vals.size()) { - if (arity == 0) + } else if (size_t(m_arity) == vals.size()) { + if (m_arity == 0) { return true; } else { @@ -102,11 +100,14 @@ namespace chaiscript } /// \returns the number of arguments the function takes or -1 if it is variadic - virtual int get_arity() const = 0; + int get_arity() const + { + return m_arity; + } virtual std::string annotation() const = 0; - static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) + static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions) { if (ti.is_undef() || ti.bare_equal(user_type()) @@ -114,7 +115,7 @@ namespace chaiscript && (ti.bare_equal(user_type()) || ti.bare_equal(bv.get_type_info()) || bv.get_type_info().bare_equal(user_type >()) - || t_conversions.dynamic_cast_converts(ti, bv.get_type_info()) + || t_conversions.converts(ti, bv.get_type_info()) ) ) ) @@ -125,10 +126,10 @@ namespace chaiscript } } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const = 0; + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const = 0; - Proxy_Function_Base(std::vector t_types) - : m_types(std::move(t_types)), m_has_arithmetic_param(false) + Proxy_Function_Base(std::vector t_types, int t_arity) + : m_types(std::move(t_types)), m_has_arithmetic_param(false), m_arity(t_arity) { for (size_t i = 1; i < m_types.size(); ++i) { @@ -141,7 +142,7 @@ namespace chaiscript } - virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const + virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const { const std::vector &types = get_param_types(); @@ -175,14 +176,14 @@ namespace chaiscript std::vector m_types; bool m_has_arithmetic_param; - + int m_arity; }; } /// \brief Common typedef used for passing of any registered function in ChaiScript typedef std::shared_ptr Proxy_Function; - /// \brief Const version of Proxy_Function chaiscript. Points to a const Proxy_Function. This is how most registered functions + /// \brief Const version of Proxy_Function. Points to a const Proxy_Function. This is how most registered functions /// are handled internally. typedef std::shared_ptr Const_Proxy_Function; @@ -216,7 +217,7 @@ namespace chaiscript AST_NodePtr t_parsenode = AST_NodePtr(), std::string t_description = "", Proxy_Function t_guard = Proxy_Function()) - : Proxy_Function_Base(build_param_type_list(t_arity)), + : Proxy_Function_Base(build_param_type_list(t_arity), t_arity), m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)) { } @@ -233,16 +234,12 @@ namespace chaiscript && !this->m_guard && !prhs->m_guard); } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return (m_arity < 0 || vals.size() == size_t(m_arity)) && test_guard(vals, t_conversions); } - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return m_arity; - } Proxy_Function get_guard() const { @@ -260,7 +257,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + 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)) { @@ -278,7 +275,7 @@ namespace chaiscript } private: - bool test_guard(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const + bool test_guard(const std::vector ¶ms, const Type_Conversions &t_conversions) const { if (m_guard) { @@ -338,8 +335,8 @@ namespace chaiscript public: Bound_Function(const Const_Proxy_Function &t_f, const std::vector &t_args) - : Proxy_Function_Base(build_param_type_info(t_f, t_args)), - m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast(get_param_types().size())-1) + : Proxy_Function_Base(build_param_type_info(t_f, t_args), (t_f->get_arity()<0?-1:static_cast(build_param_type_info(t_f, t_args).size())-1)), + m_f(t_f), m_args(t_args) { assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast(m_args.size())); } @@ -351,7 +348,7 @@ namespace chaiscript virtual ~Bound_Function() {} - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return m_f->call_match(build_param_list(vals), t_conversions); } @@ -395,11 +392,6 @@ namespace chaiscript return args; } - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return m_arity; - } - virtual std::string annotation() const CHAISCRIPT_OVERRIDE { return "Bound: " + m_f->annotation(); @@ -429,7 +421,7 @@ namespace chaiscript return retval; } - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return (*m_f)(build_param_list(params), t_conversions); } @@ -437,30 +429,24 @@ namespace chaiscript private: Const_Proxy_Function m_f; std::vector m_args; - int m_arity; }; class Proxy_Function_Impl_Base : public Proxy_Function_Base { public: - Proxy_Function_Impl_Base(std::vector t_types) - : Proxy_Function_Base(std::move(t_types)) + Proxy_Function_Impl_Base(const std::vector &t_types) + : Proxy_Function_Base(t_types, static_cast(t_types.size()) - 1) { } virtual ~Proxy_Function_Impl_Base() {} - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return static_cast(m_types.size()) - 1; - } - virtual std::string annotation() const CHAISCRIPT_OVERRIDE { return ""; } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (int(vals.size()) != get_arity()) { @@ -470,7 +456,7 @@ namespace chaiscript return compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions); } - virtual bool compare_types_with_cast(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0; + virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const = 0; }; /** @@ -490,7 +476,7 @@ namespace chaiscript virtual ~Proxy_Function_Impl() {} - virtual bool compare_types_with_cast(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + 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); } @@ -506,7 +492,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const { return detail::Do_Call::result_type>::go(m_f, params, t_conversions); } @@ -524,8 +510,8 @@ namespace chaiscript { public: Attribute_Access(T Class::* t_attr) - : Proxy_Function_Base(param_types()), - m_attr(t_attr) + : Proxy_Function_Base(param_types(), 1), + m_attr(t_attr) { } @@ -543,13 +529,7 @@ namespace chaiscript } } - - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return 1; - } - - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE { if (vals.size() != 1) { @@ -565,7 +545,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (params.size() == 1) { @@ -622,7 +602,7 @@ namespace chaiscript { template bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector &plist, - const Dynamic_Cast_Conversions &t_conversions) + const Type_Conversions &t_conversions) { if (t_func->get_arity() != static_cast(plist.size())) { @@ -650,7 +630,7 @@ namespace chaiscript template Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector &plist, - const Dynamic_Cast_Conversions &t_conversions) + const Type_Conversions &t_conversions) { InItr orig(begin); @@ -712,17 +692,42 @@ namespace chaiscript * each function against the set of parameters, in order, until a matching * function is found or throw dispatch_error if no matching function is found */ - template - Boxed_Value dispatch(InItr begin, const InItr &end, - const std::vector &plist, const Dynamic_Cast_Conversions &t_conversions) + template + Boxed_Value dispatch(const Funcs &funcs, + const std::vector &plist, const Type_Conversions &t_conversions) { - InItr orig(begin); - while (begin != end) + + std::multimap ordered_funcs; + + for (const auto &func : funcs) + { + size_t numdiffs = 0; + const auto arity = func->get_arity(); + + if (arity == -1) + { + numdiffs = plist.size(); + } else if (arity == static_cast(plist.size())) { + for (size_t i = 0; i < plist.size(); ++i) + { + if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info())) + { + ++numdiffs; + } + } + } else { + continue; + } + + ordered_funcs.insert(std::make_pair(numdiffs, func.get())); + } + + for (const auto &func : ordered_funcs ) { try { - if ((*begin)->filter(plist, t_conversions)) + if (func.second->filter(plist, t_conversions)) { - return (*(*begin))(plist, t_conversions); + return (*(func.second))(plist, t_conversions); } } catch (const exception::bad_boxed_cast &) { //parameter failed to cast, try again @@ -732,22 +737,9 @@ namespace chaiscript //guard failed to allow the function to execute, //try again } - ++begin; } - return detail::dispatch_with_conversions(orig, end, plist, t_conversions); - } - - /** - * Take a vector of functions and a vector of parameters. Attempt to execute - * each function against the set of parameters, in order, until a matching - * function is found or throw dispatch_error if no matching function is found - */ - template - Boxed_Value dispatch(const Funcs &funcs, - const std::vector &plist, const Dynamic_Cast_Conversions &t_conversions) - { - return dispatch::dispatch(funcs.begin(), funcs.end(), plist, t_conversions); + return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions); } } } diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index 1660a27..744d40b 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -20,7 +20,7 @@ #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace exception { class bad_boxed_cast; } // namespace exception @@ -53,29 +53,6 @@ namespace chaiscript { namespace detail { - template - struct Build_Param_Type_List; - - template - struct Build_Param_Type_List - { - static void build(std::vector &t_params) - { - t_params.push_back(chaiscript::detail::Get_Type_Info::get()); - Build_Param_Type_List::build(t_params); - } - }; - - // 0th case - template<> - struct Build_Param_Type_List<> - { - static void build(std::vector &) - { - } - }; - - /** * Used by Proxy_Function_Impl to return a list of all param types * it contains. @@ -83,12 +60,8 @@ namespace chaiscript template std::vector build_param_type_list(Ret (*)(Params...)) { - /// \todo this code was previously using { chaiscript::detail::Get_Type_Info::get()... } - /// but this seems to indicate another bug with MSVC's uniform initializer lists - std::vector params; - params.push_back(chaiscript::detail::Get_Type_Info::get()); - Build_Param_Type_List::build(params); - return params; + /// \note somehow this is responsible for a large part of the code generation + return { user_type(), user_type()... }; } @@ -99,7 +72,7 @@ namespace chaiscript template struct Try_Cast { - static void do_try(const std::vector ¶ms, int generation, const Dynamic_Cast_Conversions &t_conversions) + static void do_try(const std::vector ¶ms, int generation, const Type_Conversions &t_conversions) { boxed_cast(params[generation], &t_conversions); Try_Cast::do_try(params, generation+1, t_conversions); @@ -110,7 +83,7 @@ namespace chaiscript template<> struct Try_Cast<> { - static void do_try(const std::vector &, int, const Dynamic_Cast_Conversions &) + static void do_try(const std::vector &, int, const Type_Conversions &) { } }; @@ -118,12 +91,12 @@ namespace chaiscript /** * Used by Proxy_Function_Impl to determine if it is equivalent to another - * Proxy_Function_Impl object. This function is primarly used to prevent + * 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(Ret (*)(Params...), - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { try { Try_Cast::do_try(params, 0, t_conversions); @@ -140,7 +113,7 @@ namespace chaiscript template static Ret do_call(const std::function &f, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) + 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]); } @@ -155,7 +128,7 @@ namespace chaiscript #endif template static Ret do_call(const std::function &f, - const std::vector &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) + const std::vector &, const Type_Conversions &t_conversions, InnerParams &&... innerparams) { return f(boxed_cast(std::forward(innerparams), &t_conversions)...); } @@ -166,13 +139,13 @@ namespace chaiscript /** * Used by Proxy_Function_Impl to perform typesafe execution of a function. - * The function attempts to unbox each paramter to the expected type. + * 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 std::function &f, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { if (params.size() == sizeof...(Params)) { @@ -198,7 +171,7 @@ namespace chaiscript struct Do_Call { template - static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) { return Handle_Return::handle(call_func(fun, params, t_conversions)); } @@ -208,7 +181,7 @@ namespace chaiscript struct Do_Call { template - static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) { call_func(fun, params, t_conversions); return Handle_Return::handle(); diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp new file mode 100644 index 0000000..b238b97 --- /dev/null +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -0,0 +1,447 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2014, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ +#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include "../chaiscript_threading.hpp" +#include "bad_boxed_cast.hpp" +#include "boxed_cast_helper.hpp" +#include "boxed_value.hpp" +#include "type_info.hpp" + +namespace chaiscript +{ + namespace exception + { + class bad_boxed_dynamic_cast : public bad_boxed_cast + { + public: + bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, + const std::string &t_what) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(t_from, t_to, t_what) + { + } + + bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(t_from, t_to) + { + } + + bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(w) + { + } + + virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {} + }; + + class bad_boxed_type_cast : public bad_boxed_cast + { + public: + bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, + const std::string &t_what) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(t_from, t_to, t_what) + { + } + + bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(t_from, t_to) + { + } + + bad_boxed_type_cast(const std::string &w) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(w) + { + } + + virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {} + }; + } + + + namespace detail + { + class Type_Conversion_Base + { + public: + virtual Boxed_Value convert(const Boxed_Value &from) const = 0; + virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0; + + const Type_Info &to() const + { + return m_to; + } + const Type_Info &from() const + { + return m_from; + } + + protected: + Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from) + : m_to(t_to), m_from(t_from) + { + } + + virtual ~Type_Conversion_Base() {} + + private: + Type_Info m_to; + Type_Info m_from; + + }; + + template + class Dynamic_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()) + { + std::shared_ptr data + = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr)); + if (!data) + { + throw std::bad_cast(); + } + + return Boxed_Value(data); + } else { + std::shared_ptr data + = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr)); + + if (!data) + { + throw std::bad_cast(); + } + + return Boxed_Value(data); + } + } 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 = dynamic_cast(d); + return Boxed_Value(std::cref(data)); + } else { + From &d = detail::Cast_Helper::cast(t_from, nullptr); + To &data = dynamic_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_Conversion_Impl : public Type_Conversion_Base + { + public: + Dynamic_Conversion_Impl() + : Type_Conversion_Base(chaiscript::user_type(), chaiscript::user_type()) + { + } + + virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE + { + return Dynamic_Caster::cast(t_base); + } + + virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE + { + return Dynamic_Caster::cast(t_derived); + } + }; + + + template + class Type_Conversion_Impl : public Type_Conversion_Base + { + public: + Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) + : Type_Conversion_Base(std::move(t_to), std::move(t_from)), + m_func(std::move(t_func)) + { + } + + virtual Boxed_Value convert_down(const Boxed_Value &) const CHAISCRIPT_OVERRIDE + { + throw chaiscript::exception::bad_boxed_type_cast("No conversion exists"); + } + + virtual Boxed_Value convert(const Boxed_Value &t_from) const CHAISCRIPT_OVERRIDE + { + /// \todo better handling of errors from the conversion function + return m_func(t_from); + } + + private: + Callable m_func; + }; + + } + + class Type_Conversions + { + public: + struct Less_Than + { + bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const + { + return *t_lhs != *t_rhs && t_lhs->before(*t_rhs); + } + }; + + Type_Conversions() + : m_num_types(0), + m_thread_cache(this), + m_conversion_saves(this) + { + } + + Type_Conversions(const Type_Conversions &t_other) + : m_conversions(t_other.get_conversions()), m_num_types(m_conversions.size()), + m_thread_cache(this), + m_conversion_saves(this) + + { + } + + const std::set &thread_cache() const + { + auto &cache = *m_thread_cache; + if (cache.size() != m_num_types) + { + chaiscript::detail::threading::shared_lock l(m_mutex); + cache = m_convertableTypes; + } + + return cache; + } + + void add_conversion(const std::shared_ptr &conversion) + { + chaiscript::detail::threading::unique_lock l(m_mutex); + /// \todo error if a conversion already exists + m_conversions.insert(conversion); + m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()}); + m_num_types = m_convertableTypes.size(); + } + + template + bool convertable_type() const + { + return thread_cache().count(user_type().bare_type_info()) != 0; + } + + template + bool converts() const + { + return converts(user_type(), user_type()); + } + + bool converts(const Type_Info &to, const Type_Info &from) const + { + 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); + } else { + return false; + } + + } + + template + Boxed_Value boxed_type_conversion(const Boxed_Value &from) const + { + try { + Boxed_Value ret = get_conversion(user_type(), from.get_type_info())->convert(from); + if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret); + return ret; + } catch (const std::out_of_range &) { + throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion"); + } catch (const std::bad_cast &) { + throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation"); + } + } + + template + Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const + { + try { + Boxed_Value ret = get_conversion(to.get_type_info(), user_type())->convert_down(to); + if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret); + return ret; + } catch (const std::out_of_range &) { + throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion"); + } catch (const std::bad_cast &) { + throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation"); + } + } + + void enable_conversion_saves(bool t_val) + { + m_conversion_saves->enabled = t_val; + } + + std::vector take_saves() + { + std::vector ret; + std::swap(ret, m_conversion_saves->saves); + return ret; + } + + 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(); + } + + std::shared_ptr get_conversion(const Type_Info &to, const Type_Info &from) const + { + chaiscript::detail::threading::shared_lock l(m_mutex); + + auto itr = find(to, from); + + if (itr != m_conversions.end()) + { + return *itr; + } else { + throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name()); + } + } + + private: + std::set >::const_iterator find( + 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) + { + return conversion->to().bare_equal(to) && conversion->from().bare_equal(from); + } + ); + } + + std::set> get_conversions() const + { + chaiscript::detail::threading::shared_lock l(m_mutex); + + return m_conversions; + } + + + struct Conversion_Saves + { + Conversion_Saves() + : enabled(false) + {} + + bool enabled; + std::vector saves; + }; + + mutable chaiscript::detail::threading::shared_mutex m_mutex; + std::set> m_conversions; + std::set m_convertableTypes; + std::atomic_size_t m_num_types; + chaiscript::detail::threading::Thread_Storage> m_thread_cache; + chaiscript::detail::threading::Thread_Storage m_conversion_saves; + }; + + typedef std::shared_ptr Type_Conversion; + + /// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you + /// want automatic conversions up your inheritance hierarchy. + /// + /// Create a new to class registration for applying to a module or to the ChaiScript engine + /// Currently, due to limitations in module loading on Windows, and for the sake of portability, + /// if you have a type that is introduced in a loadable module and is used by multiple modules + /// (through a tertiary dll that is shared between the modules, static linking the new type + /// into both loadable modules would not be portable), you need to register the type + /// relationship in all modules that use the newly added type in a polymorphic way. + /// + /// Example: + /// \code + /// class Base + /// {}; + /// class Derived : public Base + /// {}; + /// + /// chaiscript::ChaiScript chai; + /// chai.add(chaiscript::to_class()); + /// \endcode + /// + template + Type_Conversion base_class() + { + //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 std::make_shared>(); + } + + template + Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, + const Callable &t_func) + { + return std::make_shared>(t_from, t_to, t_func); + } + + template + Type_Conversion type_conversion(const Callable &t_function) + { + auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value { + // not even attempting to call boxed_cast so that we don't get caught in some call recursion + return chaiscript::Boxed_Value(t_function(detail::Cast_Helper::cast(t_bv, nullptr))); + }; + + return std::make_shared>(user_type(), user_type(), func); + } + + template + Type_Conversion type_conversion() + { + static_assert(std::is_convertible::value, "Types are not automatically convertible"); + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + // not even attempting to call boxed_cast so that we don't get caught in some call recursion + std::cout << " Type conversion to : " << typeid(To).name() << " from " << typeid(From).name() << std::endl; + auto &&from = detail::Cast_Helper::cast(t_bv, nullptr); + std::cout << "Ptr" << static_cast(from) << std::endl; + std::cout << "Ptr" << from << std::endl; + + To to(from); + return chaiscript::Boxed_Value(to); + }; + + return std::make_shared>(user_type(), user_type(), func); + } + +} + + +#endif diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 4944e80..2cf6455 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -25,6 +25,7 @@ namespace chaiscript }; } + /// \brief Compile time deduced information about a type class Type_Info { @@ -38,7 +39,7 @@ namespace chaiscript { } - Type_Info() + CHAISCRIPT_CONSTEXPR Type_Info() : m_type_info(nullptr), m_bare_type_info(nullptr), m_is_const(false), m_is_reference(false), m_is_pointer(false), m_is_void(false), m_is_arithmetic(false), @@ -46,63 +47,49 @@ namespace chaiscript { } - Type_Info(const Type_Info &ti) - : m_type_info(ti.m_type_info), - m_bare_type_info(ti.m_bare_type_info), - m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference), - m_is_pointer(ti.m_is_pointer), - m_is_void(ti.m_is_void), m_is_arithmetic(ti.m_is_arithmetic), - m_is_undef(ti.m_is_undef) - { - } +#if !defined(_MSC_VER) || _MSC_VER != 1800 + Type_Info(Type_Info&&) = default; + Type_Info& operator=(Type_Info&&) = default; +#endif - Type_Info &operator=(const Type_Info &ti) - { - m_type_info = ti.m_type_info; - m_bare_type_info = ti.m_bare_type_info; - m_is_const = ti.m_is_const; - m_is_reference = ti.m_is_reference; - m_is_pointer = ti.m_is_pointer; - m_is_void = ti.m_is_void; - m_is_arithmetic = ti.m_is_arithmetic; - m_is_undef = ti.m_is_undef; - return *this; - } + Type_Info(const Type_Info&) = default; + Type_Info& operator=(const Type_Info&) = default; - bool operator<(const Type_Info &ti) const + + CHAISCRIPT_CONSTEXPR bool operator<(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT { return m_type_info < ti.m_type_info; } - bool operator==(const Type_Info &ti) const + CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT { return ti.m_type_info == m_type_info || (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info); } - bool operator==(const std::type_info &ti) const + CHAISCRIPT_CONSTEXPR bool operator==(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT { return m_type_info != nullptr && (*m_type_info) == ti; } - bool bare_equal(const Type_Info &ti) const + CHAISCRIPT_CONSTEXPR bool bare_equal(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT { return ti.m_bare_type_info == m_bare_type_info || (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info); } - bool bare_equal_type_info(const std::type_info &ti) const + CHAISCRIPT_CONSTEXPR bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT { return m_bare_type_info != nullptr && (*m_bare_type_info) == ti; } - bool is_const() const { return m_is_const; } - bool is_reference() const { return m_is_reference; } - bool is_void() const { return m_is_void; } - bool is_arithmetic() const { return m_is_arithmetic; } - bool is_undef() const { return m_is_undef || m_bare_type_info == nullptr; } - bool is_pointer() const { return m_is_pointer; } + CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; } + 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_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; } std::string name() const { @@ -114,7 +101,7 @@ namespace chaiscript } } - std::string bare_name() const + std::string bare_name() const { if (m_bare_type_info) { @@ -124,6 +111,11 @@ namespace chaiscript } } + CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const + { + return m_bare_type_info; + } + private: const std::type_info *m_type_info; const std::type_info *m_bare_type_info; @@ -215,11 +207,6 @@ namespace chaiscript } }; - template - struct Stripped_Type - { - typedef typename Bare_Type::type>::type type; - }; } /// \brief Creates a Type_Info object representing the type passed in diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 09987fa..d15c2d9 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -69,6 +69,7 @@ namespace chaiscript /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree typedef std::shared_ptr AST_NodePtr; + typedef std::shared_ptr AST_NodePtr_Const; /// \brief Classes which may be thrown during error cases when ChaiScript is executing. @@ -82,7 +83,7 @@ namespace chaiscript File_Position end_position; std::string filename; std::string detail; - std::vector call_stack; + std::vector call_stack; eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, const std::vector &t_parameters, const std::vector &t_functions, @@ -425,7 +426,7 @@ namespace chaiscript /// Prints the contents of an AST node, including its children, recursively - std::string to_string(const std::string &t_prepend = "") { + std::string to_string(const std::string &t_prepend = "") const { std::ostringstream oss; oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " @@ -437,7 +438,7 @@ namespace chaiscript return oss.str(); } - Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) + Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) const { try { return eval_internal(t_e); @@ -466,7 +467,7 @@ namespace chaiscript virtual ~AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const { throw std::runtime_error("Undispatched ast_node (internal error)"); } @@ -548,6 +549,11 @@ namespace chaiscript m_de.save_function_params(t_params); } + void save_params(std::initializer_list t_params) + { + m_de.save_function_params(std::move(t_params)); + } + private: diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 0513194..b5393c5 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -26,7 +26,7 @@ #include "../dispatchkit/boxed_cast_helper.hpp" #include "../dispatchkit/boxed_value.hpp" #include "../dispatchkit/dispatchkit.hpp" -#include "../dispatchkit/dynamic_cast_conversion.hpp" +#include "../dispatchkit/type_conversions.hpp" #include "../dispatchkit/proxy_functions.hpp" #include "chaiscript_common.hpp" @@ -282,7 +282,7 @@ namespace chaiscript return Boxed_Value(); } } - catch (const chaiscript::eval::detail::Return_Value &rv) { + catch (chaiscript::eval::detail::Return_Value &rv) { return rv.retval; } } @@ -345,12 +345,21 @@ namespace chaiscript 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(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&chaiscript::detail::Dispatch_Engine::call_exists, std::ref(m_engine), std::placeholders::_1))), - "call_exists"); + m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function( + [this](const std::vector &t_params) { + return m_engine.call_exists(t_params); + })), "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(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name"); + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type, std::ref(m_engine)), "type"); + 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&); @@ -382,7 +391,7 @@ namespace chaiscript throw chaiscript::exception::file_not_found_error(t_filename); } - std::streampos size = infile.tellg(); + const auto size = infile.tellg(); infile.seekg(0, std::ios::beg); assert(size >= 0); @@ -391,7 +400,7 @@ namespace chaiscript { return std::string(); } else { - std::vector v(static_cast(size)); + std::vector v(static_cast(size)); infile.read(&v[0], size); return std::string(v.begin(), v.end()); } @@ -457,7 +466,7 @@ namespace chaiscript u.in_ptr = &ChaiScript::use; if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) { std::string dllpath(rInfo.dli_fname); - size_t lastslash = dllpath.rfind('/'); + const size_t lastslash = dllpath.rfind('/'); if (lastslash != std::string::npos) { dllpath.erase(lastslash); @@ -465,15 +474,15 @@ namespace chaiscript // Let's see if this is a link that we should expand std::vector buf(2048); - size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size()); + const size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size()); if (pathlen > 0 && pathlen < buf.size()) { dllpath = std::string(&buf.front(), pathlen); } m_modulepaths.insert(m_modulepaths.begin(), dllpath+"/"); - } -#endif + } +#endif // attempt to load the stdlib @@ -523,10 +532,10 @@ namespace chaiscript /// \param[in] t_filename Filename to load and evaluate void use(const std::string &t_filename) { - for (size_t i = 0; i < m_usepaths.size(); ++i) + for (const auto &path : m_usepaths) { try { - const std::string appendedpath = m_usepaths[i] + t_filename; + const auto appendedpath = path + t_filename; chaiscript::detail::threading::unique_lock l(m_use_mutex); chaiscript::detail::threading::unique_lock l2(m_mutex); @@ -541,14 +550,12 @@ namespace chaiscript return; // return, we loaded it, or it was already loaded } catch (const exception::file_not_found_error &) { - if (i == m_usepaths.size() - 1) - { - throw exception::file_not_found_error(t_filename); - } - // failed to load, try the next path } } + + // failed to load by any name + throw exception::file_not_found_error(t_filename); } /// \brief Adds a constant object that is available in all contexts and to all threads @@ -679,7 +686,7 @@ namespace chaiscript /// chaiscript::ChaiScript chai; /// chai.add(chaiscript::base_class()); /// \endcode - ChaiScript &add(const Dynamic_Cast_Conversion &d) + ChaiScript &add(const Type_Conversion &d) { m_engine.add(d); return *this; @@ -716,15 +723,9 @@ namespace chaiscript version_stripped_name.erase(version_pos); } - std::vector prefixes; - prefixes.push_back("lib"); - prefixes.push_back("cyg"); - prefixes.push_back(""); + std::vector prefixes{"lib", "cyg", ""}; - std::vector postfixes; - postfixes.push_back(".dll"); - postfixes.push_back(".so"); - postfixes.push_back(""); + std::vector postfixes{".dll", ".so", ""}; for (auto & elem : m_modulepaths) { @@ -733,7 +734,7 @@ namespace chaiscript for (auto & postfix : postfixes) { try { - std::string name = elem + prefix + t_module_name + postfix; + const auto name = elem + prefix + t_module_name + postfix; // std::cerr << "trying location: " << name << std::endl; load_module(version_stripped_name, name); return name; @@ -845,7 +846,7 @@ namespace chaiscript /// /// \param[in] t_input Script to execute /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions - /// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful + /// \param[in] t_filename Optional filename to report to the user for where the error occurred. Useful /// in special cases where you are loading a file internally instead of using eval_file /// /// \return result of the script execution @@ -879,7 +880,7 @@ namespace chaiscript } } - /// \brief Loads the file specified by filename, evaluates it, and returns the typesafe result. + /// \brief Loads the file specified by filename, evaluates it, and returns the type safe result. /// \tparam T Type to extract from the result value of the script execution /// \param[in] t_filename File to load and parse. /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index f40a9fc..36978ab 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -45,19 +45,17 @@ namespace chaiscript { namespace detail { - /** - * Helper function that will set up the scope around a function call, including handling the named function parameters - */ - static const 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) { + /// 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) { chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - for (unsigned int i = 0; i < t_param_names.size(); ++i) { + for (size_t i = 0; i < t_param_names.size(); ++i) { t_ss.add_object(t_param_names[i], t_vals[i]); } try { return t_node->eval(t_ss); - } catch (const detail::Return_Value &rv) { + } catch (detail::Return_Value &rv) { return rv.retval; } } @@ -65,12 +63,12 @@ namespace chaiscript struct Binary_Operator_AST_Node : public AST_Node { public: - Binary_Operator_AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) + Binary_Operator_AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr &t_fname, int t_start_line, int t_start_col, int t_end_line, int t_end_col) : + AST_Node(std::move(t_ast_node_text), t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Binary_Operator_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { return do_oper(t_ss, Operators::to_operator(children[1]->text), children[1]->text, this->children[0]->eval(t_ss), this->children[2]->eval(t_ss)); @@ -88,15 +86,12 @@ namespace chaiscript protected: Boxed_Value do_oper(chaiscript::detail::Dispatch_Engine &t_ss, - Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) + Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const { try { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - std::vector params(2); - params.push_back(t_lhs); - params.push_back(t_rhs); - fpp.save_params(params); - + fpp.save_params({t_lhs, t_rhs}); + if (t_oper != Operators::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic()) { // If it's an arithmetic operation we want to short circuit dispatch @@ -117,24 +112,13 @@ namespace chaiscript } }; - struct Error_AST_Node : public AST_Node { - public: - Error_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Error, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - - virtual ~Error_AST_Node() {} - }; - struct Int_AST_Node : public AST_Node { public: - Int_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Int, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), - m_value(const_var(int(atoi(t_ast_node_text.c_str())))) { } - Int_AST_Node(const std::string &t_ast_node_text, const Boxed_Value &t_bv, const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Int, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), - m_value(t_bv) { } + Int_AST_Node(std::string t_ast_node_text, Boxed_Value t_bv, const std::shared_ptr &t_fname, int t_start_line, int t_start_col, int t_end_line, int t_end_col) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), + m_value(std::move(t_bv)) { } virtual ~Int_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ return m_value; } @@ -145,14 +129,11 @@ namespace chaiscript struct Float_AST_Node : public AST_Node { public: - Float_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Float, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), - m_value(const_var(double(atof(t_ast_node_text.c_str())))) { } - Float_AST_Node(const std::string &t_ast_node_text, const Boxed_Value &t_bv, const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Float, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), - m_value(t_bv) { } + Float_AST_Node(std::string t_ast_node_text, Boxed_Value t_bv, const std::shared_ptr &t_fname, int t_start_line, int t_start_col, int t_end_line, int t_end_col) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Float, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), + m_value(std::move(t_bv)) { } virtual ~Float_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ return m_value; } @@ -163,13 +144,13 @@ namespace chaiscript struct Id_AST_Node : public AST_Node { public: - Id_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Id_AST_Node(const std::string &t_ast_node_text, const std::shared_ptr &t_fname, int t_start_line, int t_start_col, int t_end_line, int t_end_col) : AST_Node(t_ast_node_text, AST_Node_Type::Id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), m_value(get_value(t_ast_node_text)) { } virtual ~Id_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { if (!m_value.is_undef()) { return m_value; @@ -207,22 +188,22 @@ namespace chaiscript struct Char_AST_Node : public AST_Node { public: - Char_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Char, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Char_AST_Node(std::string t_ast_node_text, const std::shared_ptr &t_fname, int t_start_line, int t_start_col, int t_end_line, int t_end_col) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Char, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Char_AST_Node() {} }; struct Str_AST_Node : public AST_Node { public: - Str_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Str, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Str_AST_Node(std::string t_ast_node_text, const std::shared_ptr &t_fname, int t_start_line, int t_start_col, int t_end_line, int t_end_col) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Str, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Str_AST_Node() {} }; struct Eol_AST_Node : public AST_Node { public: - Eol_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Eol, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Eol_AST_Node(std::string t_ast_node_text, const std::shared_ptr &t_fname, int t_start_line, int t_start_col, int t_end_line, int t_end_col) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Eol, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Eol_AST_Node() {} virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE @@ -236,24 +217,27 @@ namespace chaiscript Fun_Call_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Fun_Call, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Fun_Call_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + std::vector params; - if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { - for (size_t i = 0; i < this->children[1]->children.size(); ++i) { - params.push_back(this->children[1]->children[i]->eval(t_ss)); + if ((this->children.size() > 1)) { + const AST_Node &first_child(*(this->children[1])); + if (first_child.identifier == AST_Node_Type::Arg_List) { + for (const auto &child : first_child.children) { + params.push_back(child->eval(t_ss)); + } } } fpp.save_params(params); + Boxed_Value fn(this->children[0]->eval(t_ss)); - Boxed_Value fn = this->children[0]->eval(t_ss); try { chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); - const Boxed_Value &retval = (*t_ss.boxed_cast(fn))(params, t_ss.conversions()); - return retval; + 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); @@ -262,9 +246,7 @@ namespace chaiscript try { 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 - std::vector funcs; - funcs.push_back(f); - throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, funcs, 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."); } @@ -284,13 +266,15 @@ namespace chaiscript { std::ostringstream oss; - for (size_t j = 0; j < this->children.size(); ++j) { - oss << this->children[j]->pretty_print(); + int count = 0; + for (const auto &child : this->children) { + oss << child->pretty_print(); - if (j == 0) + if (count == 0) { oss << "("; } + ++count; } oss << ")"; @@ -300,25 +284,26 @@ namespace chaiscript }; + /// Used in the context of in-string ${} evals, so that no new scope is created struct Inplace_Fun_Call_AST_Node : public AST_Node { public: Inplace_Fun_Call_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Inplace_Fun_Call, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Inplace_Fun_Call_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ std::vector params; + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { - for (size_t i = 0; i < this->children[1]->children.size(); ++i) { - params.push_back(this->children[1]->children[i]->eval(t_ss)); + for (const auto &child : this->children[1]->children) { + params.push_back(child->eval(t_ss)); } } - Boxed_Value bv; Const_Proxy_Function fn; try { - bv = this->children[0]->eval(t_ss); + Boxed_Value bv = this->children[0]->eval(t_ss); try { fn = t_ss.boxed_cast(bv); } catch (const exception::bad_boxed_cast &) { @@ -333,7 +318,7 @@ namespace chaiscript // handle the case where there is only 1 function to try to call and dispatch fails on it std::vector funcs; funcs.push_back(fn); - throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, funcs, 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 + "'"); @@ -349,13 +334,15 @@ namespace chaiscript virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE { std::ostringstream oss; - for (size_t j = 0; j < this->children.size(); ++j) { - oss << this->children[j]->pretty_print(); + int count = 0; + for (const auto &child : this->children) { + oss << child->pretty_print(); - if (j == 0) + if (count == 0) { oss << "("; } + ++count; } oss << ")"; @@ -367,14 +354,14 @@ namespace chaiscript struct Arg_List_AST_Node : public AST_Node { public: - Arg_List_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Arg_List, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Arg_List_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Arg_List, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Arg_List_AST_Node() {} virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE { std::ostringstream oss; - for (unsigned int j = 0; j < this->children.size(); ++j) { + for (size_t j = 0; j < this->children.size(); ++j) { if (j != 0) { oss << ", "; @@ -387,21 +374,14 @@ namespace chaiscript } }; - struct Variable_AST_Node : public AST_Node { - public: - Variable_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Variable, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Variable_AST_Node() {} - }; - struct Equation_AST_Node : public AST_Node { public: - Equation_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Equation, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) + Equation_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Equation, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) {} virtual ~Equation_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { Boxed_Value retval = this->children.back()->eval(t_ss); @@ -435,7 +415,7 @@ namespace chaiscript } try { - retval = t_ss.call_function(this->children[1]->text, lhs, retval); + retval = t_ss.call_function(this->children[1]->text, std::move(lhs), retval); } 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); @@ -454,9 +434,9 @@ namespace chaiscript } else { try { - retval = t_ss.call_function(this->children[1]->text, lhs, retval); + retval = t_ss.call_function(this->children[1]->text, std::move(lhs), retval); } 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); } } } @@ -466,25 +446,26 @@ namespace chaiscript struct Var_Decl_AST_Node : public AST_Node { public: - Var_Decl_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Var_Decl, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Var_Decl_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Var_Decl_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { if (this->children[0]->identifier == AST_Node_Type::Reference) { return this->children[0]->eval(t_ss); } else { std::string idname = this->children[0]->text; + Boxed_Value bv; try { - t_ss.add_object(idname, Boxed_Value()); + t_ss.add_object(idname, bv); } catch (const exception::reserved_word_error &) { throw exception::eval_error("Reserved word used as variable '" + idname + "'"); } catch (const exception::name_conflict_error &e) { throw exception::eval_error("Variable redefined '" + e.name() + "'"); } - return t_ss.get_object(idname); + return bv; } } @@ -498,67 +479,67 @@ namespace chaiscript struct Comparison_AST_Node : public Binary_Operator_AST_Node { public: - Comparison_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Comparison, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Comparison_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Comparison, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Comparison_AST_Node() {} }; struct Addition_AST_Node : public Binary_Operator_AST_Node { public: - Addition_AST_Node(const std::string &t_ast_node_text = "+", + Addition_AST_Node(std::string t_ast_node_text = "+", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Addition, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Addition, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Addition_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { return do_oper(t_ss, Operators::sum, "+", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)); } }; struct Subtraction_AST_Node : public Binary_Operator_AST_Node { public: - Subtraction_AST_Node(const std::string &t_ast_node_text = "-", + Subtraction_AST_Node(std::string t_ast_node_text = "-", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Subtraction, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Subtraction, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Subtraction_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { return do_oper(t_ss, Operators::difference, "-", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)); } }; struct Multiplication_AST_Node : public Binary_Operator_AST_Node { public: - Multiplication_AST_Node(const std::string &t_ast_node_text = "*", + Multiplication_AST_Node(std::string t_ast_node_text = "*", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Multiplication, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Multiplication, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Multiplication_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { return do_oper(t_ss, Operators::product, "*", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)); } }; struct Division_AST_Node : public Binary_Operator_AST_Node { public: - Division_AST_Node(const std::string &t_ast_node_text = "/", + Division_AST_Node(std::string t_ast_node_text = "/", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Division, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Division, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Division_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { return do_oper(t_ss, Operators::quotient, "/", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)); } }; struct Modulus_AST_Node : public Binary_Operator_AST_Node { public: - Modulus_AST_Node(const std::string &t_ast_node_text = "%", + Modulus_AST_Node(std::string t_ast_node_text = "%", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Modulus, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Modulus, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Modulus_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { return do_oper(t_ss, Operators::remainder, "%", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)); } }; @@ -568,11 +549,11 @@ namespace chaiscript Array_Call_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Array_Call, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Array_Call_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - Boxed_Value retval = this->children[0]->eval(t_ss); - std::vector params; - params.push_back(retval); + + Boxed_Value retval(this->children[0]->eval(t_ss)); + std::vector params{retval}; for (size_t i = 1; i < this->children.size(); ++i) { try { @@ -582,7 +563,7 @@ namespace chaiscript params.push_back(p1); fpp.save_params(params); params.clear(); - retval = t_ss.call_function("[]", retval, p1); + retval = t_ss.call_function("[]", retval, std::move(p1)); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, t_ss ); @@ -613,18 +594,17 @@ namespace chaiscript Dot_Access_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Dot_Access, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Dot_Access_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ Boxed_Value retval = this->children[0]->eval(t_ss); + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); if (this->children.size() > 1) { for (size_t i = 2; i < this->children.size(); i+=2) { - chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - std::vector params; - params.push_back(retval); + std::vector params{retval}; if (this->children[i]->children.size() > 1) { - for (size_t j = 0; j < this->children[i]->children[1]->children.size(); ++j) { - params.push_back(this->children[i]->children[1]->children[j]->eval(t_ss)); + for (const auto &child : this->children[i]->children[1]->children) { + params.push_back(child->eval(t_ss)); } } @@ -640,7 +620,7 @@ namespace chaiscript try { chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); - retval = t_ss.call_function(fun_name, params); + retval = t_ss.call_function(fun_name, std::move(params)); } catch(const exception::dispatch_error &e){ if (e.functions.empty()) @@ -678,7 +658,8 @@ namespace chaiscript AST_Node(t_ast_node_text, AST_Node_Type::Quoted_String, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), m_value(const_var(t_ast_node_text)) { } virtual ~Quoted_String_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) CHAISCRIPT_OVERRIDE { + + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE { return m_value; } @@ -697,8 +678,9 @@ namespace chaiscript Single_Quoted_String_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Single_Quoted_String, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), m_value(const_var(char(t_ast_node_text.at(0)))) { } + virtual ~Single_Quoted_String_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ return m_value; } @@ -716,46 +698,51 @@ namespace chaiscript Lambda_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Lambda, const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Lambda_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ std::vector t_param_names; + size_t numparams = 0; - if ((this->children.size() > 0) && (this->children[0]->identifier == AST_Node_Type::Arg_List)) { + if (!this->children.empty() && (this->children[0]->identifier == AST_Node_Type::Arg_List)) { numparams = this->children[0]->children.size(); - for (size_t i = 0; i < numparams; ++i) { - t_param_names.push_back(this->children[0]->children[i]->text); + + for (const auto &child : this->children[0]->children) + { + t_param_names.push_back(child->text); } - - } - else { - //no parameters - numparams = 0; } - return Boxed_Value(Proxy_Function(new dispatch::Dynamic_Proxy_Function - (std::bind(chaiscript::eval::detail::eval_function, std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1), - static_cast(numparams), this->children.back()))); + const auto &lambda_node = this->children.back(); + + return Boxed_Value(Proxy_Function(new dispatch::Dynamic_Proxy_Function( + [&t_ss, lambda_node, t_param_names](const std::vector &t_params) + { + return detail::eval_function(t_ss, lambda_node, t_param_names, t_params); + }, + static_cast(numparams), lambda_node))); } }; struct Block_AST_Node : public AST_Node { public: - Block_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Block, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Block_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Block, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Block_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ - const size_t num_children = this->children.size(); + + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + const auto num_children = this->children.size(); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); for (size_t i = 0; i < num_children; ++i) { try { - const Boxed_Value &retval = this->children[i]->eval(t_ss); - - if (i + 1 == num_children) + if (i + 1 < num_children) { - return retval; + this->children[i]->eval(t_ss); + } else { + return this->children[i]->eval(t_ss); } } catch (const chaiscript::eval::detail::Return_Value &) { @@ -765,7 +752,6 @@ namespace chaiscript return Boxed_Value(); } - }; struct Def_AST_Node : public AST_Node { @@ -773,15 +759,17 @@ namespace chaiscript Def_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Def, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Def_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ std::vector t_param_names; size_t numparams = 0; AST_NodePtr guardnode; if ((this->children.size() > 2) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { numparams = this->children[1]->children.size(); - for (size_t i = 0; i < numparams; ++i) { - t_param_names.push_back(this->children[1]->children[i]->text); + + for (const auto &child : this->children[1]->children) + { + t_param_names.push_back(child->text); } if (this->children.size() > 3) { @@ -800,19 +788,22 @@ namespace chaiscript std::shared_ptr guard; if (guardnode) { guard = std::shared_ptr - (new dispatch::Dynamic_Proxy_Function(std::bind(chaiscript::eval::detail::eval_function, - std::ref(t_ss), guardnode, - t_param_names, std::placeholders::_1), static_cast(numparams), guardnode)); + (new dispatch::Dynamic_Proxy_Function([&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)); } 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(Proxy_Function - (new dispatch::Dynamic_Proxy_Function(std::bind(chaiscript::eval::detail::eval_function, - std::ref(t_ss), this->children.back(), - t_param_names, std::placeholders::_1), static_cast(numparams), this->children.back(), - l_annotation, guard)), l_function_name); + (new dispatch::Dynamic_Proxy_Function([&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(), + 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() + "'"); @@ -826,10 +817,10 @@ namespace chaiscript struct While_AST_Node : public AST_Node { public: - While_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::While, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + While_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::While, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~While_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); try { @@ -857,7 +848,7 @@ namespace chaiscript Class_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Class, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Class_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); // put class name in current scope so it can be looked up by the attrs and methods @@ -874,8 +865,8 @@ namespace chaiscript Ternary_Cond_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::If, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Ternary_Cond_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ - bool cond; + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + bool cond = false; try { cond = boxed_cast(this->children[0]->eval(t_ss)); } @@ -897,8 +888,8 @@ namespace chaiscript If_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::If, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~If_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ - bool cond; + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + bool cond = false; try { cond = boxed_cast(this->children[0]->eval(t_ss)); } @@ -927,22 +918,23 @@ namespace chaiscript return this->children[i+2]->eval(t_ss); } } - i = i + 3; + i += 3; } } } - return Boxed_Value(false); + return const_var(false); } }; struct For_AST_Node : public AST_Node { public: - For_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::For, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + For_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::For, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~For_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); // initial expression @@ -978,18 +970,17 @@ namespace chaiscript struct Switch_AST_Node : public AST_Node { public: - Switch_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Switch, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Switch_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Switch, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Switch_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { - Boxed_Value match_value; + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { bool breaking = false; size_t currentCase = 1; bool hasMatched = false; chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - match_value = this->children[0]->eval(t_ss); + Boxed_Value match_value(this->children[0]->eval(t_ss)); while (!breaking && (currentCase < this->children.size())) { try { @@ -1021,24 +1012,24 @@ namespace chaiscript struct Case_AST_Node : public AST_Node { public: - Case_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Case, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Case_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Case, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Case_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); this->children[1]->eval(t_ss); - + return Boxed_Value(); } }; struct Default_AST_Node : public AST_Node { public: - Default_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Default, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Default_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Default, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Default_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); this->children[0]->eval(t_ss); @@ -1050,19 +1041,18 @@ namespace chaiscript struct Inline_Array_AST_Node : public AST_Node { public: - Inline_Array_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Inline_Array, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Inline_Array_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Inline_Array_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { try { std::vector vec; - if (this->children.size() > 0) { - for (size_t i = 0; i < this->children[0]->children.size(); ++i) { - Boxed_Value bv = t_ss.call_function("clone", this->children[0]->children[i]->eval(t_ss)); - vec.push_back(bv); + if (!this->children.empty()) { + for (const auto &child : this->children[0]->children) { + vec.push_back(t_ss.call_function("clone", child->eval(t_ss))); } } - return const_var(vec); + return const_var(std::move(vec)); } catch (const exception::dispatch_error &) { throw exception::eval_error("Can not find appropriate 'clone' or copy constructor for vector elements"); @@ -1078,17 +1068,18 @@ namespace chaiscript struct Inline_Map_AST_Node : public AST_Node { public: - Inline_Map_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Inline_Map, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Inline_Map_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Inline_Map_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ try { std::map retval; - for (size_t i = 0; i < this->children[0]->children.size(); ++i) { - Boxed_Value bv = t_ss.call_function("clone", this->children[0]->children[i]->children[1]->eval(t_ss)); - retval[t_ss.boxed_cast(this->children[0]->children[i]->children[0]->eval(t_ss))] - = bv; + + for (const auto &child : this->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); } + return const_var(retval); } catch (const exception::dispatch_error &e) { @@ -1100,11 +1091,11 @@ namespace chaiscript struct Return_AST_Node : public AST_Node { public: - Return_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Return, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + Return_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Return, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Return_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ - if (this->children.size() > 0) { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + if (!this->children.empty()) { throw detail::Return_Value(this->children[0]->eval(t_ss)); } else { @@ -1116,13 +1107,13 @@ namespace chaiscript struct File_AST_Node : public AST_Node { public: - File_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::File, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + File_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::File, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~File_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE { + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { const size_t size = this->children.size(); for (size_t i = 0; i < size; ++i) { - const Boxed_Value &retval = this->children[i]->eval(t_ss); + Boxed_Value retval(this->children[i]->eval(t_ss)); if (i + 1 == size) { return retval; } @@ -1133,18 +1124,19 @@ namespace chaiscript struct Reference_AST_Node : public AST_Node { public: - Reference_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Reference, const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) + Reference_AST_Node(std::string t_ast_node_text = "", int t_id = AST_Node_Type::Reference, const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ try { - t_ss.add_object(this->children[0]->text, Boxed_Value()); + Boxed_Value bv; + t_ss.add_object(this->children[0]->text, bv); + return bv; } catch (const exception::reserved_word_error &) { throw exception::eval_error("Reserved word used as variable '" + this->children[0]->text + "'"); } - return t_ss.get_object(this->children[0]->text); } virtual ~Reference_AST_Node() {} @@ -1152,12 +1144,12 @@ namespace chaiscript struct Prefix_AST_Node : public AST_Node { public: - Prefix_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : - AST_Node(t_ast_node_text, AST_Node_Type::Prefix, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) + Prefix_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Prefix, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Prefix_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); Boxed_Value bv(this->children[1]->eval(t_ss)); @@ -1166,13 +1158,11 @@ namespace chaiscript // short circuit arithmetic operations if (bv.get_type_info().is_arithmetic() && oper != Operators::invalid) { - return Boxed_Number::do_oper(oper, bv); + return Boxed_Number::do_oper(oper, std::move(bv)); } else { chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); - std::vector params; - params.push_back(bv); - fpp.save_params(params); - return t_ss.call_function(this->children[0]->text, bv); + fpp.save_params({bv}); + return t_ss.call_function(this->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); @@ -1186,7 +1176,7 @@ namespace chaiscript Break_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Break, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Break_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ throw detail::Break_Loop(); } }; @@ -1196,7 +1186,7 @@ namespace chaiscript Continue_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Continue, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Continue_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ throw detail::Continue_Loop(); } }; @@ -1209,7 +1199,7 @@ namespace chaiscript { } virtual ~Noop_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{ // It's a no-op, that evaluates to "true" return m_value; } @@ -1237,7 +1227,7 @@ namespace chaiscript Inline_Range_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Inline_Range, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Inline_Range_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ try { return t_ss.call_function("generate_range", this->children[0]->children[0]->children[0]->eval(t_ss), @@ -1262,8 +1252,8 @@ namespace chaiscript Try_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Try, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Try_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ - Boxed_Value retval; + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ + Boxed_Value retval; chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); @@ -1277,7 +1267,7 @@ namespace chaiscript throw; } catch (const std::exception &e) { - Boxed_Value except = Boxed_Value(std::ref(e)); + Boxed_Value except(std::ref(e)); size_t end_point = this->children.size(); if (this->children.back()->identifier == AST_Node_Type::Finally) { @@ -1304,7 +1294,7 @@ namespace chaiscript //Variable capture, no guards t_ss.add_object(catch_block->children[0]->text, except); - bool guard; + bool guard = false; try { guard = boxed_cast(catch_block->children[1]->eval(t_ss)); } catch (const exception::bad_boxed_cast &) { @@ -1329,7 +1319,7 @@ namespace chaiscript catch (Boxed_Value &except) { for (size_t i = 1; i < this->children.size(); ++i) { chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss); - AST_NodePtr catch_block = this->children[i]; + const auto &catch_block = this->children[i]; if (catch_block->children.size() == 1) { //No variable capture, no guards @@ -1405,9 +1395,8 @@ namespace chaiscript Method_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Method, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Method_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ - std::vector t_param_names; AST_NodePtr guardnode; auto d = t_ss.get_parent_locals(); @@ -1417,33 +1406,33 @@ namespace chaiscript const std::string & class_name = (itr != d.end())?std::string(boxed_cast(itr->second)):this->children[0]->text; //The first param of a method is always the implied this ptr. - t_param_names.push_back("this"); + std::vector t_param_names{"this"}; - if ((this->children.size() > (3 + class_offset)) && (this->children[(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) { - for (size_t i = 0; i < this->children[(2 + class_offset)]->children.size(); ++i) { - t_param_names.push_back(this->children[(2 + class_offset)]->children[i]->text); + if ((this->children.size() > static_cast(3 + class_offset)) && (this->children[(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) { + for (const auto &child : this->children[(2 + class_offset)]->children) { + t_param_names.push_back(child->text); } - if (this->children.size() > (4 + class_offset)) { + if (this->children.size() > static_cast(4 + class_offset)) { guardnode = this->children[(3 + class_offset)]; } } else { //no parameters - if (this->children.size() > (3 + class_offset)) { + if (this->children.size() > static_cast(3 + class_offset)) { guardnode = this->children[(2 + class_offset)]; } } - size_t numparams = t_param_names.size(); + const size_t numparams = t_param_names.size(); std::shared_ptr guard; if (guardnode) { - guard = std::shared_ptr - (new dispatch::Dynamic_Proxy_Function(std::bind(chaiscript::eval::detail::eval_function, - std::ref(t_ss), guardnode, - t_param_names, std::placeholders::_1), static_cast(numparams), guardnode)); + guard = std::make_shared + (std::bind(chaiscript::eval::detail::eval_function, + std::ref(t_ss), guardnode, + t_param_names, std::placeholders::_1), static_cast(numparams), guardnode); } try { @@ -1452,31 +1441,29 @@ namespace chaiscript const std::string & function_name = this->children[(1 + class_offset)]->text; if (function_name == class_name) { - t_ss.add(Proxy_Function - (new dispatch::detail::Dynamic_Object_Constructor(class_name, Proxy_Function - (new dispatch::Dynamic_Proxy_Function(std::bind(chaiscript::eval::detail::eval_function, - std::ref(t_ss), this->children.back(), - t_param_names, std::placeholders::_1), static_cast(numparams), this->children.back(), - l_annotation, guard)))), function_name); + t_ss.add(std::make_shared(class_name, std::make_shared(std::bind(chaiscript::eval::detail::eval_function, + std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1), + static_cast(numparams), this->children.back(), l_annotation, guard)), + function_name); } else { try { // Do know type name - t_ss.add(Proxy_Function - (new dispatch::detail::Dynamic_Object_Function(class_name, Proxy_Function - (new dispatch::Dynamic_Proxy_Function(std::bind(chaiscript::eval::detail::eval_function, + t_ss.add( + std::make_shared(class_name, + std::make_shared(std::bind(chaiscript::eval::detail::eval_function, std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1), static_cast(numparams), this->children.back(), - l_annotation, guard)), t_ss.get_type(class_name))), function_name); + l_annotation, guard), t_ss.get_type(class_name)), function_name); } catch (const std::range_error &) { // Do not know type name - t_ss.add(Proxy_Function - (new dispatch::detail::Dynamic_Object_Function(class_name, Proxy_Function - (new dispatch::Dynamic_Proxy_Function(std::bind(chaiscript::eval::detail::eval_function, + t_ss.add( + std::make_shared(class_name, + std::make_shared(std::bind(chaiscript::eval::detail::eval_function, std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1), static_cast(numparams), this->children.back(), - l_annotation, guard)))), function_name); + l_annotation, guard)), function_name); } } } @@ -1495,7 +1482,7 @@ namespace chaiscript Attr_Decl_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Attr_Decl, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Attr_Decl_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { const auto &d = t_ss.get_parent_locals(); const auto itr = d.find("_current_class_name"); @@ -1504,13 +1491,13 @@ namespace chaiscript std::string class_name = (itr != d.end())?std::string(boxed_cast(itr->second)):this->children[0]->text; try { - t_ss.add(Proxy_Function - (new dispatch::detail::Dynamic_Object_Function( + t_ss.add( + std::make_shared( class_name, fun(std::function(std::bind(&dispatch::Dynamic_Object::get_attr, std::placeholders::_1, this->children[(1 + class_offset)]->text - ))) + )) ) ), this->children[(1 + class_offset)]->text); @@ -1565,7 +1552,7 @@ namespace chaiscript Logical_And_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Logical_And, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Logical_And_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ Boxed_Value retval = this->children[0]->eval(t_ss); if (this->children.size() > 1) { @@ -1599,7 +1586,7 @@ namespace chaiscript Logical_Or_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, AST_Node_Type::Logical_Or, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Logical_Or_AST_Node() {} - virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_OVERRIDE{ + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{ Boxed_Value retval; retval = this->children[0]->eval(t_ss); diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index e50a5d0..482d653 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -57,94 +57,63 @@ namespace chaiscript std::vector m_match_stack; bool m_alphabet[detail::max_alphabet][detail::lengthof_alphabet]; - std::vector > m_operator_matches; + std::vector> m_operator_matches; std::vector m_operators; public: ChaiScript_Parser() : m_line(-1), m_col(-1), - m_multiline_comment_begin("/*"), + m_multiline_comment_begin("/*"), m_multiline_comment_end("*/"), m_singleline_comment("//") { setup_operators(); } - ChaiScript_Parser(const ChaiScript_Parser &); // explicitly unimplemented copy constructor - ChaiScript_Parser &operator=(const ChaiScript_Parser &); // explicitly unimplemented assignment operator + ChaiScript_Parser(const ChaiScript_Parser &) = delete; + ChaiScript_Parser &operator=(const ChaiScript_Parser &) = delete; void setup_operators() { - m_operators.push_back(AST_Node_Type::Ternary_Cond); - std::vector ternary_cond; - ternary_cond.push_back("?"); - m_operator_matches.push_back(ternary_cond); + m_operators.emplace_back(AST_Node_Type::Ternary_Cond); + m_operator_matches.emplace_back(std::initializer_list({"?"})); - m_operators.push_back(AST_Node_Type::Logical_Or); - std::vector logical_or; - logical_or.push_back("||"); - m_operator_matches.push_back(logical_or); + m_operators.emplace_back(AST_Node_Type::Logical_Or); + m_operator_matches.emplace_back(std::initializer_list({"||"})); - m_operators.push_back(AST_Node_Type::Logical_And); - std::vector logical_and; - logical_and.push_back("&&"); - m_operator_matches.push_back(logical_and); + m_operators.emplace_back(AST_Node_Type::Logical_And); + m_operator_matches.emplace_back(std::initializer_list({"&&"})); - m_operators.push_back(AST_Node_Type::Bitwise_Or); - std::vector bitwise_or; - bitwise_or.push_back("|"); - m_operator_matches.push_back(bitwise_or); + m_operators.emplace_back(AST_Node_Type::Bitwise_Or); + m_operator_matches.emplace_back(std::initializer_list({"|"})); - m_operators.push_back(AST_Node_Type::Bitwise_Xor); - std::vector bitwise_xor; - bitwise_xor.push_back("^"); - m_operator_matches.push_back(bitwise_xor); + m_operators.emplace_back(AST_Node_Type::Bitwise_Xor); + m_operator_matches.emplace_back(std::initializer_list({"^"})); - m_operators.push_back(AST_Node_Type::Bitwise_And); - std::vector bitwise_and; - bitwise_and.push_back("&"); - m_operator_matches.push_back(bitwise_and); + m_operators.emplace_back(AST_Node_Type::Bitwise_And); + m_operator_matches.emplace_back(std::initializer_list({"&"})); - m_operators.push_back(AST_Node_Type::Equality); - std::vector equality; - equality.push_back("=="); - equality.push_back("!="); - m_operator_matches.push_back(equality); + m_operators.emplace_back(AST_Node_Type::Equality); + m_operator_matches.emplace_back(std::initializer_list({"==", "!="})); - m_operators.push_back(AST_Node_Type::Comparison); - std::vector comparison; - comparison.push_back("<"); - comparison.push_back("<="); - comparison.push_back(">"); - comparison.push_back(">="); - m_operator_matches.push_back(comparison); + m_operators.emplace_back(AST_Node_Type::Comparison); + m_operator_matches.emplace_back(std::initializer_list({"<", "<=", ">", ">="})); - m_operators.push_back(AST_Node_Type::Shift); - std::vector shift; - shift.push_back("<<"); - shift.push_back(">>"); - m_operator_matches.push_back(shift); + m_operators.emplace_back(AST_Node_Type::Shift); + m_operator_matches.emplace_back(std::initializer_list({"<<", ">>"})); //We share precedence here but then separate them later - m_operators.push_back(AST_Node_Type::Addition); - std::vector addition; - addition.push_back("+"); - addition.push_back("-"); - m_operator_matches.push_back(addition); + m_operators.emplace_back(AST_Node_Type::Addition); + m_operator_matches.emplace_back(std::initializer_list({"+", "-"})); //We share precedence here but then separate them later - m_operators.push_back(AST_Node_Type::Multiplication); - std::vector multiplication; - multiplication.push_back("*"); - multiplication.push_back("/"); - multiplication.push_back("%"); - m_operator_matches.push_back(multiplication); + m_operators.emplace_back(AST_Node_Type::Multiplication); + m_operator_matches.emplace_back(std::initializer_list({"*", "/", "%"})); - for ( int c = 0 ; c < detail::lengthof_alphabet ; ++c ) { - for (auto & elem : m_alphabet) { - elem[c]=false; - } + for (auto & elem : m_alphabet) { + std::fill(std::begin(elem), std::end(elem), false); } + m_alphabet[detail::symbol_alphabet][static_cast('?')]=true; m_alphabet[detail::symbol_alphabet][static_cast('+')]=true; m_alphabet[detail::symbol_alphabet][static_cast('-')]=true; @@ -194,17 +163,12 @@ namespace chaiscript m_alphabet[detail::float_suffix_alphabet][static_cast('L')] = true; m_alphabet[detail::float_suffix_alphabet][static_cast('f')] = true; m_alphabet[detail::float_suffix_alphabet][static_cast('F')] = true; - } - /** - * test a char in an m_alphabet - */ - bool char_in_alphabet(char c, detail::Alphabet a) { return m_alphabet[a][static_cast(c)]; } + /// test a char in an m_alphabet + bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast(c)]; } - /** - * Prints the parsed ast_nodes as a tree - */ + /// Prints the parsed ast_nodes as a tree /* void debug_print(AST_NodePtr t, std::string prepend = "") { std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl; @@ -214,9 +178,7 @@ namespace chaiscript } */ - /** - * Shows the current stack of matched ast_nodes - */ + /// Shows the current stack of matched ast_nodes void show_match_stack() const { for (auto & elem : m_match_stack) { //debug_print(match_stack[i]); @@ -224,26 +186,20 @@ namespace chaiscript } } - /** - * Clears the stack of matched ast_nodes - */ + /// Clears the stack of matched ast_nodes void clear_match_stack() { m_match_stack.clear(); } - /** - * Returns the front-most AST node - */ - AST_NodePtr ast() { + /// Returns the front-most AST node + AST_NodePtr ast() const { return m_match_stack.front(); } - /** - * Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node - */ + /// Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node void build_match(AST_NodePtr t_t, size_t t_match_start) { int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop; - int is_deep = false; + bool is_deep = false; //so we want to take everything to the right of this and make them children if (t_match_start != m_match_stack.size()) { @@ -269,70 +225,66 @@ namespace chaiscript if (is_deep) { t_t->children.assign(m_match_stack.begin() + t_match_start, m_match_stack.end()); m_match_stack.erase(m_match_stack.begin() + t_match_start, m_match_stack.end()); - m_match_stack.push_back(t_t); - } - else { - /// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position - m_match_stack.push_back(t_t); } + + /// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position + m_match_stack.push_back(std::move(t_t)); } - /** - * Check to see if there is more text parse - */ + /// Check to see if there is more text parse inline bool has_more_input() const { return (m_input_pos != m_input_end); } - /** - * Skips any multi-line or single-line comment - */ + /// Skips any multi-line or single-line comment bool SkipComment() { - bool retval = false; - if (Symbol_(m_multiline_comment_begin.c_str())) { while (m_input_pos != m_input_end) { if (Symbol_(m_multiline_comment_end.c_str())) { break; - } - else if (!Eol_()) { + } else if (!Eol_()) { ++m_col; ++m_input_pos; } } - retval = true; - } - else if (Symbol_(m_singleline_comment.c_str())) { + return true; + } else if (Symbol_(m_singleline_comment.c_str())) { while (m_input_pos != m_input_end) { if (Symbol_("\r\n")) { m_input_pos -= 2; break; - } - else if (Char_('\n')) { + } else if (Char_('\n')) { --m_input_pos; break; - } - else { + } else { ++m_col; ++m_input_pos; } } - retval = true; + return true; } - return retval; + return false; } - /** - * Skips ChaiScript whitespace, which means space and tab, but not cr/lf - * jespada: Modified SkipWS to skip optionally CR ('\n') - */ + + /// Skips ChaiScript whitespace, which means space and tab, but not cr/lf + /// jespada: Modified SkipWS to skip optionally CR ('\n') and/or LF+CR ("\r\n") bool SkipWS(bool skip_cr=false) { bool retval = false; + while (has_more_input()) { - if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && (*m_input_pos == '\n'))) { - if(*m_input_pos == '\n') { + auto end_line = (*m_input_pos != 0) && ((*m_input_pos == '\n') || (*m_input_pos == '\r' && *(m_input_pos+1) == '\n')); + + if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && end_line)) { + + if(end_line) { m_col = 1; ++m_line; + + if(*(m_input_pos) == '\r') { + // discards lf + ++m_input_pos; + } } else { ++m_col; @@ -343,30 +295,26 @@ namespace chaiscript } else if (SkipComment()) { retval = true; - } - else { + } else { break; } } return retval; } - /** - * Reads a floating point value from input, without skipping initial whitespace - */ - bool Float_() { - bool retval = false; + /// Reads a floating point value from input, without skipping initial whitespace + bool Float_() { if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { ++m_input_pos; ++m_col; } + if (has_more_input() && (*m_input_pos == '.')) { ++m_input_pos; ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet)) { - retval = true; while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { ++m_input_pos; ++m_col; @@ -377,21 +325,19 @@ namespace chaiscript ++m_input_pos; ++m_col; } - } - else { + + return true; + } else { --m_input_pos; --m_col; } } } - return retval; + return false; } - /** - * Reads a hex value from input, without skipping initial whitespace - */ + /// Reads a hex value from input, without skipping initial whitespace bool Hex_() { - bool retval = false; if (has_more_input() && (*m_input_pos == '0')) { ++m_input_pos; ++m_col; @@ -400,7 +346,6 @@ namespace chaiscript ++m_input_pos; ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet)) { - retval = true; while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) { ++m_input_pos; ++m_col; @@ -410,6 +355,8 @@ namespace chaiscript ++m_input_pos; ++m_col; } + + return true; } else { --m_input_pos; @@ -422,9 +369,10 @@ namespace chaiscript } } - return retval; + return false; } + /// Reads an integer suffix void IntSuffix_() { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) { @@ -433,11 +381,8 @@ namespace chaiscript } } - /** - * Reads a binary value from input, without skipping initial whitespace - */ + /// Reads a binary value from input, without skipping initial whitespace bool Binary_() { - bool retval = false; if (has_more_input() && (*m_input_pos == '0')) { ++m_input_pos; ++m_col; @@ -446,32 +391,31 @@ namespace chaiscript ++m_input_pos; ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { - retval = true; while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { ++m_input_pos; ++m_col; } - } - else { + return true; + } else { --m_input_pos; --m_col; } - } - else { + } else { --m_input_pos; --m_col; } } - return retval; + return false; } + /// Parses a floating point value and returns a Boxed_Value representation of it static Boxed_Value buildFloat(const std::string &t_val) { bool float_ = false; bool long_ = false; - size_t i = t_val.size(); + auto i = t_val.size(); for (; i > 0; --i) { @@ -492,16 +436,16 @@ namespace chaiscript if (float_) { float f; - ss >> f; - return Boxed_Value(const_var(f)); + ss >> f; + return const_var(f); } else if (long_) { long double f; - ss >> f; - return Boxed_Value(const_var(f)); + ss >> f; + return const_var(f); } else { double f; - ss >> f; - return Boxed_Value(const_var(f)); + ss >> f; + return const_var(f); } } @@ -514,11 +458,11 @@ namespace chaiscript bool long_ = false; bool longlong_ = false; - size_t i = t_val.size(); + auto i = t_val.size(); for (; i > 0; --i) { - char val = t_val[i-1]; + const char val = t_val[i-1]; if (val == 'u' || val == 'U') { @@ -543,7 +487,6 @@ namespace chaiscript testu >> t_type >> u; bool unsignedrequired = false; - size_t size = sizeof(int) * 8; if ((u >> (sizeof(int) * 8)) > 0) { @@ -561,6 +504,8 @@ namespace chaiscript } + size_t size = sizeof(int) * 8; + if (longlong_) { size = sizeof(int64_t) * 8; @@ -595,60 +540,57 @@ namespace chaiscript if (longlong_) { uint64_t val; - ss >> val; - return Boxed_Value(const_var(val)); + ss >> val; + return const_var(val); } else if (long_) { unsigned long val; ss >> val; - return Boxed_Value(const_var(val)); + return const_var(val); } else { unsigned int val; ss >> val; - return Boxed_Value(const_var(val)); + return const_var(val); } } else { if (longlong_) { int64_t val; - ss >> val; - return Boxed_Value(const_var(val)); + ss >> val; + return const_var(val); } else if (long_) { long val; ss >> val; - return Boxed_Value(const_var(val)); + return const_var(val); } else { int val; ss >> val; - return Boxed_Value(const_var(val)); + return const_var(val); } } } - /** - * Reads a number from the input, detecting if it's an integer or floating point - */ - bool Num(bool t_capture = false) { + /// Reads a number from the input, detecting if it's an integer or floating point + bool Num(const bool t_capture = false) { SkipWS(); if (!t_capture) { return Hex_() || Float_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; + } else { + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) { if (Hex_()) { std::string match(start, m_input_pos); - Boxed_Value i = buildInt(std::hex, match); - AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.emplace_back(std::make_shared(std::move(match), buildInt(std::hex, match), m_filename, prev_line, prev_col, m_line, m_col)); return true; } + if (Binary_()) { std::string match(start, m_input_pos); int64_t temp_int = 0; - size_t pos = 0, end = match.length(); + size_t pos = 0; + const auto end = match.length(); while ((pos < end) && (pos < (2 + sizeof(int) * 8))) { temp_int <<= 1; @@ -661,34 +603,27 @@ namespace chaiscript Boxed_Value i; if (match.length() <= sizeof(int) * 8) { - i = Boxed_Value(const_var(int(temp_int))); + i = const_var(static_cast(temp_int)); } else { - i = Boxed_Value(const_var(temp_int)); + i = const_var(temp_int); } - AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), std::move(i), m_filename, prev_line, prev_col, m_line, m_col)); return true; } if (Float_()) { std::string match(start, m_input_pos); - Boxed_Value f = buildFloat(match); - AST_NodePtr t(new eval::Float_AST_Node(match, f, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), buildFloat(match), m_filename, prev_line, prev_col, m_line, m_col)); return true; } else { IntSuffix_(); std::string match(start, m_input_pos); - if ((match.size() > 0) && (match[0] == '0')) { - Boxed_Value i = buildInt(std::oct, match); - AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + if (!match.empty() && (match[0] == '0')) { + m_match_stack.push_back(std::make_shared(std::move(match), buildInt(std::oct, match), m_filename, prev_line, prev_col, m_line, m_col)); } else { - Boxed_Value i = buildInt(std::dec, match); - AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), buildInt(std::dec, match), m_filename, prev_line, prev_col, m_line, m_col)); } return true; } @@ -699,23 +634,19 @@ namespace chaiscript } } - /** - * Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace - */ + /// Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace bool Id_() { - bool retval = false; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::id_alphabet)) { - retval = true; while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { ++m_input_pos; ++m_col; } - } - else if (has_more_input() && (*m_input_pos == '`')) { - retval = true; + + return true; + } else if (has_more_input() && (*m_input_pos == '`')) { ++m_col; ++m_input_pos; - std::string::const_iterator start = m_input_pos; + const auto start = m_input_pos; while (has_more_input() && (*m_input_pos != '`')) { if (Eol()) { @@ -736,52 +667,44 @@ namespace chaiscript ++m_col; ++m_input_pos; + + return true; } - return retval; + return false; } - /** - * Reads (and potentially captures) an identifier from input - */ - bool Id(bool t_capture = false) { + /// Reads (and potentially captures) an identifier from input + bool Id(const bool t_capture = false) { SkipWS(); if (!t_capture) { return Id_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; + } else { + const auto start = m_input_pos; + const int prev_col = m_col; + const int prev_line = m_line; if (Id_()) { + std::string match; if (*start == '`') { //Id Literal - std::string match(start+1, m_input_pos-1); - AST_NodePtr t(new eval::Id_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; + match = std::string(start+1, m_input_pos-1); + } else { + match = std::string(start, m_input_pos); } - else { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Id_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - } - else { + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + return true; + } else { return false; } } } - /** - * Checks for a node annotation of the form "#" - */ + /// Checks for a node annotation of the form "#" bool Annotation() { SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; if (Symbol_("#")) { do { while (m_input_pos != m_input_end) { @@ -796,8 +719,7 @@ namespace chaiscript } while (Symbol("#")); std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Annotation_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); return true; } else { @@ -805,13 +727,9 @@ namespace chaiscript } } - /** - * Reads a quoted string from input, without skipping initial whitespace - */ + /// Reads a quoted string from input, without skipping initial whitespace bool Quoted_String_() { - bool retval = false; if (has_more_input() && (*m_input_pos == '\"')) { - retval = true; char prev_char = *m_input_pos; ++m_input_pos; ++m_col; @@ -820,8 +738,7 @@ namespace chaiscript if (!Eol_()) { if (prev_char == '\\') { prev_char = 0; - } - else { + } else { prev_char = *m_input_pos; } ++m_input_pos; @@ -832,33 +749,32 @@ namespace chaiscript if (has_more_input()) { ++m_input_pos; ++m_col; - } - else { + } else { throw exception::eval_error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); } + + return true; } - return retval; + return false; } - /** - * Reads (and potentially captures) a quoted string from input. Translates escaped sequences. - */ - bool Quoted_String(bool t_capture = false) { + /// Reads (and potentially captures) a quoted string from input. Translates escaped sequences. + bool Quoted_String(const bool t_capture = false) { SkipWS(); if (!t_capture) { return Quoted_String_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; + } else { + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + if (Quoted_String_()) { std::string match; bool is_escaped = false; bool is_interpolated = false; bool saw_interpolation_marker = false; - size_t prev_stack_top = m_match_stack.size(); + const auto prev_stack_top = m_match_stack.size(); std::string::const_iterator s = start + 1, end = m_input_pos - 1; @@ -869,76 +785,62 @@ namespace chaiscript if (is_interpolated) { //If we've seen previous interpolation, add on instead of making a new one + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - - build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); - } - else { - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + build_match(std::make_shared(), prev_stack_top); + } else { + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); } //We've finished with the part of the string up to this point, so clear it - match = ""; + match.clear(); std::string eval_match; ++s; - while ((*s != '}') && (s != end)) { + while ((s != end) && (*s != '}')) { eval_match.push_back(*s); ++s; } + if (*s == '}') { is_interpolated = true; ++s; - size_t tostr_stack_top = m_match_stack.size(); + const auto tostr_stack_top = m_match_stack.size(); - AST_NodePtr tostr(new eval::Id_AST_Node("to_string", m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(tostr); + m_match_stack.push_back(std::make_shared("to_string", m_filename, prev_line, prev_col, m_line, m_col)); - size_t ev_stack_top = m_match_stack.size(); + const auto ev_stack_top = m_match_stack.size(); - AST_NodePtr ev(new eval::Id_AST_Node("eval", m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(ev); + /// \todo can we evaluate this in place and save the runtime cost of evaluating with each execution of the node? + m_match_stack.push_back(std::make_shared("eval", m_filename, prev_line, prev_col, m_line, m_col)); - size_t arg_stack_top = m_match_stack.size(); + const auto arg_stack_top = m_match_stack.size(); - AST_NodePtr t(new eval::Quoted_String_AST_Node(eval_match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(eval_match, m_filename, prev_line, prev_col, m_line, m_col)); - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), arg_stack_top); - - build_match(AST_NodePtr(new eval::Inplace_Fun_Call_AST_Node()), ev_stack_top); - - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), ev_stack_top); - - build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), tostr_stack_top); - - build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); - } - else { + build_match(std::make_shared(), arg_stack_top); + build_match(std::make_shared(), ev_stack_top); + build_match(std::make_shared(), ev_stack_top); + build_match(std::make_shared(), tostr_stack_top); + build_match(std::make_shared(), prev_stack_top); + } else { throw exception::eval_error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); } - } - else { + } else { match.push_back('$'); } saw_interpolation_marker = false; - } - else { + } else { if (*s == '\\') { if (is_escaped) { match.push_back('\\'); is_escaped = false; - } - else { + } else { is_escaped = true; } - } - else { + } else { if (is_escaped) { switch (*s) { case ('b') : match.push_back('\b'); break; @@ -947,15 +849,13 @@ namespace chaiscript case ('r') : match.push_back('\r'); break; case ('t') : match.push_back('\t'); break; case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; + case ('\"') : match.push_back('\"'); break; case ('$') : match.push_back('$'); break; default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); } - } - else if (*s == '$') { + } else if (*s == '$') { saw_interpolation_marker = true; - } - else { + } else { match.push_back(*s); } is_escaped = false; @@ -963,1551 +863,1425 @@ namespace chaiscript ++s; } } - if (is_interpolated) { - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); + if (is_interpolated) { + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); + + build_match(std::make_shared(), prev_stack_top); + } else { + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); } - else { - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + return true; + } else { + return false; + } + } + } + + /// Reads a character group from input, without skipping initial whitespace + bool Single_Quoted_String_() { + bool retval = false; + if (has_more_input() && (*m_input_pos == '\'')) { + retval = true; + char prev_char = *m_input_pos; + ++m_input_pos; + ++m_col; + + while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { + if (!Eol_()) { + if (prev_char == '\\') { + prev_char = 0; + } else { + prev_char = *m_input_pos; + } + ++m_input_pos; + ++m_col; } + } + + if (m_input_pos != m_input_end) { + ++m_input_pos; + ++m_col; + } else { + throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); + } + } + return retval; + } + + /// Reads (and potentially captures) a char group from input. Translates escaped sequences. + bool Single_Quoted_String(const bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Single_Quoted_String_(); + } else { + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + if (Single_Quoted_String_()) { + std::string match; + bool is_escaped = false; + for (auto s = start + 1, end = m_input_pos - 1; s != end; ++s) { + if (*s == '\\') { + if (is_escaped) { + match.push_back('\\'); + is_escaped = false; + } else { + is_escaped = true; + } + } else { + if (is_escaped) { + switch (*s) { + case ('b') : match.push_back('\b'); break; + case ('f') : match.push_back('\f'); break; + case ('n') : match.push_back('\n'); break; + case ('r') : match.push_back('\r'); break; + case ('t') : match.push_back('\t'); break; + case ('\'') : match.push_back('\''); break; + case ('\"') : match.push_back('\"'); break; + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); + } + } else { + match.push_back(*s); + } + is_escaped = false; + } + } + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); return true; } else { return false; } - } } + } - /** - * Reads a character group from input, without skipping initial whitespace - */ - bool Single_Quoted_String_() { - bool retval = false; - if (has_more_input() && (*m_input_pos == '\'')) { - retval = true; - char prev_char = *m_input_pos; - ++m_input_pos; - ++m_col; - - while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { - if (!Eol_()) { - if (prev_char == '\\') { - prev_char = 0; - } - else { - prev_char = *m_input_pos; - } - ++m_input_pos; - ++m_col; - } - } - - if (m_input_pos != m_input_end) { - ++m_input_pos; - ++m_col; - } - else { - throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); - } - } - return retval; + /// Reads a char from input if it matches the parameter, without skipping initial whitespace + bool Char_(const char c) { + if (has_more_input() && (*m_input_pos == c)) { + ++m_input_pos; + ++m_col; + return true; + } else { + return false; } + } - /** - * Reads (and potentially captures) a char group from input. Translates escaped sequences. - */ - bool Single_Quoted_String(bool t_capture = false) { - SkipWS(); + /// Reads (and potentially captures) a char from input if it matches the parameter + bool Char(const char t_c, bool t_capture = false) { + SkipWS(); - if (!t_capture) { - return Single_Quoted_String_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Single_Quoted_String_()) { - std::string match; - bool is_escaped = false; - for (std::string::const_iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { - if (*s == '\\') { - if (is_escaped) { - match.push_back('\\'); - is_escaped = false; - } - else { - is_escaped = true; - } - } - else { - if (is_escaped) { - switch (*s) { - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); - } - } - else { - match.push_back(*s); - } - is_escaped = false; - } - } - AST_NodePtr t(new eval::Single_Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - return false; - } - } - } - - /** - * Reads a char from input if it matches the parameter, without skipping initial whitespace - */ - bool Char_(char c) { - bool retval = false; - if (has_more_input() && (*m_input_pos == c)) { - ++m_input_pos; - ++m_col; - retval = true; - } - - return retval; - } - - /** - * Reads (and potentially captures) a char from input if it matches the parameter - */ - bool Char(char t_c, bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Char_(t_c); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Char_(t_c)) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Char_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - return false; - } - } - } - - /** - * Reads a string from input if it matches the parameter, without skipping initial whitespace - */ - bool Keyword_(const char *t_s) { - bool retval = false; - size_t len = strlen(t_s); - - if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { - std::string::const_iterator tmp = m_input_pos; - for (size_t i = 0; i < len; ++i) { - if (*tmp != t_s[i]) { - return false; - } - ++tmp; - } - retval = true; - m_input_pos = tmp; - m_col += static_cast(len); - } - - return retval; - } - - /** - * Reads (and potentially captures) a string from input if it matches the parameter - */ - bool Keyword(const char *t_s, bool t_capture = false) { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - bool retval = Keyword_(t_s); - // ignore substring matches - if ( retval && has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { - m_input_pos = start; - m_col = prev_col; - m_line = prev_line; - retval = false; - } - - if ( t_capture && retval ) { + if (!t_capture) { + return Char_(t_c); + } else { + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + if (Char_(t_c)) { std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Str_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + return true; + } else { + return false; } - return retval; } + } - /** - * Reads a symbol group from input if it matches the parameter, without skipping initial whitespace - */ - bool Symbol_(const char *t_s) { - bool retval = false; - size_t len = strlen(t_s); + /// Reads a string from input if it matches the parameter, without skipping initial whitespace + bool Keyword_(const char *t_s) { + const auto len = strlen(t_s); - if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { - std::string::const_iterator tmp = m_input_pos; - for (size_t i = 0; i < len; ++i) { - if (*tmp != t_s[i]) { - return false; - } - ++tmp; - } - retval = true; - m_input_pos = tmp; - m_col += static_cast(len); - } - - return retval; - } - - /** - * Reads (and potentially captures) a symbol group from input if it matches the parameter - */ - bool Symbol(const char *t_s, bool t_capture = false, bool t_disallow_prevention=false) { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - bool retval = Symbol_(t_s); - // ignore substring matches - if (retval && has_more_input() && (t_disallow_prevention == false) && char_in_alphabet(*m_input_pos,detail::symbol_alphabet)) { - m_input_pos = start; - m_col = prev_col; - m_line = prev_line; - retval = false; - } - - if ( t_capture && retval ) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Str_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - - return retval; - } - - /** - * Reads an end-of-line group from input, without skipping initial whitespace - */ - bool Eol_() { - 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_(';')) { - retval = true; - } - - return retval; - } - - /** - * Reads (and potentially captures) an end-of-line group from input - */ - bool Eol(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Eol_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Eol_()) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Eol_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { + if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { + auto tmp = m_input_pos; + for (size_t i = 0; i < len; ++i) { + if (*tmp != t_s[i]) { return false; } + ++tmp; } + m_input_pos = tmp; + m_col += static_cast(len); + return true; } - /** - * Reads a comma-separated list of values from input - */ - bool Arg_List() { + return false; + } - SkipWS(true); - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Equation()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Equation()) { - throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - - SkipWS(true); - - return retval; + /// Reads (and potentially captures) a string from input if it matches the parameter + bool Keyword(const char *t_s, bool t_capture = false) { + SkipWS(); + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + bool retval = Keyword_(t_s); + // ignore substring matches + if ( retval && has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { + m_input_pos = start; + m_col = prev_col; + m_line = prev_line; + retval = false; } - /** - * Reads possible special container values, including ranges and map_pairs - */ - bool Container_Arg_List() { - bool retval = false; - SkipWS(true); + if ( t_capture && retval ) { + std::string match(start, m_input_pos); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + } + return retval; + } - size_t prev_stack_top = m_match_stack.size(); + /// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace + bool Symbol_(const char *t_s) { + const auto len = strlen(t_s); - if (Value_Range()) { - retval = true; - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - else if (Map_Pair()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Map_Pair()) { - throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); + if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { + auto tmp = m_input_pos; + for (size_t i = 0; i < len; ++i) { + if (*tmp != t_s[i]) { + return false; } - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + ++tmp; } - else if (Operator()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Operator()) { - throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - - SkipWS(true); - - return retval; - + m_input_pos = tmp; + m_col += static_cast(len); + return true; } - /** - * Reads a lambda (anonymous function) from input - */ - bool Lambda() { - bool retval = false; + return false; + } - size_t prev_stack_top = m_match_stack.size(); + /// Reads (and potentially captures) a symbol group from input if it matches the parameter + bool Symbol(const char *t_s, const bool t_capture = false, const bool t_disallow_prevention=false) { + SkipWS(); + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + bool retval = Symbol_(t_s); - if (Keyword("fun")) { - retval = true; + // ignore substring matches + if (retval && has_more_input() && (t_disallow_prevention == false) && char_in_alphabet(*m_input_pos,detail::symbol_alphabet)) { + m_input_pos = start; + m_col = prev_col; + m_line = prev_line; + retval = false; + } - if (Char('(')) { - Arg_List(); - if (!Char(')')) { - throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); + if ( t_capture && retval ) { + std::string match(start, m_input_pos); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + } + + return retval; + } + + /// Reads an end-of-line group from input, without skipping initial whitespace + bool Eol_() { + 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_(';')) { + retval = true; + } + + return retval; + } + + /// Reads (and potentially captures) an end-of-line group from input + bool Eol(const bool t_capture = false) { + 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_()) { + std::string match(start, m_input_pos); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + return true; + } else { + return false; + } + } + } + + /// Reads a comma-separated list of values from input + bool Arg_List() { + SkipWS(true); + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Equation()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Equation()) { + throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); } - } + } while (Char(',')); + } + build_match(std::make_shared(), prev_stack_top); + } - while (Eol()) {} + SkipWS(true); - if (!Block()) { + return retval; + } + + /// Reads possible special container values, including ranges and map_pairs + bool Container_Arg_List() { + bool retval = false; + SkipWS(true); + + const auto prev_stack_top = m_match_stack.size(); + + if (Value_Range()) { + retval = true; + build_match(std::make_shared(), prev_stack_top); + } else if (Map_Pair()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Map_Pair()) { + throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + } + } while (Char(',')); + } + build_match(std::make_shared(), prev_stack_top); + } else if (Operator()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Operator()) { + throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + } + } while (Char(',')); + } + build_match(std::make_shared(), prev_stack_top); + } + + SkipWS(true); + + return retval; + } + + /// Reads a lambda (anonymous function) from input + bool Lambda() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("fun")) { + retval = true; + + if (Char('(')) { + Arg_List(); + if (!Char(')')) { throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); } - - build_match(AST_NodePtr(new eval::Lambda_AST_Node()), prev_stack_top); } - return retval; + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); } - /** - * Reads a function definition from input - */ - bool Def(bool t_class_context = false) { - bool retval = false; - bool is_annotated = false; - AST_NodePtr annotation; + return retval; + } - if (Annotation()) { - while (Eol_()) {} - annotation = m_match_stack.back(); - m_match_stack.pop_back(); - is_annotated = true; + /// Reads a function definition from input + bool Def(const bool t_class_context = false) { + bool retval = false; + AST_NodePtr annotation; + + if (Annotation()) { + while (Eol_()) {} + annotation = m_match_stack.back(); + m_match_stack.pop_back(); + } + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("def")) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Missing function name in definition", File_Position(m_line, m_col), *m_filename); } - size_t prev_stack_top = m_match_stack.size(); + bool is_method = false; - if (Keyword("def")) { - retval = true; + if (Symbol("::", false)) { + //We're now a method + is_method = true; if (!Id(true)) { - throw exception::eval_error("Missing function name in definition", File_Position(m_line, m_col), *m_filename); - } - - bool is_method = false; - - if (Symbol("::", false)) { - //We're now a method - is_method = true; - - if (!Id(true)) { - throw exception::eval_error("Missing method name in definition", File_Position(m_line, m_col), *m_filename); - } - } - - if (Char('(')) { - Arg_List(); - if (!Char(')')) { - throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); - } - } - - while (Eol()) {} - - if (Char(':')) { - if (!Operator()) { - throw exception::eval_error("Missing guard expression for function", File_Position(m_line, m_col), *m_filename); - } - } - - while (Eol()) {} - if (!Block()) { - throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); - } - - if (is_method || t_class_context) { - build_match(AST_NodePtr(new eval::Method_AST_Node()), prev_stack_top); - } - else { - build_match(AST_NodePtr(new eval::Def_AST_Node()), prev_stack_top); - } - - if (is_annotated) { - m_match_stack.back()->annotation = annotation; + throw exception::eval_error("Missing method name in definition", File_Position(m_line, m_col), *m_filename); } } - return retval; + if (Char('(')) { + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); + } + } + + while (Eol()) {} + + if (Char(':')) { + if (!Operator()) { + throw exception::eval_error("Missing guard expression for function", File_Position(m_line, m_col), *m_filename); + } + } + + while (Eol()) {} + if (!Block()) { + throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); + } + + if (is_method || t_class_context) { + build_match(std::make_shared(), prev_stack_top); + } else { + build_match(std::make_shared(), prev_stack_top); + } + + if (annotation) { + m_match_stack.back()->annotation = std::move(annotation); + } } - /** - * Reads a function definition from input - */ - bool Try() { - bool retval = false; + return retval; + } - size_t prev_stack_top = m_match_stack.size(); + /// Reads a function definition from input + bool Try() { + bool retval = false; - if (Keyword("try")) { - retval = true; + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("try")) { + retval = true; + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'try' block", File_Position(m_line, m_col), *m_filename); + } + + bool has_matches = true; + while (has_matches) { + while (Eol()) {} + has_matches = false; + if (Keyword("catch", false)) { + const auto catch_stack_top = m_match_stack.size(); + if (Char('(')) { + if (!(Id(true) && Char(')'))) { + throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); + } + if (Char(':')) { + if (!Operator()) { + throw exception::eval_error("Missing guard expression for catch", File_Position(m_line, m_col), *m_filename); + } + } + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); + } + build_match(std::make_shared(), catch_stack_top); + has_matches = true; + } + } + while (Eol()) {} + if (Keyword("finally", false)) { + const auto finally_stack_top = m_match_stack.size(); while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'try' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); } + build_match(std::make_shared(), finally_stack_top); + } - bool has_matches = true; - while (has_matches) { - while (Eol()) {} - has_matches = false; - if (Keyword("catch", false)) { - size_t catch_stack_top = m_match_stack.size(); - if (Char('(')) { - if (!(Id(true) && Char(')'))) { - throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); - } - if (Char(':')) { - if (!Operator()) { - throw exception::eval_error("Missing guard expression for catch", File_Position(m_line, m_col), *m_filename); - } - } + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads an if/else if/else block from input + bool If() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("if")) { + retval = true; + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'if' block", File_Position(m_line, m_col), *m_filename); + } + + bool has_matches = true; + while (has_matches) { + while (Eol()) {} + has_matches = false; + if (Keyword("else", true)) { + if (Keyword("if")) { + const AST_NodePtr back(m_match_stack.back()); + m_match_stack.back() = std::make_shared("else if"); + m_match_stack.back()->start = back->start; + m_match_stack.back()->end = back->end; + m_match_stack.back()->children = back->children; + m_match_stack.back()->annotation = back->annotation; + if (!Char('(')) { + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); } while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'else if' block", File_Position(m_line, m_col), *m_filename); + } + has_matches = true; + } else { + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'else' block", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new eval::Catch_AST_Node()), catch_stack_top); has_matches = true; } } - while (Eol()) {} - if (Keyword("finally", false)) { - size_t finally_stack_top = m_match_stack.size(); - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); - } - build_match(AST_NodePtr(new eval::Finally_AST_Node()), finally_stack_top); - } - - build_match(AST_NodePtr(new eval::Try_AST_Node()), prev_stack_top); } - return retval; + build_match(std::make_shared(), prev_stack_top); } - /** - * Reads an if/else if/else block from input - */ - bool If() { - bool retval = false; + return retval; + } - size_t prev_stack_top = m_match_stack.size(); + /// Reads a class block from input + bool Class() { + bool retval = false; - if (Keyword("if")) { - retval = true; + size_t prev_stack_top = m_match_stack.size(); - if (!Char('(')) { - throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); - } + if (Keyword("class")) { + retval = true; - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'if' block", File_Position(m_line, m_col), *m_filename); - } - - bool has_matches = true; - while (has_matches) { - while (Eol()) {} - has_matches = false; - if (Keyword("else", true)) { - if (Keyword("if")) { - AST_NodePtr back(m_match_stack.back()); - m_match_stack.back() = AST_NodePtr(new eval::If_AST_Node("else if")); - m_match_stack.back()->start = back->start; - m_match_stack.back()->end = back->end; - m_match_stack.back()->children = back->children; - m_match_stack.back()->annotation = back->annotation; - if (!Char('(')) { - throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'else if' block", File_Position(m_line, m_col), *m_filename); - } - has_matches = true; - } - else { - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'else' block", File_Position(m_line, m_col), *m_filename); - } - has_matches = true; - } - } - } - - build_match(AST_NodePtr(new eval::If_AST_Node()), prev_stack_top); + if (!Id(true)) { + throw exception::eval_error("Missing class name in definition", File_Position(m_line, m_col), *m_filename); } - return retval; - } - /** - * Reads a class block from input - */ - bool Class() { - bool retval = false; + while (Eol()) {} - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("class")) { - retval = true; - - if (!Id(true)) { - throw exception::eval_error("Missing class name in definition", File_Position(m_line, m_col), *m_filename); - } - - - while (Eol()) {} - - if (!Class_Block()) { - throw exception::eval_error("Incomplete 'class' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Class_AST_Node()), prev_stack_top); + if (!Class_Block()) { + throw exception::eval_error("Incomplete 'class' block", File_Position(m_line, m_col), *m_filename); } - return retval; + build_match(std::make_shared(), prev_stack_top); } + return retval; + } - /** - * Reads a while block from input - */ - bool While() { - bool retval = false; - size_t prev_stack_top = m_match_stack.size(); + /// Reads a while block from input + bool While() { + bool retval = false; - if (Keyword("while")) { - retval = true; + const auto prev_stack_top = m_match_stack.size(); - if (!Char('(')) { - throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); - } + if (Keyword("while")) { + retval = true; - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'while' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::While_AST_Node()), prev_stack_top); + if (!Char('(')) { + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); } - return retval; + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'while' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); } + return retval; + } - /** - * Reads the C-style for conditions from input - */ - bool For_Guards() { - if (!(Equation() && Eol())) + + /// Reads the C-style for conditions from input + bool For_Guards() { + if (!(Equation() && Eol())) + { + if (!Eol()) { - if (!Eol()) - { - throw exception::eval_error("'for' loop initial statment missing", File_Position(m_line, m_col), *m_filename); - } else { - AST_NodePtr t(new eval::Noop_AST_Node()); - m_match_stack.push_back(t); - } - } - - if (!(Equation() && Eol())) - { - if (!Eol()) - { - throw exception::eval_error("'for' loop condition missing", File_Position(m_line, m_col), *m_filename); - } else { - AST_NodePtr t(new eval::Noop_AST_Node()); - m_match_stack.push_back(t); - } - } - - if (!Equation()) - { - AST_NodePtr t(new eval::Noop_AST_Node()); - m_match_stack.push_back(t); - } - - return true; - } - - /** - * Reads a for block from input - */ - bool For() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("for")) { - retval = true; - - if (!Char('(')) { - throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(For_Guards() && Char(')'))) { - throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'for' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::For_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a case block from input - */ - bool Case() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("case")) { - retval = true; - - if (!Char('(')) { - throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'case' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Case_AST_Node()), prev_stack_top); - } - else if (Keyword("default")) { - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'default' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Default_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a switch statement from input - */ - bool Switch() { - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("switch")) { - - if (!Char('(')) { - throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (Char('{')) { - while (Eol()) {} - - while (Case()) { - while (Eol()) { } // eat - } - - while (Eol()) { } // eat - - if (!Char('}')) { - throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); - } - } - else { - throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Switch_AST_Node()), prev_stack_top); - return true; - + throw exception::eval_error("'for' loop initial statment missing", File_Position(m_line, m_col), *m_filename); } else { - return false; + m_match_stack.push_back(std::make_shared()); } - } - /** - * Reads a curly-brace C-style class block from input - */ - bool Class_Block() { - bool retval = false; + if (!(Equation() && Eol())) + { + if (!Eol()) + { + throw exception::eval_error("'for' loop condition missing", File_Position(m_line, m_col), *m_filename); + } else { + m_match_stack.push_back(std::make_shared()); + } + } - size_t prev_stack_top = m_match_stack.size(); + if (!Equation()) + { + m_match_stack.push_back(std::make_shared()); + } + + return true; + } + + /** + * Reads a for block from input + */ + bool For() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("for")) { + retval = true; + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(For_Guards() && Char(')'))) { + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'for' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads a case block from input + bool Case() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("case")) { + retval = true; + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'case' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Keyword("default")) { + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'default' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + + /// Reads a switch statement from input + bool Switch() { + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("switch")) { + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} if (Char('{')) { - retval = true; + while (Eol()) {} - Class_Statements(); - if (!Char('}')) { - throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename); + while (Case()) { + while (Eol()) { } // eat } - build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top); - } + while (Eol()) { } // eat - return retval; - } - - /** - * Reads a curly-brace C-style block from input - */ - bool Block() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Char('{')) { - retval = true; - - Statements(); if (!Char('}')) { throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); } - - build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a return statement from input - */ - bool Return() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("return")) { - retval = true; - - Operator(); - build_match(AST_NodePtr(new eval::Return_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a break statement from input - */ - bool Break() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("break")) { - retval = true; - - build_match(AST_NodePtr(new eval::Break_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a continue statement from input - */ - bool Continue() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("continue")) { - retval = true; - - build_match(AST_NodePtr(new eval::Continue_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a dot expression(member access), then proceeds to check if it's a function or array call - */ - bool Dot_Fun_Array() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - if (Lambda() || Num(true) || Quoted_String(true) || Single_Quoted_String(true) || - Paren_Expression() || Inline_Container() || Id(true)) { - retval = true; - bool has_more = true; - - while (has_more) { - has_more = false; - - if (Char('(')) { - has_more = true; - - Arg_List(); - if (!Char(')')) { - throw exception::eval_error("Incomplete function call", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), prev_stack_top); - /// \todo Work around for method calls until we have a better solution - if (!m_match_stack.back()->children.empty()) { - if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) { - AST_NodePtr dot_access = m_match_stack.back()->children[0]; - AST_NodePtr func_call = m_match_stack.back(); - m_match_stack.pop_back(); - func_call->children.erase(func_call->children.begin()); - func_call->children.insert(func_call->children.begin(), dot_access->children.back()); - dot_access->children.pop_back(); - dot_access->children.push_back(func_call); - m_match_stack.push_back(dot_access); - } - } - } - else if (Char('[')) { - has_more = true; - - if (!(Operator() && Char(']'))) { - throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Array_Call_AST_Node()), prev_stack_top); - } - else if (Symbol(".", true)) { - has_more = true; - if (!(Id(true))) { - throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Dot_Access_AST_Node()), prev_stack_top); - } - } - } - - return retval; - } - - /** - * Reads a variable declaration from input - */ - bool Var_Decl(bool t_class_context = false) { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) { - retval = true; - - if (!Id(true)) { - throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top); - } else if (Keyword("auto") || Keyword("var")) { - retval = true; - - if (!(Reference() || Id(true))) { - throw exception::eval_error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Var_Decl_AST_Node()), prev_stack_top); - } else if (Keyword("attr")) { - retval = true; - - if (!Id(true)) { - throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - if (!Symbol("::", false)) { - throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - if (!Id(true)) { - throw exception::eval_error("Missing attribute name in definition", File_Position(m_line, m_col), *m_filename); - } - - - build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads an expression surrounded by parentheses from input - */ - bool Paren_Expression() { - bool retval = false; - - if (Char('(')) { - retval = true; - if (!Operator()) { - throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename); - } - if (!Char(')')) { - throw exception::eval_error("Missing closing parenthesis ')'", File_Position(m_line, m_col), *m_filename); - } - } - return retval; - } - - /** - * Reads, and identifies, a short-form container initialization from input - */ - bool Inline_Container() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Char('[')) { - retval = true; - Container_Arg_List(); - - if (!Char(']')) { - throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_line, m_col), *m_filename); - } - if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { - if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { - build_match(AST_NodePtr(new eval::Inline_Range_AST_Node()), prev_stack_top); - } - else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { - build_match(AST_NodePtr(new eval::Inline_Map_AST_Node()), prev_stack_top); - } - else { - build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); - } - } - else { - build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); - } - } - - return retval; - } - - bool Reference() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Symbol("&", false)) { - retval = true; - - if (!Id(true)) { - throw exception::eval_error("Incomplete '&' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr( - new eval::Reference_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a unary prefixed expression from input - */ - bool Prefix() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Symbol("++", true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Symbol("--", true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('-', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('+', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('!', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('~', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('&', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Parses any of a group of 'value' style ast_node groups from input - */ - bool Value() { - if (Var_Decl() || Dot_Fun_Array() || Prefix()) { - return true; } else { - return false; + throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); } - } - bool Operator_Helper(size_t t_precedence) { - for (auto & elem : m_operator_matches[t_precedence]) { - if (Symbol(elem.c_str(), true)) { - return true; - } - } + build_match(std::make_shared(), prev_stack_top); + return true; + + } else { return false; } - bool Operator(size_t t_precedence = 0) { - bool retval = false; - AST_NodePtr oper; - size_t prev_stack_top = m_match_stack.size(); + } - if (t_precedence < m_operators.size()) { - if (Operator(t_precedence+1)) { - retval = true; - if (Operator_Helper(t_precedence)) { - do { - while (Eol()) {} - if (!Operator(t_precedence+1)) { - throw exception::eval_error("Incomplete " - + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", - File_Position(m_line, m_col), *m_filename); - } - switch (m_operators[t_precedence]) { - case(AST_Node_Type::Comparison) : - build_match(AST_NodePtr(new eval::Comparison_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Ternary_Cond) : - m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, - m_match_stack.begin() + m_match_stack.size() - 1); - if (Symbol(":")) { - if (!Operator(t_precedence+1)) { - throw exception::eval_error("Incomplete " - + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", - File_Position(m_line, m_col), *m_filename); - } - build_match(AST_NodePtr(new eval::Ternary_Cond_AST_Node()), prev_stack_top); - } - else { + /// Reads a curly-brace C-style class block from input + bool Class_Block() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Char('{')) { + retval = true; + + Class_Statements(); + if (!Char('}')) { + throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads a curly-brace C-style block from input + bool Block() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Char('{')) { + retval = true; + + Statements(); + if (!Char('}')) { + throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads a return statement from input + bool Return() { + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("return")) { + Operator(); + build_match(std::make_shared(), prev_stack_top); + return true; + } else { + return false; + } + } + + /// Reads a break statement from input + bool Break() { + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("break")) { + build_match(std::make_shared(), prev_stack_top); + return true; + } else { + return false; + } + } + + /// Reads a continue statement from input + bool Continue() { + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("continue")) { + build_match(std::make_shared(), prev_stack_top); + return true; + } else { + return false; + } + } + + /// Reads a dot expression(member access), then proceeds to check if it's a function or array call + bool Dot_Fun_Array() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + if (Lambda() || Num(true) || Quoted_String(true) || Single_Quoted_String(true) || + Paren_Expression() || Inline_Container() || Id(true)) + { + retval = true; + bool has_more = true; + + while (has_more) { + has_more = false; + + if (Char('(')) { + has_more = true; + + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete function call", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + /// \todo Work around for method calls until we have a better solution + if (!m_match_stack.back()->children.empty()) { + if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) { + AST_NodePtr dot_access = m_match_stack.back()->children[0]; + AST_NodePtr func_call = m_match_stack.back(); + m_match_stack.pop_back(); + func_call->children.erase(func_call->children.begin()); + func_call->children.insert(func_call->children.begin(), dot_access->children.back()); + dot_access->children.pop_back(); + dot_access->children.push_back(std::move(func_call)); + m_match_stack.push_back(std::move(dot_access)); + } + } + } else if (Char('[')) { + has_more = true; + + if (!(Operator() && Char(']'))) { + throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else if (Symbol(".", true)) { + has_more = true; + if (!(Id(true))) { + throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + } + } + + return retval; + } + + /// Reads a variable declaration from input + bool Var_Decl(const bool t_class_context = false) { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Keyword("auto") || Keyword("var")) { + retval = true; + + if (!(Reference() || Id(true))) { + throw exception::eval_error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Keyword("attr")) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + if (!Symbol("::", false)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + if (!Id(true)) { + throw exception::eval_error("Missing attribute name in definition", File_Position(m_line, m_col), *m_filename); + } + + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads an expression surrounded by parentheses from input + bool Paren_Expression() { + if (Char('(')) { + if (!Operator()) { + throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename); + } + if (!Char(')')) { + throw exception::eval_error("Missing closing parenthesis ')'", File_Position(m_line, m_col), *m_filename); + } + return true; + } else { + return false; + } + } + + /// Reads, and identifies, a short-form container initialization from input + bool Inline_Container() { + const auto prev_stack_top = m_match_stack.size(); + + if (Char('[')) { + Container_Arg_List(); + + if (!Char(']')) { + throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_line, m_col), *m_filename); + } + if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { + if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { + build_match(std::make_shared(), prev_stack_top); + } + else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { + build_match(std::make_shared(), prev_stack_top); + } + else { + build_match(std::make_shared(), prev_stack_top); + } + } + else { + build_match(std::make_shared(), prev_stack_top); + } + + return true; + } else { + return false; + } + } + + /// Parses a variable specified with a & aka reference + bool Reference() { + const auto prev_stack_top = m_match_stack.size(); + + if (Symbol("&", false)) { + if (!Id(true)) { + throw exception::eval_error("Incomplete '&' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + return true; + } else { + return false; + } + } + + /// Reads a unary prefixed expression from input + bool Prefix() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Symbol("++", true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Symbol("--", true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Char('-', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Char('+', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else if (Char('!', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else if (Char('~', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else if (Char('&', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Parses any of a group of 'value' style ast_node groups from input + bool Value() { + if (Var_Decl() || Dot_Fun_Array() || Prefix()) { + return true; + } else { + return false; + } + } + + bool Operator_Helper(const size_t t_precedence) { + for (auto & elem : m_operator_matches[t_precedence]) { + if (Symbol(elem.c_str(), true)) { + return true; + } + } + return false; + } + + bool Operator(const size_t t_precedence = 0) { + bool retval = false; + AST_NodePtr oper; + const auto prev_stack_top = m_match_stack.size(); + + if (t_precedence < m_operators.size()) { + if (Operator(t_precedence+1)) { + retval = true; + if (Operator_Helper(t_precedence)) { + do { + while (Eol()) {} + if (!Operator(t_precedence+1)) { + throw exception::eval_error("Incomplete " + + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", + File_Position(m_line, m_col), *m_filename); + } + + switch (m_operators[t_precedence]) { + case(AST_Node_Type::Comparison) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Ternary_Cond) : + m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, + m_match_stack.begin() + m_match_stack.size() - 1); + if (Symbol(":")) { + if (!Operator(t_precedence+1)) { throw exception::eval_error("Incomplete " + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", File_Position(m_line, m_col), *m_filename); } - break; - case(AST_Node_Type::Addition) : - oper = m_match_stack.at(m_match_stack.size()-2); - m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, - m_match_stack.begin() + m_match_stack.size() - 1); - if (oper->text == "+") { - build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); - } - else if (oper->text == "-") { - build_match(AST_NodePtr(new eval::Subtraction_AST_Node()), prev_stack_top); - } - break; - case(AST_Node_Type::Multiplication) : - oper = m_match_stack.at(m_match_stack.size()-2); - m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, - m_match_stack.begin() + m_match_stack.size() - 1); - if (oper->text == "*") { - build_match(AST_NodePtr(new eval::Multiplication_AST_Node()), prev_stack_top); - } - else if (oper->text == "/") { - build_match(AST_NodePtr(new eval::Division_AST_Node()), prev_stack_top); - } - else if (oper->text == "%") { - build_match(AST_NodePtr(new eval::Modulus_AST_Node()), prev_stack_top); - } - break; - case(AST_Node_Type::Shift) : - build_match(AST_NodePtr(new eval::Shift_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Equality) : - build_match(AST_NodePtr(new eval::Equality_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_And) : - build_match(AST_NodePtr(new eval::Bitwise_And_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_Xor) : - build_match(AST_NodePtr(new eval::Bitwise_Xor_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_Or) : - build_match(AST_NodePtr(new eval::Bitwise_Or_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Logical_And) : - build_match(AST_NodePtr(new eval::Logical_And_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Logical_Or) : - build_match(AST_NodePtr(new eval::Logical_Or_AST_Node()), prev_stack_top); - break; - default: - throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); - } - } while (Operator_Helper(t_precedence)); - } + build_match(std::make_shared(), prev_stack_top); + } + else { + throw exception::eval_error("Incomplete " + + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", + File_Position(m_line, m_col), *m_filename); + } + break; + case(AST_Node_Type::Addition) : + oper = m_match_stack.at(m_match_stack.size()-2); + m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, + m_match_stack.begin() + m_match_stack.size() - 1); + if (oper->text == "+") { + build_match(std::make_shared(), prev_stack_top); + } + else if (oper->text == "-") { + build_match(std::make_shared(), prev_stack_top); + } + break; + case(AST_Node_Type::Multiplication) : + oper = m_match_stack.at(m_match_stack.size()-2); + m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, + m_match_stack.begin() + m_match_stack.size() - 1); + if (oper->text == "*") { + build_match(std::make_shared(), prev_stack_top); + } + else if (oper->text == "/") { + build_match(std::make_shared(), prev_stack_top); + } + else if (oper->text == "%") { + build_match(std::make_shared(), prev_stack_top); + } + break; + case(AST_Node_Type::Shift) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Equality) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_And) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_Xor) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_Or) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Logical_And) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Logical_Or) : + build_match(std::make_shared(), prev_stack_top); + break; + default: + throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); + } + } while (Operator_Helper(t_precedence)); } } - else { - return Value(); - } - - return retval; + } + else { + return Value(); } - /** - * Reads a pair of values used to create a map initialization from input - */ - bool Map_Pair() { - bool retval = false; + return retval; + } - size_t prev_stack_top = m_match_stack.size(); - std::string::const_iterator prev_pos = m_input_pos; - int prev_col = m_col; + /// Reads a pair of values used to create a map initialization from input + bool Map_Pair() { + bool retval = false; - if (Operator()) { - if (Symbol(":")) { - retval = true; - if (!Operator()) { - throw exception::eval_error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); - } + const auto prev_stack_top = m_match_stack.size(); + const auto prev_pos = m_input_pos; + const auto prev_col = m_col; - build_match(AST_NodePtr(new eval::Map_Pair_AST_Node()), prev_stack_top); - } - else { - m_input_pos = prev_pos; - m_col = prev_col; - while (prev_stack_top != m_match_stack.size()) { - m_match_stack.pop_back(); - } - } - } - - return retval; - } - - /** - * Reads a pair of values used to create a range initialization from input - */ - bool Value_Range() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - std::string::const_iterator prev_pos = m_input_pos; - int prev_col = m_col; - - if (Operator()) { - if (Symbol("..")) { - retval = true; - if (!Operator()) { - throw exception::eval_error("Incomplete value range", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Value_Range_AST_Node()), prev_stack_top); - } - else { - m_input_pos = prev_pos; - m_col = prev_col; - while (prev_stack_top != m_match_stack.size()) { - m_match_stack.pop_back(); - } - } - } - - return retval; - } - - /** - * Parses a string of binary equation operators - */ - bool Equation() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Operator()) { + if (Operator()) { + if (Symbol(":")) { retval = true; - if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) || - Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true) || - Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) || - Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { - SkipWS(true); - if (!Equation()) { - throw exception::eval_error("Incomplete equation", File_Position(m_line, m_col), *m_filename); - } + if (!Operator()) { + throw exception::eval_error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); + } - build_match(AST_NodePtr(new eval::Equation_AST_Node()), prev_stack_top); - } - } - - return retval; - } - - /** - * Parses statements allowed inside of a class block - */ - bool Class_Statements() { - bool retval = false; - - bool has_more = true; - bool saw_eol = true; - - while (has_more) { - int prev_line = m_line; - int prev_col = m_col; - if (Def(true)) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } else if (Var_Decl(true)) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } else if (Eol()) { - has_more = true; - retval = true; - saw_eol = true; - } else { - has_more = false; - } - } - - return retval; - } - - /** - * Top level parser, starts parsing of all known parses - */ - bool Statements() { - bool retval = false; - - bool has_more = true; - bool saw_eol = true; - - while (has_more) { - int prev_line = m_line; - int prev_col = m_col; - if (Def()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Try()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (If()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (While()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Class()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (For()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Switch()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Return()) { - if (!saw_eol) { - throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Break()) { - if (!saw_eol) { - throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Continue()) { - if (!saw_eol) { - throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Block()) { - has_more = true; - retval = true; - saw_eol = true; - } - else if (Equation()) { - if (!saw_eol) { - throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Eol()) { - has_more = true; - retval = true; - saw_eol = true; - } - else { - has_more = false; - } - } - - return retval; - } - - /** - * Parses the given input string, tagging parsed ast_nodes with the given m_filename. - */ - bool parse(const std::string &t_input, const std::string &t_fname) { - m_input_pos = t_input.begin(); - m_input_end = t_input.end(); - m_line = 1; - m_col = 1; - m_filename = std::shared_ptr(new std::string(t_fname)); - - if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { - while ((m_input_pos != m_input_end) && (!Eol())) { - ++m_input_pos; - } - /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) - } - - if (Statements()) { - if (m_input_pos != m_input_end) { - throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); - } - else { - build_match(AST_NodePtr(new eval::File_AST_Node()), 0); - return true; - } + build_match(std::make_shared(), prev_stack_top); } else { - return false; + m_input_pos = prev_pos; + m_col = prev_col; + while (prev_stack_top != m_match_stack.size()) { + m_match_stack.pop_back(); + } } } - }; + + return retval; + } + + /// Reads a pair of values used to create a range initialization from input + bool Value_Range() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + const auto prev_pos = m_input_pos; + const auto prev_col = m_col; + + if (Operator()) { + if (Symbol("..")) { + retval = true; + if (!Operator()) { + throw exception::eval_error("Incomplete value range", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else { + m_input_pos = prev_pos; + m_col = prev_col; + while (prev_stack_top != m_match_stack.size()) { + m_match_stack.pop_back(); + } + } + } + + return retval; + } + + /// Parses a string of binary equation operators + bool Equation() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Operator()) { + retval = true; + if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) || + Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true) || + Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) || + Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { + SkipWS(true); + if (!Equation()) { + throw exception::eval_error("Incomplete equation", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + } + + return retval; + } + + /// Parses statements allowed inside of a class block + bool Class_Statements() { + bool retval = false; + + bool has_more = true; + bool saw_eol = true; + + while (has_more) { + const auto prev_line = m_line; + const auto prev_col = m_col; + if (Def(true)) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } else if (Var_Decl(true)) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } else if (Eol()) { + has_more = true; + retval = true; + saw_eol = true; + } else { + has_more = false; + } + } + + return retval; + } + + /// Top level parser, starts parsing of all known parses + bool Statements() { + bool retval = false; + + bool has_more = true; + bool saw_eol = true; + + while (has_more) { + int prev_line = m_line; + int prev_col = m_col; + if (Def()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Try()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (If()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (While()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Class()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (For()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Switch()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Return()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Break()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Continue()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Block()) { + has_more = true; + retval = true; + saw_eol = true; + } + else if (Equation()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Eol()) { + has_more = true; + retval = true; + saw_eol = true; + } + else { + has_more = false; + } + } + + return retval; + } + + /// Parses the given input string, tagging parsed ast_nodes with the given m_filename. + bool parse(const std::string &t_input, std::string t_fname) { + m_input_pos = t_input.begin(); + m_input_end = t_input.end(); + m_line = 1; + m_col = 1; + m_filename = std::make_shared(std::move(t_fname)); + + if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { + while ((m_input_pos != m_input_end) && (!Eol())) { + ++m_input_pos; + } + /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) + } + + if (Statements()) { + if (m_input_pos != m_input_end) { + throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); + } else { + build_match(std::make_shared(), 0); + return true; + } + } else { + return false; + } + } + }; } } #endif /* CHAISCRIPT_PARSER_HPP_ */ + diff --git a/include/chaiscript/language/chaiscript_prelude_docs.hpp b/include/chaiscript/language/chaiscript_prelude_docs.hpp index e817420..eb02f3b 100644 --- a/include/chaiscript/language/chaiscript_prelude_docs.hpp +++ b/include/chaiscript/language/chaiscript_prelude_docs.hpp @@ -112,7 +112,7 @@ class Map }; -/// \brief A concept implemented by string, Vector and Map. It is convertable to Range, default constructable and back_insertable +/// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable class Container { public: @@ -153,10 +153,10 @@ void print(Object o); /// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript. /// -/// Because the ChaiScript string object is an std::string, it is directly convertable to and from std::string +/// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string /// using the chaiscript::boxed_cast and chaiscript::var functions. /// -/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct passthroughs to the +/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the /// std::string of the same name. /// /// \note Object and function notations are equivalent in ChaiScript. This means that @@ -519,7 +519,7 @@ class Function /// \brief Returns a vector of Type_Info objects that represent the param types for this function. /// The first value in the list is the return type. /// - /// If this function is a conglomeration of several functions (get_contained_values().size() > 0) + /// If this function is a conglomerate of several functions (get_contained_values().size() > 0) /// then the function returns as many Type_Info objects as it can. If the functions contained all have /// the same arity, then it represents the arity. If they have different arities, it returns only /// one value - the return type. @@ -534,7 +534,7 @@ class Function /// \endcode Vector get_param_types() const; - /// \brief Returns true if the function has a guard to it. Always returns falls for a conglomerate function + /// \brief Returns true if the function has a guard to it. Always returns false for a conglomerate function bool has_guard() const; /// \brief Calls the function with the given set of parameters and returns the value; diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index bd60ef0..07fdff4 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -21,8 +21,29 @@ namespace chaiscript namespace utility { - /// \todo Use of this utility, and uniform initializer lists, is causing memory errors in MSVC - + /// Single step command for registering a class with ChaiScript + /// + /// \param[in,out] t_module Model to add class to + /// \param[in] t_class_name Name of the class being registered + /// \param[in] t_constructors Vector of constructors to add + /// \param[in] t_funcs Vector of methods to add + /// + /// \example Adding a basic class to ChaiScript in one step + /// + /// \code + /// chaiscript::utility::add_class(*m, + /// "test", + /// { constructor(), + /// constructor() }, + /// { {fun(&test::function), "function"}, + /// {fun(&test::function2), "function2"}, + /// {fun(&test::function3), "function3"}, + /// {fun(static_cast(&test::functionoverload)), "functionoverload" }, + /// {fun(static_cast(&test::functionoverload)), "functionoverload" }, + /// {fun(static_cast(&test::operator=)), "=" } + /// } + /// ); + /// template void add_class(ModuleType &t_module, const std::string &t_class_name, @@ -36,13 +57,11 @@ namespace chaiscript t_module.add(ctor, t_class_name); } - for(auto fun: t_funcs) + for(const auto &fun: t_funcs) { t_module.add(fun.first, fun.second); } - } - } } diff --git a/releasenotes.md b/releasenotes.md index 5a2d8bf..9942993 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,6 +1,15 @@ Notes: ======= -Current Version: 5.4.0 +Current Version: 5.5.0 + +### Changes since 5.4.0 +* 2x performance increase +* Significant code cleanups +* Throw exception if user attempts to call function on null object +* Allow user defined type conversions +* Fix object lifetime for nested function calls made at the global scope +* Fix returning of boolean values from function calls + ### Changes since 5.3.1 * Decreased compile time and build size diff --git a/samples/inheritance.cpp b/samples/inheritance.cpp new file mode 100644 index 0000000..5bd8c86 --- /dev/null +++ b/samples/inheritance.cpp @@ -0,0 +1,134 @@ +#include +#include + +class BaseClass +{ + public: + BaseClass() + { + } + + virtual ~BaseClass() {} + + virtual std::string doSomething(float, double) const = 0; + + + void setValue(const std::string &t_val) { + if (validateValue(t_val)) + { + m_value = t_val; + } + } + + std::string getValue() const { + return m_value; + } + + protected: + virtual bool validateValue(const std::string &t_val) = 0; + + private: + std::string m_value; +}; + +class ChaiScriptDerived : public BaseClass +{ + public: + ChaiScriptDerived(const std::vector &t_funcs) + { + // using the range-checked .at() methods to give us an exception + // instead of a crash if the user passed in too-few params + tie(t_funcs.at(0), m_doSomethingImpl); + tie(t_funcs.at(1), m_validateValueImpl); + } + + std::string doSomething(float f, double d) const CHAISCRIPT_OVERRIDE + { + assert(m_doSomethingImpl); + return m_doSomethingImpl(*this, f, d); + } + + protected: + bool validateValue(const std::string &t_val) CHAISCRIPT_OVERRIDE + { + assert(m_validateValueImpl); + return m_validateValueImpl(*this, t_val); + } + + private: + template + void tie(const chaiscript::Boxed_Value &t_func, Param &t_param) + { + t_param = chaiscript::boxed_cast(t_func); + } + + std::function m_doSomethingImpl; + std::function m_validateValueImpl; +}; + +int main() +{ + chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); + chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething"); + chai.add(chaiscript::fun(&BaseClass::setValue), "setValue"); + chai.add(chaiscript::fun(&BaseClass::getValue), "getValue"); + chai.add(chaiscript::constructor &)>(), "ChaiScriptDerived"); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::user_type(), "BaseClass"); + chai.add(chaiscript::user_type(), "ChaiScriptDerived"); + + std::string script = R""( + def MakeDerived() { + return ChaiScriptDerived( + // create a dynamically created array and pass it in to the constructor + [ + fun(this, f, d) { + // see here that we are calling back into the 'this' pointer + return "${this.getValue()}${f * d}"; + }, + + fun(this, new_val) { + if (new_val.size() < 5) { + true; + } else { + print("String ${new_val} is too long"); + false; + } + } + ] + ); + } + + var myderived := MakeDerived(); // avoid a copy by using reference assignment := + + )""; + + chai.eval(script); + + BaseClass &myderived = chai.eval("myderived"); + + // at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases + // it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors + // assigned in the MakeDerived() factory function + // + // Notice that our validateValue() function has a requirement that the new string be < 5 characters long + + myderived.setValue("1234"); + assert(myderived.getValue() == "1234"); + + // chaiscript defined function will print out an error message and refuse to allow the setting + myderived.setValue("12345"); + assert(myderived.getValue() == "1234"); + + + chai.eval("myderived.setValue(\"new\")"); // set the value via chaiscript + assert(myderived.getValue() == "new"); + + // call the other derived method via chaiscript and return the value to c++ land: + std::string retval = chai.eval("myderived.doSomething(2,4.3)"); + assert(retval == "new8.6"); + + // The whole process is fully orthogonal +} + + diff --git a/samples/memory_leak_test.cpp b/samples/memory_leak_test.cpp index 23a7455..fb58003 100644 --- a/samples/memory_leak_test.cpp +++ b/samples/memory_leak_test.cpp @@ -70,12 +70,12 @@ int main(int /*argc*/, char * /*argv*/[]) { std::string command = ""; // - // this loop increases memoryusage, if RunFile is not called (just hitting enter) + // this loop increases memory usage, if RunFile is not called (just hitting enter) // as soon RunFile gets called, memory will be freed. // - // scenario1 - RunFile gets called every Loop: memoryusage does not change - // scenario2 - RunFile gets never called (just hitting enter): memoryusage increases every loop - // scenario3 - RunFile gets in changing intervals: memoryusage goes up and down, but never as + // scenario1 - RunFile gets called every Loop: memory usage does not change + // scenario2 - RunFile gets never called (just hitting enter): memory usage increases every loop + // scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as // low as in case 1 scenario3 : while(command != "quit") diff --git a/src/test_module.cpp b/src/test_module.cpp index 7c65dc8..cb95326 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -2,6 +2,8 @@ #include #include + + class TestBaseType { public: @@ -22,6 +24,30 @@ class TestBaseType TestBaseType &operator=(const TestBaseType &); }; +class Type2 +{ + public: + Type2(TestBaseType t_bt) + : m_bt(std::move(t_bt)), + m_str("Hello World") + { + } + + int get_val() const + { + return m_bt.val; + } + + const char *get_str() const + { + return m_str.c_str(); + } + + private: + TestBaseType m_bt; + std::string m_str; +}; + enum TestEnum { TestValue1 = 1 @@ -51,12 +77,17 @@ class TestMoreDerivedType : public TestDerivedType std::shared_ptr derived_type_factory() { - return std::shared_ptr(new TestDerivedType()); + return std::make_shared(); } std::shared_ptr more_derived_type_factory() { - return std::shared_ptr(new TestMoreDerivedType()); + return std::make_shared(); +} + +std::shared_ptr null_factory() +{ + return std::shared_ptr(); } std::string hello_world() @@ -90,6 +121,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::user_type(), "TestBaseType"); m->add(chaiscript::user_type(), "TestDerivedType"); m->add(chaiscript::user_type(), "TestMoreDerivedType"); + m->add(chaiscript::user_type(), "Type2"); m->add(chaiscript::constructor(), "TestBaseType"); // m->add(chaiscript::constructor(), "TestBaseType"); @@ -111,6 +143,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::fun(&derived_type_factory), "derived_type_factory"); m->add(chaiscript::fun(&more_derived_type_factory), "more_derived_type_factory"); + m->add(chaiscript::fun(&null_factory), "null_factory"); m->add(chaiscript::fun(&TestDerivedType::func), "func"); @@ -129,6 +162,12 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::fun(&to_int), "to_int"); m->add(chaiscript::fun(&TestBaseType::constMe), "constMe"); + m->add(chaiscript::type_conversion([](const TestBaseType &t_bt) { return Type2(t_bt); })); + + m->add(chaiscript::fun(&Type2::get_val), "get_val"); + m->add(chaiscript::fun(&Type2::get_str), "get_str"); + m->add(chaiscript::type_conversion()); + m->add(chaiscript::constructor(), "Type2"); return m; } diff --git a/unittests/null_object_access.chai b/unittests/null_object_access.chai new file mode 100644 index 0000000..2a4a06c --- /dev/null +++ b/unittests/null_object_access.chai @@ -0,0 +1,13 @@ +load_module("test_module") + +auto o := null_factory(); + +try { + o.func(); +} catch (e) { + exit(0); +} + +assert_true(false); + + diff --git a/unittests/type_info_test.cpp b/unittests/type_info_test.cpp index 56f2681..e41f111 100644 --- a/unittests/type_info_test.cpp +++ b/unittests/type_info_test.cpp @@ -2,6 +2,7 @@ #include #include +#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, @@ -30,5 +31,7 @@ int main() test_type(chaiscript::user_type(), true, true, false, false, false); test_type(chaiscript::Type_Info(), false, false, false, false, true); + std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << std::endl; + return EXIT_SUCCESS; } diff --git a/unittests/user_defined_conversions.chai b/unittests/user_defined_conversions.chai new file mode 100644 index 0000000..e73e92a --- /dev/null +++ b/unittests/user_defined_conversions.chai @@ -0,0 +1,11 @@ + +add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); }); + +// This looks simple, but it takes the string "string" and using the registered +// conversion above, automatically converts that into a Type_Info object, which then +// allows the Type_Info.name() function to be called + +assert_equal("string".name(), "string"); + + + diff --git a/unittests/user_defined_conversions_2.chai b/unittests/user_defined_conversions_2.chai new file mode 100644 index 0000000..fdb601c --- /dev/null +++ b/unittests/user_defined_conversions_2.chai @@ -0,0 +1,27 @@ +load_module("test_module") + +auto t := TestBaseType(); + +// This uses the TestBaseType to Type2 user type +// conversion which was added in the module and then calls +// "get_val()" which exists on the Type2 type +//assert_equal(t.get_val(), 10); +//print("Made it past test 1"); + +var t2 := Type2(t); +var str = string(get_str(t2)); + +assert_equal("Hello World", str); +print("Made it past test 2"); + +assert_equal(11, size(get_str(t2))); +print("Made it past test 3"); + + +assert_equal(11, t2.get_str().size()); +print("Made it past test 4"); + +assert_equal(11, t.get_str().size()); +print("Made it past test 5"); + +