From bd9af5eff45e7a12e3e2b0f7abd1ba7f1d88ce26 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 14 Aug 2015 21:58:54 -0600 Subject: [PATCH 01/18] Order typed functions over untyped specifically the chaiscript defined ones --- .../chaiscript/dispatchkit/dispatchkit.hpp | 226 ++++++++++++------ .../dispatchkit/dynamic_object_detail.hpp | 32 ++- .../dispatchkit/proxy_functions.hpp | 49 +++- unittests/clone_object.chai | 38 +++ 4 files changed, 264 insertions(+), 81 deletions(-) create mode 100644 unittests/clone_object.chai diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 43cb7b12..a7b7edac 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -732,7 +732,6 @@ namespace chaiscript /// \throws std::range_error if it does not Boxed_Value get_function_object(const std::string &t_name) const { -// std::cout << "Getting function object: " << t_name << '\n'; chaiscript::detail::threading::shared_lock l(m_mutex); const auto &funs = get_boxed_functions_int(); @@ -1026,6 +1025,13 @@ namespace chaiscript void dump_function(const std::pair &f) const { std::vector params = f.second->get_param_types(); + std::vector> typed_params; + + auto func(std::dynamic_pointer_cast(f.second)); + if (func) { + typed_params = func->get_dynamic_param_types().types(); + } + std::string annotation = f.second->annotation(); if (annotation.size() > 0) { @@ -1034,19 +1040,20 @@ namespace chaiscript dump_type(params.front()); std::cout << " " << f.first << "("; - for (std::vector::const_iterator itr = params.begin() + 1; - itr != params.end(); - ) + for (size_t i = 1; i < params.size(); ++i) { - dump_type(*itr); - ++itr; + if (!typed_params.empty() && !typed_params[i-1].first.empty()) { + std::cout << typed_params[i-1].first; + } else { + dump_type(params[i]); + } - if (itr != params.end()) - { + if (i != params.size() - 1) { std::cout << ", "; } } + std::cout << ") \n"; } @@ -1253,97 +1260,166 @@ namespace chaiscript return m_state.m_functions; } - static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) + + static std::vector param_types(const Proxy_Function &t_f) { + assert(t_f); + return t_f->get_param_types(); + } - auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); - auto dynamic_rhs(std::dynamic_pointer_cast(rhs)); + static std::vector> param_types(const std::shared_ptr &t_f) + { + assert(t_f); + const auto types = t_f->get_dynamic_param_types().types(); + std::vector> ret(1); + ret.insert(ret.end(), types.begin(), types.end()); + return ret; + } - if (dynamic_lhs && dynamic_rhs) + static Type_Info type_info(const std::pair &t_ti) + { + return t_ti.second; + } + + static Type_Info type_info(const Type_Info &t_ti) + { + return t_ti; + } + + static std::string dynamic_type_name(const std::pair &t_ti) + { + return t_ti.first.empty()?t_ti.second.name():t_ti.first; + } + + static std::string dynamic_type_name(const Type_Info &ti) + { + return ti.name(); + } + + + template + static bool params_less_than(const LHS &t_lhs, const RHS &t_rhs) { - if (dynamic_lhs->get_guard()) - { - return dynamic_rhs->get_guard() ? false : true; - } else { - return false; - } - } + assert(t_lhs); + assert(t_rhs); + const auto lhsparamtypes = param_types(t_lhs); + const auto rhsparamtypes = param_types(t_rhs); - if (dynamic_lhs && !dynamic_rhs) - { - return false; - } - - if (!dynamic_lhs && dynamic_rhs) - { - return true; - } - - const auto &lhsparamtypes = lhs->get_param_types(); - const auto &rhsparamtypes = rhs->get_param_types(); - - const auto lhssize = lhsparamtypes.size(); - const auto rhssize = rhsparamtypes.size(); + const auto lhssize = lhsparamtypes.size(); + const auto rhssize = rhsparamtypes.size(); #ifdef CHAISCRIPT_HAS_MAGIC_STATICS - static auto boxed_type = user_type(); - static auto boxed_pod_type = user_type(); + static auto boxed_type = user_type(); + static auto boxed_pod_type = user_type(); + static auto dynamic_type = user_type(); #else - auto boxed_type = user_type(); - auto boxed_pod_type = user_type(); + auto boxed_type = user_type(); + auto boxed_pod_type = user_type(); + auto dynamic_type = user_type(); #endif - for (size_t i = 1; i < lhssize && i < rhssize; ++i) - { - const Type_Info < = lhsparamtypes[i]; - const Type_Info &rt = rhsparamtypes[i]; - - if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) + for (size_t i = 1; i < lhssize && i < rhssize; ++i) { - continue; // The first two types are essentially the same, next iteration - } + const Type_Info lt = type_info(lhsparamtypes[i]); + const Type_Info rt = type_info(rhsparamtypes[i]); + const std::string ln = dynamic_type_name(lhsparamtypes[i]); + const std::string rn = dynamic_type_name(rhsparamtypes[i]); - // const is after non-const for the same type - if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) - { - return false; - } + if ( (lt.bare_equal(dynamic_type) || lt.is_undef()) + && (rt.bare_equal(dynamic_type) || rt.is_undef())) + { - if (lt.bare_equal(rt) && !lt.is_const()) - { - return true; - } + if (!ln.empty() && rn.empty()) { + return true; + } else if (ln.empty() && !rn.empty()) { + return false; + } else if (!ln.empty() && !rn.empty()) { + if (ln < rn) { + return true; + } else if (rn < ln) { + return false; + } - // boxed_values are sorted last - if (lt.bare_equal(boxed_type)) - { - return false; - } + // the remaining cases are handled by the is_const rules below + } + } - if (rt.bare_equal(boxed_type)) - { - if (lt.bare_equal(boxed_pod_type)) + if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) + { + continue; // The first two types are essentially the same, next iteration + } + + // const is after non-const for the same type + if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) + { + return false; + } + + if (lt.bare_equal(rt) && !lt.is_const()) { return true; } - return true; + + // boxed_values are sorted last + if (lt.bare_equal(boxed_type)) + { + return false; + } + + if (rt.bare_equal(boxed_type)) + { + if (lt.bare_equal(boxed_pod_type)) + { + return true; + } + return true; + } + + if (lt.bare_equal(boxed_pod_type)) + { + return false; + } + + if (rt.bare_equal(boxed_pod_type)) + { + return true; + } + + // otherwise, we want to sort by typeid + return lt < rt; } - if (lt.bare_equal(boxed_pod_type)) - { - return false; + // if everything else checks out, sort on guard + // + auto dynamic_lhs(std::dynamic_pointer_cast(t_lhs)); + auto dynamic_rhs(std::dynamic_pointer_cast(t_rhs)); + + if (dynamic_lhs && dynamic_rhs) { + if (dynamic_lhs->get_guard() && !dynamic_rhs->get_guard()) { + return true; + } else if (dynamic_rhs->get_guard()) { + return false; + } } - if (rt.bare_equal(boxed_pod_type)) - { - return true; - } - - // otherwise, we want to sort by typeid - return lt < rt; + return false; } - return false; + static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) + { + auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); + auto dynamic_rhs(std::dynamic_pointer_cast(rhs)); + + if (dynamic_lhs && dynamic_rhs) + { + return params_less_than(dynamic_lhs, dynamic_rhs); + } else if (dynamic_lhs) { + return params_less_than(dynamic_lhs, rhs); + } else if (dynamic_rhs) { + return params_less_than(lhs, dynamic_rhs); + } else { + return params_less_than(lhs, rhs); + } } diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 9d501aed..710c927f 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -39,7 +39,8 @@ namespace chaiscript /// 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 + class Dynamic_Object_Function : public Proxy_Function_Base, public Dynamic_Function_Interface + { public: Dynamic_Object_Function( @@ -72,6 +73,17 @@ namespace chaiscript Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; Dynamic_Object_Function(Dynamic_Object_Function &) = delete; + virtual Param_Types get_dynamic_param_types() const { + auto dynamic(std::dynamic_pointer_cast(m_func)); + + if (dynamic) { + return dynamic->get_dynamic_param_types(); + } else { + return Param_Types(get_param_types()); + } + } + + virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE { if (const auto *df = dynamic_cast(&f)) @@ -182,7 +194,7 @@ namespace chaiscript * that is automatically guarded based on the first param based on the * param's type name */ - class Dynamic_Object_Constructor : public Proxy_Function_Base + class Dynamic_Object_Constructor : public Proxy_Function_Base, public Dynamic_Function_Interface { public: Dynamic_Object_Constructor( @@ -191,6 +203,7 @@ namespace chaiscript : 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 ); assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); } @@ -210,6 +223,17 @@ namespace chaiscript virtual ~Dynamic_Object_Constructor() {} + virtual Param_Types get_dynamic_param_types() const { + auto dynamic(std::dynamic_pointer_cast(m_func)); + + if (dynamic) { + return dynamic->get_dynamic_param_types(); + } else { + return Param_Types(get_param_types()); + } + } + + virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE { const Dynamic_Object_Constructor *dc = dynamic_cast(&f); @@ -222,7 +246,7 @@ namespace chaiscript new_vals.insert(new_vals.end(), vals.begin(), vals.end()); return m_func->call_match(new_vals, t_conversions); - } + } virtual std::string annotation() const CHAISCRIPT_OVERRIDE { @@ -232,7 +256,7 @@ namespace chaiscript protected: virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - auto bv = var(Dynamic_Object(m_type_name)); + auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); std::vector new_params{bv}; new_params.insert(new_params.end(), params.begin(), params.end()); diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 156831f7..940468e4 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -53,6 +53,13 @@ namespace chaiscript m_doti(user_type()) {} + Param_Types(const std::vector &t_types) + : m_types(build_param_types(t_types)), + m_has_types(false), + m_doti(user_type()) + { + } + Param_Types(std::vector> t_types) : m_types(std::move(t_types)), m_has_types(false), @@ -61,6 +68,18 @@ namespace chaiscript update_has_types(); } + static std::vector> build_param_types(const std::vector &t_types) + { + std::vector> retval; + std::transform(t_types.begin(), t_types.end(), std::back_inserter(retval), + [](const Type_Info &ti){ + return std::make_pair(std::string(), ti); + } + ); + + return retval; + } + void push_front(std::string t_name, Type_Info t_ti) { m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti)); @@ -295,11 +314,18 @@ namespace chaiscript namespace dispatch { + class Dynamic_Function_Interface + { + public: + virtual ~Dynamic_Function_Interface() {} + virtual Param_Types get_dynamic_param_types() const = 0; + }; + /** * A Proxy_Function implementation that is not type safe, the called function * is expecting a vector that it works with how it chooses. */ - class Dynamic_Proxy_Function : public Proxy_Function_Base + class Dynamic_Proxy_Function : public Proxy_Function_Base, public Dynamic_Function_Interface { public: Dynamic_Proxy_Function( @@ -349,6 +375,9 @@ namespace chaiscript return m_description; } + virtual Param_Types get_dynamic_param_types() const { + return m_param_types; + } protected: bool test_guard(const std::vector ¶ms, const Type_Conversions &t_conversions) const @@ -367,6 +396,8 @@ namespace chaiscript } } + + private: static std::vector build_param_type_list(const Param_Types &t_types) { @@ -678,6 +709,8 @@ namespace chaiscript std::reference_wrapper> m_f; std::shared_ptr> m_shared_ptr_holder; }; + + /// Attribute getter Proxy_Function implementation template class Attribute_Access : public Proxy_Function_Base @@ -875,6 +908,15 @@ namespace chaiscript std::vector> ordered_funcs; ordered_funcs.reserve(funcs.size()); +#ifdef CHAISCRIPT_HAS_MAGIC_STATICS + static auto boxed_type = user_type(); + static auto dynamic_type = user_type(); +#else + auto boxed_type = user_type(); + auto dynamic_type = user_type(); +#endif + + for (const auto &func : funcs) { const auto arity = func->get_arity(); @@ -886,7 +928,10 @@ namespace chaiscript size_t numdiffs = 0; for (size_t i = 0; i < plist.size(); ++i) { - if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info())) + const auto &p_type = plist[i].get_type_info(); + const auto &f_type = func->get_param_types()[i+1]; + + if (!(f_type.bare_equal(boxed_type) && p_type.bare_equal(dynamic_type)) && !f_type.bare_equal(p_type)) { ++numdiffs; } diff --git a/unittests/clone_object.chai b/unittests/clone_object.chai new file mode 100644 index 00000000..78c38a29 --- /dev/null +++ b/unittests/clone_object.chai @@ -0,0 +1,38 @@ +GLOBAL clone_count = 0; + +class Cloneable +{ + def Cloneable() { + } + +} + + +def clone(Cloneable c) +{ + print("Clone called"); + ++clone_count; + return c; +} + + +class MyObject +{ + def MyObject() { + this.data = Cloneable(); + } + + var data; +} + + +assert_equal(0, clone_count); + +var o = MyObject(); + +assert_equal(0, clone_count); + +var p = o; + +assert_equal(1, clone_count); + From 818fd0b8234b2b492182f182cb2af77352029498 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 26 Aug 2015 18:47:32 -0600 Subject: [PATCH 02/18] Add function ordering test --- unittests/compiled_tests.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 9e344ccd..1a859745 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -317,7 +317,8 @@ TEST_CASE("Function ordering") chaiscript::ChaiScript chai; chai.eval("def test_fun(x) { return 3; }"); chai.eval("def test_fun(x) : x == \"hi\" { return 4; }"); -// chai.eval("def test_fun(x) { return 5; }"); + chai.eval("def test_fun(double d) { return 5; }"); + chai.add(chaiscript::fun(&function_ordering_test_one), "test_fun"); chai.add(chaiscript::fun(&function_ordering_test_two), "test_fun"); @@ -325,6 +326,7 @@ TEST_CASE("Function ordering") CHECK(chai.eval("auto i = 1; test_fun(i)") == 2); CHECK(chai.eval("test_fun(\"bob\")") == 3); CHECK(chai.eval("test_fun(\"hi\")") == 4); + CHECK(chai.eval("test_fun(5.0)") == 5); } From 425c679c6c8e3f72df778b987e74fb353cf34923 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 13 Nov 2017 09:03:55 -0700 Subject: [PATCH 03/18] Fix GLOBAL in clone_object tests --- unittests/clone_object.chai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/clone_object.chai b/unittests/clone_object.chai index 78c38a29..04ad0be8 100644 --- a/unittests/clone_object.chai +++ b/unittests/clone_object.chai @@ -1,4 +1,4 @@ -GLOBAL clone_count = 0; +global clone_count = 0; class Cloneable { From 28a59d2a6e3192f59564142a02dcf45229df9fb6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 16 Nov 2017 09:10:29 -0700 Subject: [PATCH 04/18] Avoid creating vectors when possible --- include/chaiscript/chaiscript_defines.hpp | 59 +++++++-- include/chaiscript/chaiscript_stdlib.hpp | 2 +- include/chaiscript/dispatchkit/any.hpp | 8 +- include/chaiscript/dispatchkit/bootstrap.hpp | 2 +- .../chaiscript/dispatchkit/dispatchkit.hpp | 41 +++---- .../dispatchkit/dynamic_object_detail.hpp | 14 +-- .../dispatchkit/function_call_detail.hpp | 16 ++- .../dispatchkit/function_params.hpp | 81 +++++++++++++ .../dispatchkit/proxy_functions.hpp | 114 +++++++++--------- .../dispatchkit/proxy_functions_detail.hpp | 7 +- .../chaiscript/language/chaiscript_common.hpp | 9 +- .../chaiscript/language/chaiscript_engine.hpp | 4 +- .../chaiscript/language/chaiscript_eval.hpp | 107 ++++++++-------- .../chaiscript/language/chaiscript_parser.hpp | 54 ++++----- include/chaiscript/utility/stack_vector.hpp | 63 ++++++++++ 15 files changed, 375 insertions(+), 206 deletions(-) create mode 100644 include/chaiscript/dispatchkit/function_params.hpp create mode 100644 include/chaiscript/utility/stack_vector.hpp diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 9754913f..6c8ee78d 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -105,47 +105,47 @@ namespace chaiscript { } struct Build_Info { - constexpr static int version_major() noexcept + [[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; } - constexpr static int version_minor() noexcept + [[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; } - constexpr static int version_patch() noexcept + [[nodiscard]] constexpr static int version_patch() noexcept { return chaiscript::version_patch; } - static std::string version() + [[nodiscard]] static std::string version() { return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch()); } - static std::string compiler_id() + [[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); } - static std::string build_id() + [[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build()?"-Debug":"-Release"); } - static std::string compiler_version() + [[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; } - static std::string compiler_name() + [[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; } - constexpr static bool debug_build() noexcept + [[nodiscard]] constexpr static bool debug_build() noexcept { return chaiscript::debug_build; } @@ -153,7 +153,8 @@ namespace chaiscript { template - constexpr auto parse_num(const std::string_view &t_str) noexcept -> typename std::enable_if::value, T>::type + [[nodiscard]] constexpr auto parse_num(const std::string_view &t_str) noexcept + -> typename std::enable_if::value, T>::type { T t = 0; for (const auto c : t_str) { @@ -168,7 +169,8 @@ namespace chaiscript { template - auto parse_num(const std::string_view &t_str) noexcept -> typename std::enable_if::value, T>::type + [[nodiscard]] auto parse_num(const std::string_view &t_str) noexcept + -> typename std::enable_if::value, T>::type { T t = 0; T base = 0; @@ -211,11 +213,11 @@ namespace chaiscript { } struct str_less { - bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { + [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; } template - constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { + [[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); } struct is_transparent{}; @@ -229,6 +231,37 @@ namespace chaiscript { External_Scripts }; + template + struct is_nothrow_forward_constructible + : std::bool_constant()})> + { + }; + + template< class From, class To > + inline constexpr bool is_nothrow_forward_constructible_v + = is_nothrow_forward_constructible::value; + + template + [[nodiscard]] constexpr auto make_container(T && ... t) + { + Container c; + c.reserve(sizeof...(t)); + (c.push_back(std::forward(t)), ...); + return c; + } + + + template + [[nodiscard]] auto make_vector(T && ... t) + { + using container_type = + std::vector...>>; + + return make_container(std::forward(t)...); + } + + + static inline std::vector default_options() { #ifdef CHAISCRIPT_NO_DYNLOAD diff --git a/include/chaiscript/chaiscript_stdlib.hpp b/include/chaiscript/chaiscript_stdlib.hpp index ed56b234..2407fcf0 100644 --- a/include/chaiscript/chaiscript_stdlib.hpp +++ b/include/chaiscript/chaiscript_stdlib.hpp @@ -42,7 +42,7 @@ namespace chaiscript { public: - static ModulePtr library() + [[nodiscard]] static ModulePtr library() { auto lib = std::make_shared(); bootstrap::Bootstrap::bootstrap(*lib); diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index d13b653f..a9e31594 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -83,8 +83,8 @@ namespace chaiscript { public: // construct/copy/destruct constexpr Any() noexcept = default; - Any(Any &&) = default; - Any &operator=(Any &&t_any) = default; + Any(Any &&) noexcept = default; + Any &operator=(Any &&t_any) noexcept = default; Any(const Any &t_any) : m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) @@ -93,7 +93,7 @@ namespace chaiscript { template>>> - explicit Any(ValueType &&t_value) + explicit Any(ValueType &&t_value) noexcept(is_nothrow_forward_constructible_v>) : m_data(std::make_unique>>(std::forward(t_value))) { } @@ -128,7 +128,7 @@ namespace chaiscript { // queries bool empty() const noexcept { - return !bool(m_data); + return !static_cast(m_data); } const std::type_info & type() const noexcept diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 67116da6..9a94d104 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -241,7 +241,7 @@ 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 - static Boxed_Value bind_function(const std::vector ¶ms) + static Boxed_Value bind_function(const Function_Params ¶ms) { if (params.empty()) { throw exception::arity_error(0, 1); diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index f8217ea4..4f338cee 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -313,14 +313,14 @@ namespace chaiscript return arity; } - bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { return std::any_of(std::begin(m_funcs), std::end(m_funcs), [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); }); } protected: - Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { return dispatch::dispatch(m_funcs, params, t_conversions); } @@ -935,7 +935,7 @@ namespace chaiscript return m_conversions; } - static bool is_attribute_call(const std::vector &t_funs, const std::vector &t_params, + static bool is_attribute_call(const std::vector &t_funs, const Function_Params &t_params, bool t_has_params, const Type_Conversions_State &t_conversions) noexcept { if (!t_has_params || t_params.empty()) { @@ -956,7 +956,7 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4715) #endif - Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms, bool t_has_params, + Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const Function_Params ¶ms, bool t_has_params, const Type_Conversions_State &t_conversions) { uint_fast32_t loc = t_loc; @@ -964,9 +964,9 @@ namespace chaiscript if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); } const auto do_attribute_call = - [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value + [this](int l_num_params, Function_Params l_params, const std::vector &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value { - std::vector attr_params{l_params.begin(), l_params.begin() + l_num_params}; + Function_Params attr_params(l_params.begin(), l_params.begin() + l_num_params); Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type())) { struct This_Foist { @@ -1049,14 +1049,15 @@ namespace chaiscript if (!functions.empty()) { try { if (is_no_param) { - auto tmp_params(params); + auto tmp_params = params.to_vector(); tmp_params.insert(tmp_params.begin() + 1, var(t_name)); - return do_attribute_call(2, tmp_params, functions, t_conversions); + return do_attribute_call(2, Function_Params(tmp_params), functions, t_conversions); } else { - return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector(params.begin()+1, params.end()))}, t_conversions); + std::array p{params[0], var(t_name), var(std::vector(params.begin()+1, params.end()))}; + return dispatch::dispatch(functions, Function_Params{p}, t_conversions); } } catch (const dispatch::option_explicit_set &e) { - throw chaiscript::exception::dispatch_error(params, std::vector(funs.second->begin(), funs.second->end()), + throw chaiscript::exception::dispatch_error(params, std::vector(funs.second->begin(), funs.second->end()), e.what()); } } @@ -1076,7 +1077,7 @@ namespace chaiscript - Boxed_Value call_function(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms, + Boxed_Value call_function(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc, Function_Params params, const Type_Conversions_State &t_conversions) const { uint_fast32_t loc = t_loc; @@ -1132,7 +1133,7 @@ namespace chaiscript /// 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) const + Boxed_Value call_exists(const Function_Params ¶ms) const { if (params.empty()) { @@ -1142,7 +1143,7 @@ namespace chaiscript const auto &f = this->boxed_cast(params[0]); const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves()); - return const_var(f->call_match(std::vector(params.begin() + 1, params.end()), convs)); + return const_var(f->call_match(Function_Params(params.begin() + 1, params.end()), convs)); } /// Dump all system info to stdout @@ -1203,11 +1204,6 @@ namespace chaiscript m_state = t_state; } - static void save_function_params(Stack_Holder &t_s, std::initializer_list t_params) - { - t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params); - } - static void save_function_params(Stack_Holder &t_s, std::vector &&t_params) { for (auto &¶m : t_params) @@ -1216,22 +1212,17 @@ namespace chaiscript } } - static void save_function_params(Stack_Holder &t_s, const std::vector &t_params) + static void save_function_params(Stack_Holder &t_s, const Function_Params &t_params) { t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end()); } - void save_function_params(std::initializer_list t_params) - { - save_function_params(*m_stack_holder, t_params); - } - void save_function_params(std::vector &&t_params) { save_function_params(*m_stack_holder, std::move(t_params)); } - void save_function_params(const std::vector &t_params) + void save_function_params(const Function_Params &t_params) { save_function_params(*m_stack_holder, t_params); } diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index eacfb51a..7c0364d8 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -94,7 +94,7 @@ namespace chaiscript bool is_attribute_function() const noexcept override { return m_is_attribute; } - bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) { @@ -110,7 +110,7 @@ namespace chaiscript } protected: - Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) { @@ -159,7 +159,7 @@ namespace chaiscript } - bool dynamic_object_typename_match(const std::vector &bvs, const std::string &name, + bool dynamic_object_typename_match(const Function_Params &bvs, const std::string &name, const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const noexcept { if (!bvs.empty()) @@ -228,22 +228,22 @@ namespace chaiscript return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); } - bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const override + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override { 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); + return m_func->call_match(Function_Params{new_vals}, t_conversions); } protected: - Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); std::vector new_params{bv}; new_params.insert(new_params.end(), params.begin(), params.end()); - (*m_func)(new_params, t_conversions); + (*m_func)(Function_Params{new_params}, t_conversions); return bv; } diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 7d8b3d5e..5cd1932e 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -35,7 +35,7 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions_State *t_conversions) + const Function_Params ¶ms, const Type_Conversions_State *t_conversions) { if (t_conversions != nullptr) { return boxed_cast(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions); @@ -54,7 +54,7 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions_State *t_conversions) + const Function_Params ¶ms, const Type_Conversions_State *t_conversions) { if (t_conversions != nullptr) { return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as(); @@ -74,7 +74,7 @@ namespace chaiscript struct Function_Caller_Ret { static void call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions_State *t_conversions) + const Function_Params ¶ms, const Type_Conversions_State *t_conversions) { if (t_conversions != nullptr) { dispatch::dispatch(t_funcs, params, *t_conversions); @@ -101,16 +101,14 @@ namespace chaiscript template Ret operator()(P&& ... param) { + std::array params{box

(std::forward

(param))...}; + if (m_conversions) { Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves()); - return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, { - box

(std::forward

(param))... - }, &state + return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, Function_Params{params}, &state ); } else { - return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, { - box

(std::forward

(param))... - }, nullptr + return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, Function_Params{params}, nullptr ); } diff --git a/include/chaiscript/dispatchkit/function_params.hpp b/include/chaiscript/dispatchkit/function_params.hpp new file mode 100644 index 00000000..090f7004 --- /dev/null +++ b/include/chaiscript/dispatchkit/function_params.hpp @@ -0,0 +1,81 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + + +#ifndef CHAISCRIPT_FUNCTION_PARAMS_HPP +#define CHAISCRIPT_FUNCTION_PARAMS_HPP + + +#include "boxed_value.hpp" + +namespace chaiscript { + + class Function_Params + { + public: + constexpr Function_Params(const Boxed_Value * const t_begin, const Boxed_Value * const t_end) + : m_begin(t_begin), m_end(t_end) + { + } + + explicit Function_Params(const Boxed_Value &bv) + : m_begin(&bv), m_end(m_begin + 1) + { + } + + explicit Function_Params(const std::vector &vec) + : m_begin(&vec.front()), m_end(&vec.front() + vec.size()) + { + } + + template + constexpr explicit Function_Params(const std::array &a) + : m_begin(std::begin(a)), m_end(std::end(a)) + { + } + + [[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { + return m_begin[t_i]; + } + + [[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { + return m_begin; + } + + [[nodiscard]] constexpr const Boxed_Value &front() const noexcept { + return *m_begin; + } + + [[nodiscard]] constexpr const Boxed_Value *end() const noexcept { + return m_end; + } + + [[nodiscard]] constexpr std::size_t size() const noexcept { + return m_end - m_begin; + } + + std::vector to_vector() const { + return std::vector{m_begin, m_end}; + } + + [[nodiscard]] constexpr bool empty() const noexcept { + return m_begin == m_end; + } + + private: + const Boxed_Value *m_begin = nullptr; + const Boxed_Value *m_end = nullptr; + + }; + +} + + +#endif + diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index f1797417..0f97edbf 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -27,6 +27,7 @@ #include "proxy_functions_detail.hpp" #include "type_info.hpp" #include "dynamic_object.hpp" +#include "function_params.hpp" namespace chaiscript { class Type_Conversions; @@ -91,8 +92,9 @@ namespace chaiscript return m_types == t_rhs.m_types; } - std::vector convert(std::vector vals, const Type_Conversions_State &t_conversions) const + std::vector convert(Function_Params t_params, const Type_Conversions_State &t_conversions) const { + auto vals = t_params.to_vector(); constexpr auto dynamic_object_type_info = user_type(); for (size_t i = 0; i < vals.size(); ++i) { @@ -131,7 +133,7 @@ namespace chaiscript // first result: is a match // second result: needs conversions - std::pair match(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept + std::pair match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept { constexpr auto dynamic_object_type_info = user_type(); bool needs_conversion = false; @@ -154,7 +156,7 @@ namespace chaiscript } } catch (const std::bad_cast &) { return std::make_pair(false, false); - } + } } else { const auto &ti = m_types[i].second; if (!ti.is_undef()) @@ -214,7 +216,7 @@ namespace chaiscript public: virtual ~Proxy_Function_Base() = default; - Boxed_Value operator()(const std::vector ¶ms, const chaiscript::Type_Conversions_State &t_conversions) const + Boxed_Value operator()(const Function_Params ¶ms, const chaiscript::Type_Conversions_State &t_conversions) const { if (m_arity < 0 || size_t(m_arity) == params.size()) { return do_call(params, t_conversions); @@ -226,11 +228,11 @@ 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 contains exactly 1 Type_Info object: the return type - /// \returns the types of all parameters. + /// \returns the types of all parameters. const std::vector &get_param_types() const noexcept { return m_types; } virtual bool operator==(const Proxy_Function_Base &) const noexcept = 0; - virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const = 0; + virtual bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const = 0; virtual bool is_attribute_function() const noexcept { return false; } @@ -246,7 +248,7 @@ namespace chaiscript //! Return true if the function is a possible match //! to the passed in values - bool filter(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept + bool filter(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept { assert(m_arity == -1 || (m_arity > 0 && static_cast(vals.size()) == m_arity)); @@ -272,13 +274,13 @@ namespace chaiscript constexpr auto boxed_number_ti = user_type(); constexpr auto function_ti = user_type>(); - if (ti.is_undef() + if (ti.is_undef() || ti.bare_equal(boxed_value_ti) || (!bv.get_type_info().is_undef() && ( (ti.bare_equal(boxed_number_ti) && bv.get_type_info().is_arithmetic()) || ti.bare_equal(bv.get_type_info()) || bv.get_type_info().bare_equal(function_ti) - || t_conversions->converts(ti, bv.get_type_info()) + || t_conversions->converts(ti, bv.get_type_info()) ) ) ) @@ -296,7 +298,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const = 0; + virtual Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const = 0; Proxy_Function_Base(std::vector t_types, int t_arity) : m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false) @@ -313,7 +315,7 @@ namespace chaiscript } - static bool compare_types(const std::vector &tis, const std::vector &bvs, + static bool compare_types(const std::vector &tis, const Function_Params &bvs, const Type_Conversions_State &t_conversions) noexcept { if (tis.size() - 1 != bvs.size()) @@ -367,10 +369,8 @@ namespace chaiscript virtual Param_Types get_dynamic_param_types() const = 0; }; - /** - * A Proxy_Function implementation that is not type safe, the called function - * is expecting a vector that it works with how it chooses. - */ + /// A Proxy_Function implementation that is not type safe, the called function + /// is expecting a vector that it works with how it chooses. class Dynamic_Proxy_Function : public Proxy_Function_Base, public Dynamic_Function_Interface { public: @@ -398,7 +398,7 @@ namespace chaiscript && this->m_param_types == prhs->m_param_types); } - bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const override + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override { return call_match_internal(vals, t_conversions).first; } @@ -431,7 +431,7 @@ namespace chaiscript } protected: - bool test_guard(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const + bool test_guard(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const { if (m_guard) { @@ -449,7 +449,7 @@ namespace chaiscript // first result: is a match // second result: needs conversions - std::pair call_match_internal(const std::vector &vals, const Type_Conversions_State &t_conversions) const + std::pair call_match_internal(const Function_Params &vals, const Type_Conversions_State &t_conversions) const { const auto comparison_result = [&](){ if (m_arity < 0) { @@ -462,7 +462,7 @@ namespace chaiscript }(); return std::make_pair( - comparison_result.first && test_guard(vals, t_conversions), + comparison_result.first && test_guard(vals, t_conversions), comparison_result.second ); } @@ -500,7 +500,7 @@ namespace chaiscript { public: Dynamic_Proxy_Function_Impl( - Callable t_f, + Callable t_f, int t_arity=-1, std::shared_ptr t_parsenode = AST_NodePtr(), Param_Types t_param_types = Param_Types(), @@ -517,13 +517,13 @@ namespace chaiscript protected: - Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { - const auto match_results = call_match_internal(params, t_conversions); - if (match_results.first) + const auto [is_a_match, needs_conversions] = call_match_internal(params, t_conversions); + if (is_a_match) { - if (match_results.second) { - return m_f(m_param_types.convert(params, t_conversions)); + if (needs_conversions) { + return m_f(Function_Params{m_param_types.convert(params, t_conversions)}); } else { return m_f(params); } @@ -556,7 +556,7 @@ namespace chaiscript class Bound_Function final : public Proxy_Function_Base { public: - Bound_Function(const Const_Proxy_Function &t_f, + Bound_Function(const Const_Proxy_Function &t_f, const std::vector &t_args) : 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) @@ -570,9 +570,9 @@ namespace chaiscript } - bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const override + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override { - return m_f->call_match(build_param_list(vals), t_conversions); + return m_f->call_match(Function_Params(build_param_list(vals)), t_conversions); } std::vector get_contained_functions() const override @@ -581,7 +581,7 @@ namespace chaiscript } - std::vector build_param_list(const std::vector ¶ms) const + std::vector build_param_list(const Function_Params ¶ms) const { auto parg = params.begin(); auto barg = m_args.begin(); @@ -590,7 +590,7 @@ namespace chaiscript while (!(parg == params.end() && barg == m_args.end())) { - while (barg != m_args.end() + while (barg != m_args.end() && !(barg->get_type_info() == chaiscript::detail::Get_Type_Info::get())) { args.push_back(*barg); @@ -603,18 +603,18 @@ namespace chaiscript ++parg; } - if (barg != m_args.end() + if (barg != m_args.end() && barg->get_type_info() == chaiscript::detail::Get_Type_Info::get()) { ++barg; - } + } } return args; } protected: - static std::vector build_param_type_info(const Const_Proxy_Function &t_f, + static std::vector build_param_type_info(const Const_Proxy_Function &t_f, const std::vector &t_args) { assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast(t_args.size())); @@ -638,9 +638,9 @@ namespace chaiscript return retval; } - Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { - return (*m_f)(build_param_list(params), t_conversions); + return (*m_f)(Function_Params{build_param_list(params)}, t_conversions); } private: @@ -656,13 +656,13 @@ namespace chaiscript { } - bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { - return static_cast(vals.size()) == get_arity() + return static_cast(vals.size()) == get_arity() && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions)); } - virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept = 0; + virtual bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept = 0; }; @@ -678,7 +678,7 @@ namespace chaiscript { } - bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override + bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); } @@ -690,7 +690,7 @@ namespace chaiscript protected: - Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { return detail::call_func(static_cast(nullptr), m_f, params, t_conversions); } @@ -722,7 +722,7 @@ namespace chaiscript assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get()); } - bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override + bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); } @@ -742,7 +742,7 @@ namespace chaiscript } protected: - Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { return detail::call_func(static_cast(nullptr), m_f.get(), params, t_conversions); } @@ -765,11 +765,11 @@ namespace chaiscript { } - bool is_attribute_function() const noexcept override { return true; } + bool is_attribute_function() const noexcept override { return true; } bool operator==(const Proxy_Function_Base &t_func) const noexcept override { - const Attribute_Access * aa + const Attribute_Access * aa = dynamic_cast *>(&t_func); if (aa) { @@ -779,7 +779,7 @@ namespace chaiscript } } - bool call_match(const std::vector &vals, const Type_Conversions_State &) const noexcept override + bool call_match(const Function_Params &vals, const Type_Conversions_State &) const noexcept override { if (vals.size() != 1) { @@ -790,7 +790,7 @@ namespace chaiscript } protected: - Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { const Boxed_Value &bv = params[0]; if (bv.is_const()) @@ -839,22 +839,22 @@ namespace chaiscript { /// \brief Exception thrown in the case that a method dispatch fails /// because no matching function was found - /// + /// /// May be thrown due to an arity_error, a guard_error or a bad_boxed_cast /// exception class dispatch_error : public std::runtime_error { public: - dispatch_error(std::vector t_parameters, + dispatch_error(const Function_Params &t_parameters, std::vector t_functions) - : std::runtime_error("Error with function dispatch"), parameters(std::move(t_parameters)), functions(std::move(t_functions)) + : std::runtime_error("Error with function dispatch"), parameters(t_parameters.to_vector()), functions(std::move(t_functions)) { } - dispatch_error(std::vector t_parameters, + dispatch_error(const Function_Params &t_parameters, std::vector t_functions, const std::string &t_desc) - : std::runtime_error(t_desc), parameters(std::move(t_parameters)), functions(std::move(t_functions)) + : std::runtime_error(t_desc), parameters(t_parameters.to_vector()), functions(std::move(t_functions)) { } @@ -865,14 +865,14 @@ namespace chaiscript std::vector parameters; std::vector functions; }; - } + } namespace dispatch { - namespace detail + namespace detail { template - bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector &plist, + bool types_match_except_for_arithmetic(const FuncType &t_func, const Function_Params &plist, const Type_Conversions_State &t_conversions) noexcept { const std::vector &types = t_func->get_param_types(); @@ -891,7 +891,7 @@ namespace chaiscript } template - Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector &plist, + Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const Function_Params &plist, const Type_Conversions_State &t_conversions, const Funcs &t_funcs) { InItr matching_func(end); @@ -947,7 +947,7 @@ namespace chaiscript ); try { - return (*(matching_func->second))(newplist, t_conversions); + return (*(matching_func->second))(Function_Params{newplist}, t_conversions); } catch (const exception::bad_boxed_cast &) { //parameter failed to cast } catch (const exception::arity_error &) { @@ -966,7 +966,7 @@ namespace chaiscript /// 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 Type_Conversions_State &t_conversions) + const Function_Params &plist, const Type_Conversions_State &t_conversions) { std::vector> ordered_funcs; ordered_funcs.reserve(funcs.size()); diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index ed71663f..3799363f 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -21,6 +21,7 @@ #include "boxed_value.hpp" #include "handle_return.hpp" #include "type_info.hpp" +#include "function_params.hpp" namespace chaiscript { class Type_Conversions_State; @@ -77,7 +78,7 @@ namespace chaiscript */ template bool compare_types_cast(Ret (*)(Params...), - const std::vector ¶ms, const Type_Conversions_State &t_conversions) noexcept + const Function_Params ¶ms, const Type_Conversions_State &t_conversions) noexcept { try { std::vector::size_type i = 0; @@ -92,7 +93,7 @@ namespace chaiscript template Ret call_func(Ret (*)(Params...), std::index_sequence, const Callable &f, - [[maybe_unused]] const std::vector ¶ms, + [[maybe_unused]] const Function_Params ¶ms, [[maybe_unused]] const Type_Conversions_State &t_conversions) { return f(boxed_cast(params[I], &t_conversions)...); @@ -105,7 +106,7 @@ namespace chaiscript /// the bad_boxed_cast is passed up to the caller. template Boxed_Value call_func(Ret (*sig)(Params...), const Callable &f, - const std::vector ¶ms, const Type_Conversions_State &t_conversions) + const Function_Params ¶ms, const Type_Conversions_State &t_conversions) { if constexpr (std::is_same_v) { call_func(sig, std::index_sequence_for{}, f, params, t_conversions); diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index dbbfc744..0527bb0c 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -95,7 +95,7 @@ namespace chaiscript Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled }; - enum class Operator_Precidence { Ternary_Cond, Logical_Or, + enum class Operator_Precedence { Ternary_Cond, Logical_Or, Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And, Equality, Comparison, Shift, Addition, Multiplication, Prefix }; @@ -732,12 +732,7 @@ namespace chaiscript m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); } - void save_params(const std::vector &t_params) - { - m_ds->save_function_params(t_params); - } - - void save_params(std::initializer_list t_params) + void save_params(const Function_Params &t_params) { m_ds->save_function_params(t_params); } diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 47cf43a3..6cf22a1d 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -145,7 +145,7 @@ namespace chaiscript m_engine.add( dispatch::make_dynamic_proxy_function( - [this](const std::vector &t_params) { + [this](const Function_Params &t_params) { return m_engine.call_exists(t_params); }) , "call_exists"); @@ -154,7 +154,7 @@ namespace chaiscript m_engine.add(fun( [=](const dispatch::Proxy_Function_Base &t_fun, const std::vector &t_params) -> Boxed_Value { Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves()); - return t_fun(t_params, s); + return t_fun(Function_Params{t_params}, s); }), "call"); diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 42c18790..dcdf073e 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -51,7 +51,7 @@ namespace chaiscript { /// Helper function that will set up the scope around a function call, including handling the named function parameters template - static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl &t_node, const std::vector &t_param_names, const std::vector &t_vals, const std::map *t_locals=nullptr, bool has_this_capture = false) { + static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl &t_node, const std::vector &t_param_names, const Function_Params &t_vals, const std::map *t_locals=nullptr, bool has_this_capture = false) { chaiscript::detail::Dispatch_State state(t_ss); const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{ @@ -183,8 +183,9 @@ namespace chaiscript } } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - fpp.save_params({t_lhs, m_rhs}); - return t_ss->call_function(t_oper_string, m_loc, {t_lhs, m_rhs}, t_ss.conversions()); + std::array params{t_lhs, m_rhs}; + fpp.save_params(Function_Params{params}); + return t_ss->call_function(t_oper_string, m_loc, Function_Params{params}, t_ss.conversions()); } } catch(const exception::dispatch_error &e){ @@ -229,8 +230,9 @@ namespace chaiscript } } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - fpp.save_params({t_lhs, t_rhs}); - return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}, t_ss.conversions()); + std::array params{t_lhs, t_rhs}; + fpp.save_params(Function_Params(params)); + return t_ss->call_function(t_oper_string, m_loc, Function_Params(params), t_ss.conversions()); } } catch(const exception::dispatch_error &e){ @@ -304,13 +306,13 @@ namespace chaiscript } if (Save_Params) { - fpp.save_params(params); + fpp.save_params(Function_Params{params}); } Boxed_Value fn(this->children[0]->eval(t_ss)); try { - return (*t_ss->boxed_cast(fn))(params, t_ss.conversions()); + return (*t_ss->boxed_cast(fn))(Function_Params{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); @@ -319,7 +321,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 - throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss); + throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, make_vector(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."); } @@ -425,25 +427,25 @@ namespace chaiscript Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - Boxed_Value rhs = this->children[1]->eval(t_ss); - Boxed_Value lhs = this->children[0]->eval(t_ss); - if (m_oper != Operators::Opers::invalid && lhs.get_type_info().is_arithmetic() && - rhs.get_type_info().is_arithmetic()) + std::array params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)}; + + if (m_oper != Operators::Opers::invalid && params[0].get_type_info().is_arithmetic() && + params[0].get_type_info().is_arithmetic()) { try { - return Boxed_Number::do_oper(m_oper, lhs, rhs); + return Boxed_Number::do_oper(m_oper, params[0], params[1]); } catch (const std::exception &) { throw exception::eval_error("Error with unsupported arithmetic assignment operation"); } } else if (m_oper == Operators::Opers::assign) { - if (lhs.is_return_value()) { + if (params[0].is_return_value()) { throw exception::eval_error("Error, cannot assign to temporary value."); } try { - if (lhs.is_undef()) { + if (params[0].is_undef()) { if (!this->children.empty() && ((this->children[0]->identifier == AST_Node_Type::Reference) || (!this->children[0]->children.empty() @@ -454,20 +456,20 @@ namespace chaiscript { /// \todo This does not handle the case of an unassigned reference variable /// being assigned outside of its declaration - lhs.assign(rhs); - lhs.reset_return_value(); - return rhs; + params[0].assign(params[1]); + params[0].reset_return_value(); + return params[1]; } else { - if (!rhs.is_return_value()) + if (!params[1].is_return_value()) { - rhs = t_ss->call_function("clone", m_clone_loc, {rhs}, t_ss.conversions()); + params[1] = t_ss->call_function("clone", m_clone_loc, Function_Params{¶ms[0], std::end(params)}, t_ss.conversions()); } - rhs.reset_return_value(); + params[1].reset_return_value(); } } try { - return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions()); + return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions()); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss); @@ -478,22 +480,22 @@ namespace chaiscript } } else if (this->text == ":=") { - if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) { - lhs.assign(rhs); - lhs.reset_return_value(); + if (params[0].is_undef() || Boxed_Value::type_match(params[0], params[1])) { + params[0].assign(params[1]); + params[0].reset_return_value(); } else { throw exception::eval_error("Mismatched types in equation"); } } else { try { - return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions()); + return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions()); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss); } } - return rhs; + return params[1]; } private: @@ -550,11 +552,11 @@ namespace chaiscript Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - const std::vector params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)}; + std::array params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)}; try { - fpp.save_params(params); - return t_ss->call_function("[]", m_loc, params, t_ss.conversions()); + fpp.save_params(Function_Params{params}); + return t_ss->call_function("[]", m_loc, Function_Params{params}, t_ss.conversions()); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss ); @@ -579,7 +581,7 @@ namespace chaiscript Boxed_Value retval = this->children[0]->eval(t_ss); - std::vector params{retval}; + auto params = make_vector(retval); bool has_function_params = false; if (this->children[1]->children.size() > 1) { @@ -589,10 +591,10 @@ namespace chaiscript } } - fpp.save_params(params); + fpp.save_params(Function_Params{params}); try { - retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params, t_ss.conversions()); + retval = t_ss->call_member(m_fun_name, m_loc, Function_Params{params}, has_function_params, t_ss.conversions()); } catch(const exception::dispatch_error &e){ if (e.functions.empty()) @@ -608,7 +610,8 @@ namespace chaiscript if (this->children[1]->identifier == AST_Node_Type::Array_Call) { try { - retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[1]->children[1]->eval(t_ss)}, t_ss.conversions()); + std::array p{retval, this->children[1]->children[1]->eval(t_ss)}; + retval = t_ss->call_function("[]", m_array_loc, Function_Params{p}, t_ss.conversions()); } catch(const exception::dispatch_error &e){ throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss); @@ -657,7 +660,7 @@ namespace chaiscript return Boxed_Value( dispatch::make_dynamic_proxy_function( [engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures, - this_capture = this->m_this_capture] (const std::vector &t_params) + this_capture = this->m_this_capture] (const Function_Params &t_params) { return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture); }, @@ -771,7 +774,7 @@ namespace chaiscript std::shared_ptr guard; if (m_guard_node) { guard = dispatch::make_dynamic_proxy_function( - [engine, guardnode = m_guard_node, t_param_names](const std::vector &t_params) + [engine, guardnode = m_guard_node, t_param_names](const Function_Params &t_params) { return detail::eval_function(engine, *guardnode, t_param_names, t_params); }, @@ -782,7 +785,7 @@ namespace chaiscript const std::string & l_function_name = this->children[0]->text; t_ss->add( dispatch::make_dynamic_proxy_function( - [engine, func_node = m_body_node, t_param_names](const std::vector &t_params) + [engine, func_node = m_body_node, t_param_names](const Function_Params &t_params) { return detail::eval_function(engine, *func_node, t_param_names, t_params); }, @@ -873,7 +876,7 @@ namespace chaiscript }; const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) { - return dispatch::dispatch(*t_funcs, {t_param}, t_ss.conversions()); + return dispatch::dispatch(*t_funcs, Function_Params{t_param}, t_ss.conversions()); }; @@ -988,7 +991,8 @@ namespace chaiscript if (this->children[currentCase]->identifier == AST_Node_Type::Case) { //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here. try { - if (hasMatched || boxed_cast(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}, t_ss.conversions()))) { + std::array p{match_value, this->children[currentCase]->children[0]->eval(t_ss)}; + if (hasMatched || boxed_cast(t_ss->call_function("==", m_loc, Function_Params{p}, t_ss.conversions()))) { this->children[currentCase]->eval(t_ss); hasMatched = true; } @@ -1057,7 +1061,7 @@ namespace chaiscript for (const auto &child : this->children[0]->children) { if (auto obj = child->eval(t_ss); !obj.is_return_value()) { - vec.push_back(t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions())); + vec.push_back(t_ss->call_function("clone", m_loc, Function_Params{obj}, t_ss.conversions())); } else { vec.push_back(std::move(obj)); } @@ -1087,7 +1091,7 @@ namespace chaiscript for (const auto &child : this->children[0]->children) { auto obj = child->children[1]->eval(t_ss); if (!obj.is_return_value()) { - obj = t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions()); + obj = t_ss->call_function("clone", m_loc, Function_Params{obj}, t_ss.conversions()); } retval[t_ss->boxed_cast(child->children[0]->eval(t_ss))] = std::move(obj); @@ -1174,8 +1178,8 @@ namespace chaiscript return Boxed_Number::do_oper(m_oper, bv); } else { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - fpp.save_params({bv}); - return t_ss->call_function(this->text, m_loc, {std::move(bv)}, t_ss.conversions()); + fpp.save_params(Function_Params{bv}); + return t_ss->call_function(this->text, m_loc, Function_Params{bv}, t_ss.conversions()); } } catch (const exception::dispatch_error &e) { throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss); @@ -1240,9 +1244,12 @@ namespace chaiscript Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ try { - auto oper1 = this->children[0]->children[0]->children[0]->eval(t_ss); - auto oper2 = this->children[0]->children[0]->children[1]->eval(t_ss); - return t_ss->call_function("generate_range", m_loc, {oper1, oper2}, t_ss.conversions()); + std::array params{ + this->children[0]->children[0]->children[0]->eval(t_ss), + this->children[0]->children[0]->children[1]->eval(t_ss) + }; + + return t_ss->call_function("generate_range", m_loc, Function_Params{params}, t_ss.conversions()); } catch (const exception::dispatch_error &e) { throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss); @@ -1280,7 +1287,7 @@ namespace chaiscript if (dispatch::Param_Types( std::vector>{Arg_List_AST_Node::get_arg_type(*catch_block.children[0], t_ss)} - ).match(std::vector{t_except}, t_ss.conversions()).first) + ).match(Function_Params{t_except}, t_ss.conversions()).first) { t_ss.add_object(name, t_except); @@ -1410,7 +1417,7 @@ namespace chaiscript std::reference_wrapper engine(*t_ss); if (m_guard_node) { guard = dispatch::make_dynamic_proxy_function( - [engine, t_param_names, guardnode = m_guard_node](const std::vector &t_params) { + [engine, t_param_names, guardnode = m_guard_node](const Function_Params &t_params) { return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params); }, static_cast(numparams), m_guard_node); @@ -1425,7 +1432,7 @@ namespace chaiscript t_ss->add( std::make_shared(class_name, dispatch::make_dynamic_proxy_function( - [engine, t_param_names, node = m_body_node](const std::vector &t_params) { + [engine, t_param_names, node = m_body_node](const Function_Params &t_params) { return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params); }, static_cast(numparams), m_body_node, param_types, guard @@ -1442,7 +1449,7 @@ namespace chaiscript t_ss->add( std::make_shared(class_name, dispatch::make_dynamic_proxy_function( - [engine, t_param_names, node = m_body_node](const std::vector &t_params) { + [engine, t_param_names, node = m_body_node](const Function_Params &t_params) { return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params); }, static_cast(numparams), m_body_node, param_types, guard), type), diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index ebcef83f..749ac9d3 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -263,20 +263,20 @@ namespace chaiscript }; - constexpr static std::array create_operators() noexcept { - std::array operators = { { - Operator_Precidence::Ternary_Cond, - Operator_Precidence::Logical_Or, - Operator_Precidence::Logical_And, - Operator_Precidence::Bitwise_Or, - Operator_Precidence::Bitwise_Xor, - Operator_Precidence::Bitwise_And, - Operator_Precidence::Equality, - Operator_Precidence::Comparison, - Operator_Precidence::Shift, - Operator_Precidence::Addition, - Operator_Precidence::Multiplication, - Operator_Precidence::Prefix + constexpr static std::array create_operators() noexcept { + std::array operators = { { + Operator_Precedence::Ternary_Cond, + Operator_Precedence::Logical_Or, + Operator_Precedence::Logical_And, + Operator_Precedence::Bitwise_Or, + Operator_Precedence::Bitwise_Xor, + Operator_Precedence::Bitwise_And, + Operator_Precedence::Equality, + Operator_Precedence::Comparison, + Operator_Precedence::Shift, + Operator_Precedence::Addition, + Operator_Precedence::Multiplication, + Operator_Precedence::Prefix } }; return operators; } @@ -2363,7 +2363,7 @@ namespace chaiscript bool retval = false; const auto prev_stack_top = m_match_stack.size(); - if (m_operators[t_precedence] != Operator_Precidence::Prefix) { + if (m_operators[t_precedence] != Operator_Precedence::Prefix) { if (Operator(t_precedence+1)) { retval = true; std::string oper; @@ -2375,7 +2375,7 @@ namespace chaiscript } switch (m_operators[t_precedence]) { - case(Operator_Precidence::Ternary_Cond) : + case(Operator_Precedence::Ternary_Cond) : if (Symbol(":")) { if (!Operator(t_precedence+1)) { throw exception::eval_error("Incomplete '" + oper + "' expression", @@ -2389,24 +2389,24 @@ namespace chaiscript } break; - case(Operator_Precidence::Addition) : - case(Operator_Precidence::Multiplication) : - case(Operator_Precidence::Shift) : - case(Operator_Precidence::Equality) : - case(Operator_Precidence::Bitwise_And) : - case(Operator_Precidence::Bitwise_Xor) : - case(Operator_Precidence::Bitwise_Or) : - case(Operator_Precidence::Comparison) : + case(Operator_Precedence::Addition) : + case(Operator_Precedence::Multiplication) : + case(Operator_Precedence::Shift) : + case(Operator_Precedence::Equality) : + case(Operator_Precedence::Bitwise_And) : + case(Operator_Precedence::Bitwise_Xor) : + case(Operator_Precedence::Bitwise_Or) : + case(Operator_Precedence::Comparison) : build_match>(prev_stack_top, oper); break; - case(Operator_Precidence::Logical_And) : + case(Operator_Precedence::Logical_And) : build_match>(prev_stack_top, oper); break; - case(Operator_Precidence::Logical_Or) : + case(Operator_Precedence::Logical_Or) : build_match>(prev_stack_top, oper); break; - case(Operator_Precidence::Prefix) : + case(Operator_Precedence::Prefix) : assert(false); // cannot reach here because of if() statement at the top break; diff --git a/include/chaiscript/utility/stack_vector.hpp b/include/chaiscript/utility/stack_vector.hpp new file mode 100644 index 00000000..706d276a --- /dev/null +++ b/include/chaiscript/utility/stack_vector.hpp @@ -0,0 +1,63 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + + +#ifndef CHAISCRIPT_STACK_VECTOR_HPP_ +#define CHAISCRIPT_STACK_VECTOR_HPP_ + +#include +#include +#include + + + +template +struct Stack_Vector +{ + constexpr static auto aligned_size = sizeof(T) + (sizeof(T) & std::alignment_of_v) > 0 ? std::alignment_of_v : 0; + + alignas(std::alignment_of_v) char data[aligned_size * MaxSize]; + + [[nodiscard]] T & operator[](const std::size_t idx) noexcept { + return *reinterpret_cast(&data + aligned_size * idx); + } + + [[nodiscard]] const T & operator[](const std::size_t idx) const noexcept { + return *reinterpret_cast(&data + aligned_size * idx); + } + + template + T& emplace_back(Param && ... param) { + auto *p = new(&(*this)[m_size++]) T(std::forward(param)...); + return *p; + }; + + auto size() const noexcept { + return m_size; + }; + + void pop_back() noexcept(std::is_nothrow_destructible_v) { + (*this)[m_size--].~T(); + } + + ~Stack_Vector() noexcept(std::is_nothrow_destructible_v) + { + auto loc = m_size - 1; + for (std::size_t pos = 0; pos < m_size; ++pos) { + (*this)[loc--].~T(); + } + } + + std::size_t m_size{0}; + +}; + +#endif CHAISCRIPT_STACK_VECTOR_HPP_ + + From b03b90dee602bde9316498fe98b1f4ea0ff760fc Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 17 Nov 2017 05:26:24 -0700 Subject: [PATCH 05/18] Fix bug introduced with Function_Params refactor --- include/chaiscript/language/chaiscript_eval.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index dcdf073e..cac5d293 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -462,7 +462,7 @@ namespace chaiscript } else { if (!params[1].is_return_value()) { - params[1] = t_ss->call_function("clone", m_clone_loc, Function_Params{¶ms[0], std::end(params)}, t_ss.conversions()); + params[1] = t_ss->call_function("clone", m_clone_loc, Function_Params{¶ms[1], std::end(params)}, t_ss.conversions()); } params[1].reset_return_value(); } From a6d30baa27c6fbacb85d8f675baef9f809a6bf2d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 17 Nov 2017 06:12:50 -0700 Subject: [PATCH 06/18] Apply some if constexpr action --- .../dispatchkit/function_call_detail.hpp | 104 +++++------------- .../chaiscript/dispatchkit/handle_return.hpp | 4 +- .../chaiscript/language/chaiscript_eval.hpp | 2 +- 3 files changed, 28 insertions(+), 82 deletions(-) diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 5cd1932e..023947cc 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -29,66 +29,7 @@ namespace chaiscript { namespace detail { - /// 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 Function_Params ¶ms, const Type_Conversions_State *t_conversions) - { - if (t_conversions != nullptr) { - return boxed_cast(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions); - } else { - Type_Conversions conv; - Type_Conversions_State state(conv, conv.conversion_saves()); - return boxed_cast(dispatch::dispatch(t_funcs, params, state), t_conversions); - } - } - }; - - /** - * Specialization for arithmetic return types - */ - template - struct Function_Caller_Ret - { - static Ret call(const std::vector &t_funcs, - const Function_Params ¶ms, const Type_Conversions_State *t_conversions) - { - if (t_conversions != nullptr) { - return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as(); - } else { - Type_Conversions conv; - Type_Conversions_State state(conv, conv.conversion_saves()); - return Boxed_Number(dispatch::dispatch(t_funcs, params, state)).get_as(); - } - } - }; - - - /** - * Specialization for void return types - */ - template<> - struct Function_Caller_Ret - { - static void call(const std::vector &t_funcs, - const Function_Params ¶ms, const Type_Conversions_State *t_conversions) - { - if (t_conversions != nullptr) { - dispatch::dispatch(t_funcs, params, *t_conversions); - } else { - Type_Conversions conv; - Type_Conversions_State state(conv, conv.conversion_saves()); - dispatch::dispatch(t_funcs, params, state); - } - } - }; - - /** - * used internally for unwrapping a function call's types - */ + /// used internally for unwrapping a function call's types template struct Build_Function_Caller_Helper { @@ -98,6 +39,17 @@ namespace chaiscript { } + Ret call(const Function_Params ¶ms, const Type_Conversions_State &t_state) + { + if constexpr (std::is_arithmetic_v) { + return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as(); + } else if constexpr (std::is_same_v) { + dispatch::dispatch(m_funcs, params, t_state); + } else { + return boxed_cast(dispatch::dispatch(m_funcs, params, t_state), &t_state); + } + } + template Ret operator()(P&& ... param) { @@ -105,32 +57,26 @@ namespace chaiscript if (m_conversions) { Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves()); - return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, Function_Params{params}, &state - ); + return call(Function_Params{params}, state); } else { - return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, Function_Params{params}, nullptr - ); + Type_Conversions conv; + Type_Conversions_State state(conv, conv.conversion_saves()); + return call(Function_Params{params}, state); } } - template - static auto box(Q&& q) -> typename std::enable_if::value&&!std::is_same::type>::type>::value, Boxed_Value>::type - { - return Boxed_Value(std::ref(std::forward(q))); - } template - static auto box(Q&& q) -> typename std::enable_if::value&&!std::is_same::type>::type>::value, Boxed_Value>::type - { - return Boxed_Value(std::forward(q)); - } - - template - static Boxed_Value box(Boxed_Value bv) noexcept - { - return bv; - } + static Boxed_Value box(Q &&q) { + if constexpr (std::is_same_v>) { + return std::forward(q); + } else if constexpr (std::is_reference_v

) { + return Boxed_Value(std::ref(std::forward(q))); + } else { + return Boxed_Value(std::forward(q)); + } + } std::vector m_funcs; diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index 4dc381d4..e06b44df 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -36,14 +36,14 @@ namespace chaiscript struct Handle_Return { template::type>::value>::type> + typename = std::enable_if_t>>> static Boxed_Value handle(T r) { return Boxed_Value(std::move(r), true); } template::type>::value>::type> + typename = std::enable_if_t>>> static Boxed_Value handle(T &&r) { return Boxed_Value(std::make_shared(std::forward(r)), true); diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index cac5d293..f368d62f 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -920,6 +920,7 @@ namespace chaiscript try { this->children[2]->eval(t_ss); } catch (detail::Continue_Loop &) { + // continue statement hit } call_function(pop_front_funcs, range_obj); } @@ -1456,7 +1457,6 @@ namespace chaiscript function_name); } } catch (const exception::name_conflict_error &e) { - std::cout << "Method!!" << std::endl; throw exception::eval_error("Method redefined '" + e.name() + "'"); } return void_var(); From d59350d356df3e9b5d9a83b61beaac4c0c629122 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 18 Nov 2017 18:42:45 -0700 Subject: [PATCH 07/18] Various cleanups --- include/chaiscript/dispatchkit/bootstrap.hpp | 4 ++-- include/chaiscript/dispatchkit/boxed_value.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 9a94d104..983ae64c 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -151,7 +151,7 @@ namespace chaiscript /// 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) + std::shared_ptr> shared_ptr_unconst_clone(const std::shared_ptr> &p) { return std::const_pointer_cast::type>(p); } @@ -483,7 +483,7 @@ namespace chaiscript opers_arithmetic_pod(m); - + m.add(fun(&Build_Info::version_major), "version_major"); m.add(fun(&Build_Info::version_minor), "version_minor"); m.add(fun(&Build_Info::version_patch), "version_patch"); diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 3bef5851..1fb72722 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -194,7 +194,7 @@ namespace chaiscript public: /// Basic Boxed_Value constructor template::type>::value>::type> + typename = std::enable_if_t>>> explicit Boxed_Value(T &&t, bool t_return_value = false) : m_data(Object_Data::get(std::forward(t), t_return_value)) { From 92ae85c3e822cfc530a7c865e660e81d2da9a4a2 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 18 Nov 2017 19:08:14 -0700 Subject: [PATCH 08/18] Remove guards from catch blocks --- .../chaiscript/language/chaiscript_eval.hpp | 21 ++---------- .../chaiscript/language/chaiscript_parser.hpp | 5 --- unittests/3.x/exception_guards.chai | 34 ------------------- unittests/exception_guards.chai | 34 ------------------- unittests/exception_typed_2.chai | 34 ------------------- 5 files changed, 2 insertions(+), 126 deletions(-) delete mode 100644 unittests/3.x/exception_guards.chai delete mode 100644 unittests/exception_guards.chai delete mode 100644 unittests/exception_typed_2.chai diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index f368d62f..a99c4ebb 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -1280,7 +1280,7 @@ namespace chaiscript auto &catch_block = *this->children[i]; if (catch_block.children.size() == 1) { - //No variable capture, no guards + //No variable capture retval = catch_block.children[0]->eval(t_ss); break; } else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) { @@ -1293,27 +1293,10 @@ namespace chaiscript t_ss.add_object(name, t_except); if (catch_block.children.size() == 2) { - //Variable capture, no guards + //Variable capture retval = catch_block.children[1]->eval(t_ss); break; } - else if (catch_block.children.size() == 3) { - //Variable capture, guards - - bool guard = false; - try { - guard = boxed_cast(catch_block.children[1]->eval(t_ss)); - } catch (const exception::bad_boxed_cast &) { - if (this->children.back()->identifier == AST_Node_Type::Finally) { - this->children.back()->children[0]->eval(t_ss); - } - throw exception::eval_error("Guard condition not boolean"); - } - if (guard) { - retval = catch_block.children[2]->eval(t_ss); - break; - } - } } } else { diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 749ac9d3..77386c3e 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1715,11 +1715,6 @@ namespace chaiscript if (!(Arg() && Char(')'))) { throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_position.line, m_position.col), *m_filename); } - if (Char(':')) { - if (!Operator()) { - throw exception::eval_error("Missing guard expression for catch", File_Position(m_position.line, m_position.col), *m_filename); - } - } } while (Eol()) {} diff --git a/unittests/3.x/exception_guards.chai b/unittests/3.x/exception_guards.chai deleted file mode 100644 index 99cd9018..00000000 --- a/unittests/3.x/exception_guards.chai +++ /dev/null @@ -1,34 +0,0 @@ -var results = []; - -for (var i = 2; i < 6; ++i) { - try { - throw(i) - } - catch(e) : e < 2 { - results.push_back("c1: " + e.to_string()); - } - catch(e) : e < 4 { - results.push_back("c2: " + e.to_string()); - } - catch(e) { - results.push_back("c3: " + e.to_string()); - } - catch { - // Should never get called - assert_equal(false, true) - } -} - -try { - throw(3) -} -catch(e) : e < 3 -{ - // Should never get called - assert_equal(false, true); -} -catch { - results.push_back("defaultcatch"); -} - -assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results); diff --git a/unittests/exception_guards.chai b/unittests/exception_guards.chai deleted file mode 100644 index 12792985..00000000 --- a/unittests/exception_guards.chai +++ /dev/null @@ -1,34 +0,0 @@ -auto results = []; - -for (auto i = 2; i < 6; ++i) { - try { - throw(i) - } - catch(e) : e < 2 { - results.push_back("c1: " + e.to_string()); - } - catch(e) : e < 4 { - results.push_back("c2: " + e.to_string()); - } - catch(e) { - results.push_back("c3: " + e.to_string()); - } - catch { - // Should never get called - assert_equal(false, true) - } -} - -try { - throw(3) -} -catch(e) : e < 3 -{ - // Should never get called - assert_equal(false, true); -} -catch { - results.push_back("defaultcatch"); -} - -assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results); diff --git a/unittests/exception_typed_2.chai b/unittests/exception_typed_2.chai deleted file mode 100644 index cb294c78..00000000 --- a/unittests/exception_typed_2.chai +++ /dev/null @@ -1,34 +0,0 @@ -auto results = []; - -for (auto i = 2; i < 6; ++i) { - try { - throw(i) - } - catch(int e) : e < 2 { - results.push_back("c1: " + e.to_string()); - } - catch(int e) : e < 4 { - results.push_back("c2: " + e.to_string()); - } - catch(e) { - results.push_back("c3: " + e.to_string()); - } - catch { - // Should never get called - assert_equal(false, true) - } -} - -try { - throw(3) -} -catch(int e) : e < 3 -{ - // Should never get called - assert_equal(false, true); -} -catch { - results.push_back("defaultcatch"); -} - -assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results); From c6021f3e6183aad8ccad8cd0ad702e5b1b1eb611 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 19 Nov 2017 06:20:27 -0700 Subject: [PATCH 09/18] Bug fix from Function_Params refactor --- include/chaiscript/dispatchkit/any.hpp | 4 ++-- include/chaiscript/dispatchkit/dispatchkit.hpp | 4 ++-- include/chaiscript/language/chaiscript_eval.hpp | 16 +++++++++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index a9e31594..f8f94f26 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -84,7 +84,7 @@ namespace chaiscript { // construct/copy/destruct constexpr Any() noexcept = default; Any(Any &&) noexcept = default; - Any &operator=(Any &&t_any) noexcept = default; + Any &operator=(Any &&t_any) = default; Any(const Any &t_any) : m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) @@ -93,7 +93,7 @@ namespace chaiscript { template>>> - explicit Any(ValueType &&t_value) noexcept(is_nothrow_forward_constructible_v>) + explicit Any(ValueType &&t_value) : m_data(std::make_unique>>(std::forward(t_value))) { } diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 4f338cee..6e39aff4 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1053,7 +1053,7 @@ namespace chaiscript tmp_params.insert(tmp_params.begin() + 1, var(t_name)); return do_attribute_call(2, Function_Params(tmp_params), functions, t_conversions); } else { - std::array p{params[0], var(t_name), var(std::vector(params.begin()+1, params.end()))}; + std::array p{params[0], var(t_name), var(std::vector(params.begin()+1, params.end()))}; return dispatch::dispatch(functions, Function_Params{p}, t_conversions); } } catch (const dispatch::option_explicit_set &e) { @@ -1077,7 +1077,7 @@ namespace chaiscript - Boxed_Value call_function(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc, Function_Params params, + Boxed_Value call_function(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc, const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const { uint_fast32_t loc = t_loc; diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index a99c4ebb..781615c9 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -428,10 +428,20 @@ namespace chaiscript Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - std::array params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)}; + auto params = [&](){ + // The RHS *must* be evaluated before the LHS + // consider `var range = range(x)` + // if we declare the variable in scope first, then the name lookup fails + // for the RHS + auto rhs = this->children[1]->eval(t_ss); + auto lhs = this->children[0]->eval(t_ss); + std::array p{std::move(lhs), std::move(rhs)}; + return p; + }(); + if (m_oper != Operators::Opers::invalid && params[0].get_type_info().is_arithmetic() && - params[0].get_type_info().is_arithmetic()) + params[1].get_type_info().is_arithmetic()) { try { return Boxed_Number::do_oper(m_oper, params[0], params[1]); @@ -452,7 +462,7 @@ namespace chaiscript && this->children[0]->children[0]->identifier == AST_Node_Type::Reference) ) ) - + { /// \todo This does not handle the case of an unassigned reference variable /// being assigned outside of its declaration From a1772a055b6995752cb6c8118187ebf156ce82e2 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 19 Nov 2017 06:25:30 -0700 Subject: [PATCH 10/18] Remove some `std::endl` usage --- samples/fun_call_performance.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/samples/fun_call_performance.cpp b/samples/fun_call_performance.cpp index 31fa606c..5b8478b9 100644 --- a/samples/fun_call_performance.cpp +++ b/samples/fun_call_performance.cpp @@ -145,20 +145,20 @@ std::vector default_search_paths() void help(int n) { if (n >= 0) { - std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press ." << std::endl; - std::cout << "Additionally, you can inspect the runtime system using:" << std::endl; - std::cout << " dump_system() - outputs all functions registered to the system" << std::endl; - std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl; + std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press .\n"; + std::cout << "Additionally, you can inspect the runtime system using:\n"; + std::cout << " dump_system() - outputs all functions registered to the system\n"; + std::cout << " dump_object(x) - dumps information about the given symbol\n"; } else { - std::cout << "usage : chai [option]+" << std::endl; - std::cout << "option:" << std::endl; - std::cout << " -h | --help" << std::endl; - std::cout << " -i | --interactive" << std::endl; - std::cout << " -c | --command cmd" << std::endl; - std::cout << " -v | --version" << std::endl; - std::cout << " - --stdin" << std::endl; - std::cout << " filepath" << std::endl; + std::cout << "usage : chai [option]+\n"; + std::cout << "option:\n"; + std::cout << " -h | --help\n"; + std::cout << " -i | --interactive\n"; + std::cout << " -c | --command cmd\n"; + std::cout << " -v | --version\n"; + std::cout << " - --stdin\n"; + std::cout << " filepath\n"; } } @@ -244,7 +244,7 @@ void interactive(chaiscript::ChaiScript& chai) //Then, we try to print the result of the evaluation to the user if (!val.get_type_info().bare_equal(chaiscript::user_type())) { try { - std::cout << chai.eval >("to_string")(val) << std::endl; + std::cout << chai.eval >("to_string")(val) << '\n'; } catch (...) {} //If we can't, do nothing } @@ -254,7 +254,7 @@ void interactive(chaiscript::ChaiScript& chai) if (ee.call_stack.size() > 0) { std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")"; } - std::cout << std::endl; + std::cout << '\n'; } catch (const std::exception &e) { std::cout << e.what(); From 61bce309018a04d7c05d37bb0de22f9afac6307d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 21 Nov 2017 06:30:19 -0700 Subject: [PATCH 11/18] Unused code removal --- .../chaiscript/dispatchkit/bootstrap_stl.hpp | 145 +----------------- 1 file changed, 2 insertions(+), 143 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index df25c9ec..684096d4 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -178,13 +178,6 @@ namespace chaiscript detail::input_range_type_impl >(type,m); detail::input_range_type_impl >("Const_" + type,m); } - template - ModulePtr input_range_type(const std::string &type) - { - auto m = std::make_shared(); - input_range_type(type, *m); - return m; - } /// Add random_access_container concept to the given ContainerType @@ -197,7 +190,7 @@ namespace chaiscript m.add( fun( [](ContainerType &c, int index) -> typename ContainerType::reference { - /// \todo we are prefering to keep the key as 'int' to avoid runtime conversions + /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions /// during dispatch. reevaluate return c.at(static_cast(index)); }), "[]"); @@ -205,19 +198,11 @@ namespace chaiscript m.add( fun( [](const ContainerType &c, int index) -> typename ContainerType::const_reference { - /// \todo we are prefering to keep the key as 'int' to avoid runtime conversions + /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions /// during dispatch. reevaluate return c.at(static_cast(index)); }), "[]"); } - template - ModulePtr random_access_container_type(const std::string &type) - { - auto m = std::make_shared(); - random_access_container_type(type, *m); - return m; - } - /// Add assignable concept to the given ContainerType @@ -228,14 +213,6 @@ namespace chaiscript copy_constructor(type, m); operators::assign(m); } - template - ModulePtr assignable_type(const std::string &type) - { - auto m = std::make_shared(); - assignable_type(type, *m); - return m; - } - /// Add container resize concept to the given ContainerType /// http://www.cplusplus.com/reference/stl/ @@ -245,14 +222,6 @@ namespace chaiscript m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type& val) { return a->resize(n, val); } ), "resize"); m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); } ), "resize"); } - template - ModulePtr resizable_type(const std::string &type) - { - auto m = std::make_shared(); - resizable_type(type, *m); - return m; - } - /// Add container reserve concept to the given ContainerType /// http://www.cplusplus.com/reference/stl/ @@ -262,14 +231,6 @@ namespace chaiscript m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); } ), "reserve"); m.add(fun([](const ContainerType *a) { return a->capacity(); } ), "capacity"); } - template - ModulePtr reservable_type(const std::string &type) - { - auto m = std::make_shared(); - reservable_type(type, *m); - return m; - } - /// Add container concept to the given ContainerType /// http://www.sgi.com/tech/stl/Container.html @@ -280,14 +241,6 @@ namespace chaiscript m.add(fun([](const ContainerType *a) { return a->empty(); } ), "empty"); m.add(fun([](ContainerType *a) { a->clear(); } ), "clear"); } - template - ModulePtr container_type(const std::string& type) - { - auto m = std::make_shared(); - container_type(type, *m); - return m; - } - /// Add default constructable concept to the given Type /// http://www.sgi.com/tech/stl/DefaultConstructible.html @@ -296,15 +249,6 @@ namespace chaiscript { m.add(constructor(), type); } - template - ModulePtr default_constructible_type(const std::string& type) - { - auto m = std::make_shared(); - default_constructible_type(type, *m); - return m; - } - - /// Add sequence concept to the given ContainerType /// http://www.sgi.com/tech/stl/Sequence.html @@ -322,13 +266,6 @@ namespace chaiscript m.add(fun(&detail::erase_at), "erase_at"); } - template - ModulePtr sequence_type(const std::string &type) - { - auto m = std::make_shared(); - sequence_type(type, *m); - return m; - } /// Add back insertion sequence concept to the given ContainerType /// http://www.sgi.com/tech/stl/BackInsertionSequence.html @@ -380,14 +317,6 @@ namespace chaiscript m.add(fun(&ContainerType::pop_back), "pop_back"); } - template - ModulePtr back_insertion_sequence_type(const std::string &type) - { - auto m = std::make_shared(); - back_insertion_sequence_type(type, *m); - return m; - } - /// Front insertion sequence @@ -442,14 +371,6 @@ namespace chaiscript m.add(fun(static_cast(&ContainerType::pop_front)), "pop_front"); } - template - ModulePtr front_insertion_sequence_type(const std::string &type) - { - auto m = std::make_shared(); - front_insertion_sequence_type(type, *m); - return m; - } - /// bootstrap a given PairType /// http://www.sgi.com/tech/stl/pair.html @@ -464,14 +385,6 @@ namespace chaiscript basic_constructors(type, m); m.add(constructor(), type); } - template - ModulePtr pair_type(const std::string &type) - { - auto m = std::make_shared(); - pair_type(type, *m); - return m; - } - /// Add pair associative container concept to the given ContainerType @@ -482,14 +395,6 @@ namespace chaiscript { pair_type(type + "_Pair", m); } - template - ModulePtr pair_associative_container_type(const std::string &type) - { - auto m = std::make_shared(); - pair_associative_container_type(type, *m); - return m; - } - /// Add unique associative container concept to the given ContainerType /// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html @@ -513,14 +418,6 @@ namespace chaiscript } }()); } - template - ModulePtr unique_associative_container_type(const std::string &type) - { - auto m = std::make_shared(); - unique_associative_container_type(type, *m); - return m; - } - /// Add a MapType container /// http://www.sgi.com/tech/stl/Map.html @@ -568,14 +465,6 @@ namespace chaiscript pair_associative_container_type(type, m); input_range_type(type, m); } - template - ModulePtr map_type(const std::string &type) - { - auto m = std::make_shared(); - map_type(type, *m); - return m; - } - /// http://www.sgi.com/tech/stl/List.html template @@ -592,14 +481,6 @@ namespace chaiscript assignable_type(type, m); input_range_type(type, m); } - template - ModulePtr list_type(const std::string &type) - { - auto m = std::make_shared(); - list_type(type, m); - return m; - } - /// Create a vector type with associated concepts /// http://www.sgi.com/tech/stl/Vector.html @@ -665,13 +546,6 @@ namespace chaiscript ); } } - template - ModulePtr vector_type(const std::string &type) - { - auto m = std::make_shared(); - vector_type(type, *m); - return m; - } /// Add a String container /// http://www.sgi.com/tech/stl/basic_string.html @@ -715,14 +589,6 @@ namespace chaiscript m.add(fun([](const String *s) { return s->data(); } ), "data"); m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr"); } - template - ModulePtr string_type(const std::string &type) - { - auto m = std::make_shared(); - string_type(type, *m); - return m; - } - /// Add a MapType container @@ -736,13 +602,6 @@ namespace chaiscript m.add(fun(&FutureType::get), "get"); m.add(fun(&FutureType::wait), "wait"); } - template - ModulePtr future_type(const std::string &type) - { - auto m = std::make_shared(); - future_type(type, *m); - return m; - } } } } From fe405a781c6c6b38d7dbf57efdf6d2d643094256 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 21 Nov 2017 16:10:13 -0700 Subject: [PATCH 12/18] Revert "Merge branch 'typed_function_ordering' into c++17" This reverts commit 5d5a126bb15b8490ebdb92a8f0a8b2b990d8a067, reversing changes made to dd912822a7979aad101042c62478c2441ae21d1a. --- .../chaiscript/dispatchkit/dispatchkit.hpp | 231 ++++++------------ .../dispatchkit/dynamic_object_detail.hpp | 27 +- .../dispatchkit/proxy_functions.hpp | 38 +-- unittests/compiled_tests.cpp | 4 +- 4 files changed, 82 insertions(+), 218 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 930bff61..f8bbf45f 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -1104,30 +1104,22 @@ namespace chaiscript { const auto params = f.second->get_param_types(); - std::vector> typed_params; - - auto func(std::dynamic_pointer_cast(f.second)); - if (func) { - typed_params = func->get_dynamic_param_types().types(); - } - dump_type(params.front()); std::cout << " " << f.first << "("; - for (size_t i = 1; i < params.size(); ++i) + for (auto itr = params.begin() + 1; + itr != params.end(); + ) { - if (!typed_params.empty() && !typed_params[i-1].first.empty()) { - std::cout << typed_params[i-1].first; - } else { - dump_type(params[i]); - } + dump_type(*itr); + ++itr; - if (i != params.size() - 1) { + if (itr != params.end()) + { std::cout << ", "; } } - std::cout << ") \n"; } @@ -1321,157 +1313,88 @@ namespace chaiscript return m_state.m_functions; } - - static std::vector param_types(const Proxy_Function &t_f) + static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) noexcept { - assert(t_f); - return t_f->get_param_types(); - } - static std::vector> param_types(const std::shared_ptr &t_f) - { - assert(t_f); - const auto types = t_f->get_dynamic_param_types().types(); - std::vector> ret(1); - ret.insert(ret.end(), types.begin(), types.end()); - return ret; - } + auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); + auto dynamic_rhs(std::dynamic_pointer_cast(rhs)); - static Type_Info type_info(const std::pair &t_ti) - { - return t_ti.second; - } - - static Type_Info type_info(const Type_Info &t_ti) - { - return t_ti; - } - - static std::string dynamic_type_name(const std::pair &t_ti) - { - return t_ti.first.empty()?t_ti.second.name():t_ti.first; - } - - static std::string dynamic_type_name(const Type_Info &ti) - { - return ti.name(); - } - - - template - static bool params_less_than(const LHS &t_lhs, const RHS &t_rhs) + if (dynamic_lhs && dynamic_rhs) { - assert(t_lhs); - assert(t_rhs); - const auto lhsparamtypes = param_types(t_lhs); - const auto rhsparamtypes = param_types(t_rhs); - - const auto lhssize = lhsparamtypes.size(); - const auto rhssize = rhsparamtypes.size(); - - constexpr auto boxed_type = user_type(); - constexpr auto boxed_pod_type = user_type(); - constexpr auto dynamic_type = user_type(); - - for (size_t i = 1; i < lhssize && i < rhssize; ++i) + if (dynamic_lhs->get_guard()) { - const Type_Info lt = type_info(lhsparamtypes[i]); - const Type_Info rt = type_info(rhsparamtypes[i]); - const std::string ln = dynamic_type_name(lhsparamtypes[i]); - const std::string rn = dynamic_type_name(rhsparamtypes[i]); - - if ( (lt.bare_equal(dynamic_type) || lt.is_undef()) - && (rt.bare_equal(dynamic_type) || rt.is_undef())) - { - - if (!ln.empty() && rn.empty()) { - return true; - } else if (ln.empty() && !rn.empty()) { - return false; - } else if (!ln.empty() && !rn.empty()) { - if (ln < rn) { - return true; - } else if (rn < ln) { - return false; - } - - // the remaining cases are handled by the is_const rules below - } - } - - if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) - { - continue; // The first two types are essentially the same, next iteration - } - - - // const is after non-const for the same type - if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) - { - return false; - } - - if (lt.bare_equal(rt) && !lt.is_const()) - { - return true; - } - - // boxed_values are sorted last - if (lt.bare_equal(boxed_type)) - { - return false; - } - - if (rt.bare_equal(boxed_type)) - { - return true; - } - - if (lt.bare_equal(boxed_pod_type)) - { - return false; - } - - if (rt.bare_equal(boxed_pod_type)) - { - return true; - } - - // otherwise, we want to sort by typeid - return lt < rt; - } - - // if everything else checks out, sort on guard - // - auto dynamic_lhs(std::dynamic_pointer_cast(t_lhs)); - auto dynamic_rhs(std::dynamic_pointer_cast(t_rhs)); - - if (dynamic_lhs && dynamic_rhs) { - if (dynamic_lhs->get_guard() && !dynamic_rhs->get_guard()) { - return true; - } else if (dynamic_rhs->get_guard()) { - return false; - } + return dynamic_rhs->get_guard() ? false : true; + } else { + return false; } + } + if (dynamic_lhs && !dynamic_rhs) + { return false; } - static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) noexcept - { - auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); - auto dynamic_rhs(std::dynamic_pointer_cast(rhs)); - - if (dynamic_lhs && dynamic_rhs) + if (!dynamic_lhs && dynamic_rhs) { - return params_less_than(dynamic_lhs, dynamic_rhs); - } else if (dynamic_lhs) { - return params_less_than(dynamic_lhs, rhs); - } else if (dynamic_rhs) { - return params_less_than(lhs, dynamic_rhs); - } else { - return params_less_than(lhs, rhs); + return true; } + + const auto &lhsparamtypes = lhs->get_param_types(); + const auto &rhsparamtypes = rhs->get_param_types(); + + const auto lhssize = lhsparamtypes.size(); + const auto rhssize = rhsparamtypes.size(); + + constexpr const auto boxed_type = user_type(); + constexpr const auto boxed_pod_type = user_type(); + + for (size_t i = 1; i < lhssize && i < rhssize; ++i) + { + const Type_Info < = lhsparamtypes[i]; + const Type_Info &rt = rhsparamtypes[i]; + + if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) + { + continue; // The first two types are essentially the same, next iteration + } + + // const is after non-const for the same type + if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) + { + return false; + } + + if (lt.bare_equal(rt) && !lt.is_const()) + { + return true; + } + + // boxed_values are sorted last + if (lt.bare_equal(boxed_type)) + { + return false; + } + + if (rt.bare_equal(boxed_type)) + { + return true; + } + + if (lt.bare_equal(boxed_pod_type)) + { + return false; + } + + if (rt.bare_equal(boxed_pod_type)) + { + return true; + } + + // otherwise, we want to sort by typeid + return lt < rt; + } + + return false; } diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 7c0364d8..d9e3a15a 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -39,7 +39,7 @@ namespace chaiscript /// 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_Function_Interface + class Dynamic_Object_Function final : public Proxy_Function_Base { public: Dynamic_Object_Function( @@ -71,17 +71,6 @@ namespace chaiscript Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; Dynamic_Object_Function(Dynamic_Object_Function &) = delete; - Param_Types get_dynamic_param_types() const noexcept override { - auto dynamic(std::dynamic_pointer_cast(m_func)); - - if (dynamic) { - return dynamic->get_dynamic_param_types(); - } else { - return Param_Types(get_param_types()); - } - } - - bool operator==(const Proxy_Function_Base &f) const noexcept override { if (const auto *df = dynamic_cast(&f)) @@ -184,7 +173,7 @@ namespace chaiscript * that is automatically guarded based on the first param based on the * param's type name */ - class Dynamic_Object_Constructor final : public Proxy_Function_Base, public Dynamic_Function_Interface + class Dynamic_Object_Constructor final : public Proxy_Function_Base { public: Dynamic_Object_Constructor( @@ -193,7 +182,6 @@ namespace chaiscript : 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 ); assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); } @@ -211,17 +199,6 @@ namespace chaiscript return std::vector(begin, end); } - Param_Types get_dynamic_param_types() const noexcept override { - auto dynamic(std::dynamic_pointer_cast(m_func)); - - if (dynamic) { - return dynamic->get_dynamic_param_types(); - } else { - return Param_Types(get_param_types()); - } - } - - bool operator==(const Proxy_Function_Base &f) const noexcept override { const Dynamic_Object_Constructor *dc = dynamic_cast(&f); diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 3fee032f..7f00f235 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -56,12 +56,6 @@ namespace chaiscript : m_has_types(false) {} - explicit Param_Types(const std::vector &t_types) - : m_types(build_param_types(t_types)), - m_has_types(false) - { - } - explicit Param_Types(std::vector> t_types) : m_types(std::move(t_types)), m_has_types(false) @@ -69,18 +63,6 @@ namespace chaiscript update_has_types(); } - static std::vector> build_param_types(const std::vector &t_types) - { - std::vector> retval; - std::transform(t_types.begin(), t_types.end(), std::back_inserter(retval), - [](const Type_Info &ti){ - return std::make_pair(std::string(), ti); - } - ); - - return retval; - } - void push_front(std::string t_name, Type_Info t_ti) { m_types.emplace(m_types.begin(), std::move(t_name), t_ti); @@ -362,16 +344,9 @@ namespace chaiscript namespace dispatch { - class Dynamic_Function_Interface - { - public: - virtual ~Dynamic_Function_Interface() {} - virtual Param_Types get_dynamic_param_types() const = 0; - }; - /// A Proxy_Function implementation that is not type safe, the called function /// is expecting a vector that it works with how it chooses. - class Dynamic_Proxy_Function : public Proxy_Function_Base, public Dynamic_Function_Interface + class Dynamic_Proxy_Function : public Proxy_Function_Base { public: Dynamic_Proxy_Function( @@ -426,9 +401,6 @@ namespace chaiscript } } - Param_Types get_dynamic_param_types() const override { - return m_param_types; - } protected: bool test_guard(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const @@ -971,9 +943,6 @@ namespace chaiscript std::vector> ordered_funcs; ordered_funcs.reserve(funcs.size()); - const constexpr auto boxed_type = user_type(); - const constexpr auto dynamic_type = user_type(); - for (const auto &func : funcs) { const auto arity = func->get_arity(); @@ -985,10 +954,7 @@ namespace chaiscript size_t numdiffs = 0; for (size_t i = 0; i < plist.size(); ++i) { - const auto &p_type = plist[i].get_type_info(); - const auto &f_type = func->get_param_types()[i+1]; - - if (!(f_type.bare_equal(boxed_type) && p_type.bare_equal(dynamic_type)) && !f_type.bare_equal(p_type)) + if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info())) { ++numdiffs; } diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 48e5b378..6e241572 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -321,8 +321,7 @@ TEST_CASE("Function ordering") chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser()); chai.eval("def test_fun(x) { return 3; }"); chai.eval("def test_fun(x) : x == \"hi\" { return 4; }"); - chai.eval("def test_fun(double d) { return 5; }"); - +// chai.eval("def test_fun(x) { return 5; }"); chai.add(chaiscript::fun(&function_ordering_test_one), "test_fun"); chai.add(chaiscript::fun(&function_ordering_test_two), "test_fun"); @@ -330,7 +329,6 @@ TEST_CASE("Function ordering") CHECK(chai.eval("auto i = 1; test_fun(i)") == 2); CHECK(chai.eval("test_fun(\"bob\")") == 3); CHECK(chai.eval("test_fun(\"hi\")") == 4); - CHECK(chai.eval("test_fun(5.0)") == 5); } From f462796ee5e0053f85feee7830b9bd924bd56301 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 21 Nov 2017 16:17:53 -0700 Subject: [PATCH 13/18] Add clone shortcircuit for strings --- include/chaiscript/language/chaiscript_eval.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 2c72dbe8..eae007b1 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -96,6 +96,8 @@ namespace chaiscript return Boxed_Number::clone(incoming); } else if (incoming.get_type_info().bare_equal_type_info(typeid(bool))) { return Boxed_Value(*static_cast(incoming.get_const_ptr())); + } else if (incoming.get_type_info().bare_equal_type_info(typeid(std::string))) { + return Boxed_Value(*static_cast(incoming.get_const_ptr())); } else { std::array params{std::move(incoming)}; return t_ss->call_function("clone", t_loc, Function_Params{params}, t_ss.conversions()); From b47fec2f7178d30f9c47060a195f972744a0f1ce Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 21 Nov 2017 16:37:18 -0700 Subject: [PATCH 14/18] Comment out clone_object tests from typed_function_ordering --- unittests/clone_object.chai | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unittests/clone_object.chai b/unittests/clone_object.chai index 04ad0be8..8864d0ce 100644 --- a/unittests/clone_object.chai +++ b/unittests/clone_object.chai @@ -1,3 +1,5 @@ + +/* global clone_count = 0; class Cloneable @@ -35,4 +37,5 @@ assert_equal(0, clone_count); var p = o; assert_equal(1, clone_count); +*/ From 48e5a46cbd5b2f4a8aa5fb604cb3bd3d027338f6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 23 Nov 2017 22:38:15 -0700 Subject: [PATCH 15/18] Move to QuickFlatMap from manual vector map thing --- .../chaiscript/dispatchkit/dispatchkit.hpp | 83 +++++-------------- include/chaiscript/utility/quick_flat_map.hpp | 62 ++++++++++++++ 2 files changed, 85 insertions(+), 60 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index f8bbf45f..7fac1721 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -36,6 +36,7 @@ #include "proxy_functions.hpp" #include "type_info.hpp" #include "short_alloc.hpp" +#include "../utility/quick_flat_map.hpp" namespace chaiscript { class Boxed_Number; @@ -388,7 +389,7 @@ namespace chaiscript using SmallVector = std::vector; - using Scope = SmallVector>; + using Scope = utility::QuickFlatMap; using StackData = SmallVector; using Stacks = SmallVector; using Call_Param_List = SmallVector; @@ -409,24 +410,13 @@ namespace chaiscript void push_stack() { stacks.emplace_back(1); -// stacks.emplace_back(StackData(1, Scope(scope_allocator), stack_data_allocator)); } void push_call_params() { call_params.emplace_back(); -// call_params.emplace_back(Call_Param_List(call_param_list_allocator)); } - //Scope::allocator_type::arena_type scope_allocator; - //StackData::allocator_type::arena_type stack_data_allocator; - //Stacks::allocator_type::arena_type stacks_allocator; - //Call_Param_List::allocator_type::arena_type call_param_list_allocator; - //Call_Params::allocator_type::arena_type call_params_allocator; - -// Stacks stacks = Stacks(stacks_allocator); -// Call_Params call_params = Call_Params(call_params_allocator); - Stacks stacks; Call_Params call_params; @@ -440,7 +430,7 @@ namespace chaiscript public: using Type_Name_Map = std::map; - using Scope = std::vector>; + using Scope = utility::QuickFlatMap; using StackData = Stack_Holder::StackData; struct State @@ -486,12 +476,7 @@ namespace chaiscript for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) { - auto itr = std::find_if(stack_elem->begin(), stack_elem->end(), - [&](const std::pair &o) { - return o.first == name; - }); - - if (itr != stack_elem->end()) + if (auto itr = stack_elem->find(name); itr != stack_elem->end()) { itr->second = std::move(obj); return; @@ -504,38 +489,32 @@ namespace chaiscript /// Adds a named object to the current scope /// \warning This version does not check the validity of the name /// it is meant for internal use only - Boxed_Value &add_get_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder) + Boxed_Value &add_get_object(std::string t_name, Boxed_Value obj, Stack_Holder &t_holder) { auto &stack_elem = get_stack_data(t_holder).back(); - if (std::any_of(stack_elem.begin(), stack_elem.end(), - [&](const std::pair &o) { - return o.first == t_name; - })) + if (auto result = stack_elem.insert(std::pair{std::move(t_name), std::move(obj)}); result.second) { - throw chaiscript::exception::name_conflict_error(t_name); + return result.first->second; + } else { + //insert failed + throw chaiscript::exception::name_conflict_error(result.first->first); } - - return stack_elem.emplace_back(t_name, std::move(obj)).second; } /// Adds a named object to the current scope /// \warning This version does not check the validity of the name /// it is meant for internal use only - void add_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder) + void add_object(std::string t_name, Boxed_Value obj, Stack_Holder &t_holder) { auto &stack_elem = get_stack_data(t_holder).back(); - if (std::any_of(stack_elem.begin(), stack_elem.end(), - [&](const std::pair &o) { - return o.first == t_name; - })) + if (auto result = stack_elem.insert(std::pair{std::move(t_name), std::move(obj)}); !result.second) { - throw chaiscript::exception::name_conflict_error(t_name); + //insert failed + throw chaiscript::exception::name_conflict_error(result.first->first); } - - stack_elem.emplace_back(t_name, std::move(obj)); } @@ -566,46 +545,30 @@ namespace chaiscript } /// Adds a new global (non-const) shared object, between all the threads - Boxed_Value add_global_no_throw(const Boxed_Value &obj, const std::string &name) + Boxed_Value add_global_no_throw(Boxed_Value obj, std::string name) { chaiscript::detail::threading::unique_lock l(m_mutex); - const auto itr = m_state.m_global_objects.find(name); - if (itr == m_state.m_global_objects.end()) - { - m_state.m_global_objects.insert(std::make_pair(name, obj)); - return obj; - } else { - return itr->second; - } + return m_state.m_global_objects.insert(std::pair{std::move(name), std::move(obj)}).first->second; } /// Adds a new global (non-const) shared object, between all the threads - void add_global(const Boxed_Value &obj, const std::string &name) + void add_global(Boxed_Value obj, std::string name) { chaiscript::detail::threading::unique_lock l(m_mutex); - if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) - { - throw chaiscript::exception::name_conflict_error(name); - } else { - m_state.m_global_objects.insert(std::make_pair(name, obj)); + if (auto result = m_state.m_global_objects.insert(std::pair{std::move(name), std::move(obj)}); !result.second) { + // insert failed + throw chaiscript::exception::name_conflict_error(result.first->first); } } /// Updates an existing global shared object or adds a new global shared object if not found - void set_global(const Boxed_Value &obj, const std::string &name) + void set_global(Boxed_Value obj, std::string name) { chaiscript::detail::threading::unique_lock l(m_mutex); - - const auto itr = m_state.m_global_objects.find(name); - if (itr != m_state.m_global_objects.end()) - { - itr->second.assign(obj); - } else { - m_state.m_global_objects.insert(std::make_pair(name, obj)); - } + m_state.m_global_objects.insert_or_assign(std::move(name), std::move(obj)); } /// Adds a new scope to the stack @@ -688,7 +651,7 @@ namespace chaiscript } else if ((loc & static_cast(Loc::is_local)) != 0u) { auto &stack = get_stack_data(t_holder); - return stack[stack.size() - 1 - ((loc & static_cast(Loc::stack_mask)) >> 16)][loc & static_cast(Loc::loc_mask)].second; + return stack[stack.size() - 1 - ((loc & static_cast(Loc::stack_mask)) >> 16)].at_index(loc & static_cast(Loc::loc_mask)); } // Is the value we are looking for a global or function? diff --git a/include/chaiscript/utility/quick_flat_map.hpp b/include/chaiscript/utility/quick_flat_map.hpp index 1d3be2bb..d19a2d19 100644 --- a/include/chaiscript/utility/quick_flat_map.hpp +++ b/include/chaiscript/utility/quick_flat_map.hpp @@ -35,6 +35,14 @@ namespace chaiscript::utility { return data.end(); } + auto &back() noexcept { + return data.back(); + } + + const auto &back() const noexcept { + return data.back(); + } + Value &operator[](const Key &s) { const auto itr = find(s); @@ -45,6 +53,27 @@ namespace chaiscript::utility { } } + Value &at_index(const std::size_t idx) noexcept + { + return data[idx].second; + } + + const Value &at_index(const std::size_t idx) const noexcept + { + return data[idx].second; + } + + bool empty() const noexcept + { + return data.empty(); + } + + template + void assign(Itr begin, Itr end) + { + data.assign(begin, end); + } + Value &at(const Key &s) { const auto itr = find(s); if (itr != data.end()) { @@ -54,6 +83,30 @@ namespace chaiscript::utility { } } + + template + auto insert_or_assign(Key &&key, M &&m) + { + if (auto itr = find(key); itr != data.end()) { + *itr = std::forward(m); + return std::pair{itr, false}; + } else { + return std::pair{data.emplace(itr, std::move(key), std::forward(m)), true}; + } + } + + + template + auto insert_or_assign(const Key &key, M &&m) + { + if (auto itr = find(key); itr != data.end()) { + *itr = std::forward(m); + return std::pair{itr, false}; + } else { + return std::pair{data.emplace(itr, key, std::forward(m)), true}; + } + } + const Value &at(const Key &s) const { const auto itr = find(s); if (itr != data.end()) { @@ -69,9 +122,18 @@ namespace chaiscript::utility { std::vector> data; + using value_type = std::pair; using iterator = typename decltype(data)::iterator; using const_iterator = typename decltype(data)::const_iterator; + std::pair insert( value_type&& value ) + { + if (const auto itr = find(value.first); itr != data.end()) { + return std::pair{itr, false}; + } else { + return std::pair{data.insert(itr, std::move(value)), true}; + } + } }; From db72ab626fa7945b248cde25b5ef3617300e9086 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 24 Nov 2017 22:20:52 -0700 Subject: [PATCH 16/18] Consolidate hand-rolled flat maps --- include/chaiscript/chaiscript_defines.hpp | 12 +++ .../chaiscript/dispatchkit/dispatchkit.hpp | 99 +++++-------------- include/chaiscript/utility/quick_flat_map.hpp | 46 +++++++-- 3 files changed, 74 insertions(+), 83 deletions(-) diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 6c8ee78d..f0599e23 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -212,6 +212,18 @@ namespace chaiscript { return final_value(t, base, exponent, neg_exponent); } + struct str_equal { + [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { + return t_lhs == t_rhs; + } + template + [[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { + return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); + } + struct is_transparent{}; + }; + + struct str_less { [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 7fac1721..34607a1d 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -389,7 +389,7 @@ namespace chaiscript using SmallVector = std::vector; - using Scope = utility::QuickFlatMap; + using Scope = utility::QuickFlatMap; using StackData = SmallVector; using Stacks = SmallVector; using Call_Param_List = SmallVector; @@ -430,14 +430,14 @@ namespace chaiscript public: using Type_Name_Map = std::map; - using Scope = utility::QuickFlatMap; + using Scope = utility::QuickFlatMap; using StackData = Stack_Holder::StackData; struct State { - std::vector>>> m_functions; - std::vector> m_function_objects; - std::vector> m_boxed_functions; + utility::QuickFlatMap>, str_equal> m_functions; + utility::QuickFlatMap m_function_objects; + utility::QuickFlatMap m_boxed_functions; std::map m_global_objects; Type_Name_Map m_types; }; @@ -745,9 +745,7 @@ namespace chaiscript const auto &funs = get_functions_int(); - auto itr = find_keyed_value(funs, t_name, t_hint); - - if (itr != funs.end()) + if (const auto itr = funs.find(t_name, t_hint); itr != funs.end()) { return std::make_pair(std::distance(funs.begin(), itr), itr->second); } else { @@ -771,9 +769,7 @@ namespace chaiscript { const auto &funs = get_boxed_functions_int(); - auto itr = find_keyed_value(funs, t_name, t_hint); - - if (itr != funs.end()) + if (const auto itr = funs.find(t_name, t_hint); itr != funs.end()) { return std::make_pair(std::distance(funs.begin(), itr), itr->second); } else { @@ -787,8 +783,7 @@ namespace chaiscript { chaiscript::detail::threading::shared_lock l(m_mutex); - const auto &functions = get_functions_int(); - return find_keyed_value(functions, name) != functions.end(); + return get_functions_int().count(name) > 0; } /// \returns All values in the local thread state in the parent scope, or if it doesn't exist, @@ -1246,32 +1241,32 @@ namespace chaiscript private: - const std::vector> &get_boxed_functions_int() const noexcept + const decltype(State::m_boxed_functions) &get_boxed_functions_int() const noexcept { return m_state.m_boxed_functions; } - std::vector> &get_boxed_functions_int() noexcept + decltype(State::m_boxed_functions) &get_boxed_functions_int() noexcept { return m_state.m_boxed_functions; } - const std::vector> &get_function_objects_int() const noexcept + const decltype(State::m_function_objects) &get_function_objects_int() const noexcept { return m_state.m_function_objects; } - std::vector> &get_function_objects_int() noexcept + decltype(State::m_function_objects) &get_function_objects_int() noexcept { return m_state.m_function_objects; } - const std::vector>>> &get_functions_int() const noexcept + const decltype(State::m_functions) &get_functions_int() const noexcept { return m_state.m_functions; } - std::vector>>> &get_functions_int() noexcept + decltype(State::m_functions) &get_functions_int() noexcept { return m_state.m_functions; } @@ -1360,63 +1355,17 @@ namespace chaiscript return false; } - - - template - static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value) - { - auto itr = find_keyed_value(t_c, t_key); - - if (itr == t_c.end()) { - t_c.reserve(t_c.size() + 1); // tightly control growth of memory usage here - t_c.emplace_back(t_key, std::forward(t_value)); - } else { - using value_type = typename Container::value_type; - *itr = value_type(t_key, std::forward(t_value)); - } - } - - template - static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key) noexcept - { - return std::find_if(t_c.begin(), t_c.end(), - [&t_key](const typename Container::value_type &o) { - return o.first == t_key; - }); - } - - template - static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key) noexcept - { - return std::find_if(t_c.begin(), t_c.end(), - [&t_key](const typename Container::value_type &o) { - return std::equal(o.first.begin(), o.first.end(), t_key.begin(), t_key.end()); - }); - } - - template - static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint) noexcept - { - if (t_c.size() > t_hint && t_c[t_hint].first == t_key) { - return std::next(t_c.begin(), static_cast::difference_type>(t_hint)); - } else { - return find_keyed_value(t_c, t_key); - } - } - - /// 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); - auto &funcs = get_functions_int(); - - auto itr = find_keyed_value(funcs, t_name); - Proxy_Function new_func = [&]() -> Proxy_Function { + auto &funcs = get_functions_int(); + auto itr = funcs.find(t_name); + if (itr != funcs.end()) { auto vec = *itr->second; @@ -1437,17 +1386,21 @@ namespace chaiscript // if the function is the only function but it also contains // arithmetic operators, we must wrap it in a dispatch function // to allow for automatic arithmetic type conversions - std::vector vec({t_f}); - funcs.emplace_back(t_name, std::make_shared>(vec)); + std::vector vec; + vec.push_back(t_f); + funcs.insert(std::pair{t_name, std::make_shared>(vec)}); return std::make_shared(std::move(vec)); } else { - funcs.emplace_back(t_name, std::make_shared>(std::initializer_list({t_f}))); + auto vec = std::make_shared>(); + vec->push_back(t_f); + funcs.insert(std::pair{t_name, vec}); return t_f; } }(); - add_keyed_value(get_boxed_functions_int(), t_name, const_var(new_func)); - add_keyed_value(get_function_objects_int(), t_name, std::move(new_func)); + + get_boxed_functions_int().insert_or_assign(t_name, const_var(new_func)); + get_function_objects_int().insert_or_assign(t_name, std::move(new_func)); } mutable chaiscript::detail::threading::shared_mutex m_mutex; diff --git a/include/chaiscript/utility/quick_flat_map.hpp b/include/chaiscript/utility/quick_flat_map.hpp index d19a2d19..35bc089d 100644 --- a/include/chaiscript/utility/quick_flat_map.hpp +++ b/include/chaiscript/utility/quick_flat_map.hpp @@ -3,15 +3,29 @@ namespace chaiscript::utility { - template + template> struct QuickFlatMap { - auto find(const Key &s) noexcept { - return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; }); + Comparator comparator; + + template + auto find(const Lookup &s) noexcept { + return std::find_if(std::begin(data), std::end(data), [&s, this](const auto &d) { return comparator(d.first, s); }); } - auto find(const Key &s) const noexcept { - return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; }); + template + auto find(const Lookup &s) const noexcept { + return std::find_if(std::cbegin(data), std::cend(data), [&s, this](const auto &d) { return comparator(d.first, s); }); + } + + template + auto find(const Lookup &s, const std::size_t t_hint) const noexcept { + if (data.size() > t_hint && comparator(data[t_hint].first, s)) { + const auto begin = std::cbegin(data); + return std::next(begin, static_cast>::difference_type>(t_hint)); + } else { + return find(s); + } } auto size() const noexcept { @@ -49,6 +63,7 @@ namespace chaiscript::utility { if (itr != data.end()) { return itr->second; } else { + grow(); return data.emplace_back(s, Value()).second; } } @@ -91,7 +106,8 @@ namespace chaiscript::utility { *itr = std::forward(m); return std::pair{itr, false}; } else { - return std::pair{data.emplace(itr, std::move(key), std::forward(m)), true}; + grow(); + return std::pair{data.emplace(data.end(), std::move(key), std::forward(m)), true}; } } @@ -100,10 +116,11 @@ namespace chaiscript::utility { auto insert_or_assign(const Key &key, M &&m) { if (auto itr = find(key); itr != data.end()) { - *itr = std::forward(m); + itr->second = std::forward(m); return std::pair{itr, false}; } else { - return std::pair{data.emplace(itr, key, std::forward(m)), true}; + grow(); + return std::pair{data.emplace(data.end(), key, std::forward(m)), true}; } } @@ -116,7 +133,8 @@ namespace chaiscript::utility { } } - size_t count(const Key &s) const noexcept { + template + size_t count(const Lookup &s) const noexcept { return (find(s) != data.end())?1:0; } @@ -131,10 +149,18 @@ namespace chaiscript::utility { if (const auto itr = find(value.first); itr != data.end()) { return std::pair{itr, false}; } else { - return std::pair{data.insert(itr, std::move(value)), true}; + grow(); + return std::pair{data.insert(data.end(), std::move(value)), true}; } } + void grow() { + if ((data.capacity() - data.size()) == 0) { + data.reserve(data.size() + 2); + } + } + + }; } From 6bfc130b737f8c6008f51ac55bc4bfb30b4803b2 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 16 Dec 2017 11:50:32 -0700 Subject: [PATCH 17/18] Fix pull from develop, fix gcc warnings --- CMakeLists.txt | 25 +++-------- include/chaiscript/chaiscript_defines.hpp | 43 +++++++++++++++++++ .../chaiscript/language/chaiscript_engine.hpp | 3 +- include/chaiscript/utility/json.hpp | 6 +-- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78dfc613..c7911466 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,6 @@ option(BUILD_SAMPLES "Build Samples Folder" FALSE) option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE) option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE) option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE) -option(BUILD_IN_CPP17_MODE "Build with C++17 flags" FALSE) mark_as_advanced(USE_STD_MAKE_SHARED) @@ -150,21 +149,7 @@ endif() if(CMAKE_COMPILER_IS_GNUCC) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - if(GCC_VERSION VERSION_LESS 4.9) - set(CPP14_FLAG "-std=c++1y") - else() - if (BUILD_IN_CPP17_MODE) - set(CPP14_FLAG "-std=c++1z") - else() - set(CPP14_FLAG "-std=c++14") - endif() - endif() -else() - if (BUILD_IN_CPP17_MODE) - set(CPP14_FLAG "-std=c++1z") - else() - set(CPP14_FLAG "-std=c++14") - endif() + set(CPP17_FLAG "-std=c++1z") endif() if(MSVC) @@ -188,7 +173,7 @@ if(MSVC) # how to workaround or fix the error. So I'm disabling it globally. add_definitions(/wd4503) else() - add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic ${CPP14_FLAG}) + add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic ${CPP17_FLAG}) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template -Wno-undef ) @@ -206,12 +191,12 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if(USE_LIBCXX) add_definitions(-stdlib=libc++) - set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG} -stdlib=libc++") + set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP17_FLAG} -stdlib=libc++") else() - set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}") + set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP17_FLAG}") endif() elseif(CMAKE_COMPILER_IS_GNUCC) - set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}") + set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP17_FLAG}") endif() # limitations in MinGW require us to make an optimized build diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 1fe3a512..7bac2681 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -168,6 +168,49 @@ namespace chaiscript { } + template + [[nodiscard]] auto parse_num(const std::string_view &t_str) noexcept + -> typename std::enable_if::value, T>::type + { + T t = 0; + T base = 0; + T decimal_place = 0; + bool exponent = false; + bool neg_exponent = false; + + const auto final_value = [](const T val, const T baseval, const bool hasexp, const bool negexp) -> T { + if (!hasexp) { + return val; + } else { + return baseval * std::pow(T(10), val*T(negexp?-1:1)); + } + }; + + for (const auto c : t_str) { + if (c == '.') { + decimal_place = 10; + } else if (c == 'e' || c == 'E') { + exponent = true; + decimal_place = 0; + base = t; + t = 0; + } else if (c == '-' && exponent) { + neg_exponent = true; + } else if (c == '+' && exponent) { + neg_exponent = false; + } else if (c < '0' || c > '9') { + return final_value(t, base, exponent, neg_exponent); + } else if (decimal_place < T(10)) { + t *= T(10); + t += T(c - '0'); + } else { + t += (T(c - '0') / (T(decimal_place))); + decimal_place *= 10; + } + } + + return final_value(t, base, exponent, neg_exponent); + } template auto parse_num(const char *t_str) -> typename std::enable_if::value, T>::type diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 3dce4a76..aa34e505 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -200,7 +200,8 @@ namespace chaiscript m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global"); - m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([](Namespace& space) {}, t_namespace_name); import(t_namespace_name); }), "namespace"); + // why this unused parameter to Namesapce? + m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([](Namespace& ) {}, t_namespace_name); import(t_namespace_name); }), "namespace"); m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import"); } diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index d227d85e..f5583033 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -50,11 +50,11 @@ class JSON private: - using Data = std::variant, std::vector, std::string, double, int64_t, bool>; + using Data = std::variant, std::vector, std::string, double, int64_t, bool>; struct Internal { - Internal(nullptr_t) : d(nullptr) { } + Internal(std::nullptr_t) : d(nullptr) { } Internal() : d(nullptr) { } Internal(Class c) : d(make_type(c)) { } template Internal(T t) : d(std::move(t)) { } @@ -96,7 +96,7 @@ class JSON template auto &get_set_type() { set_type(ClassValue); - return std::get(ClassValue)>(d); + return (std::get(ClassValue)>(d)); } auto &Map() { From c902771f161ca5d80828803635eb8f9e35ef7665 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 19 Feb 2018 16:36:08 -0700 Subject: [PATCH 18/18] Use catch's test parser --- CMakeLists.txt | 34 ++-------------------------------- cmake/CatchAddTests.cmake | 10 ++++------ 2 files changed, 6 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 74f7e614..af4fd810 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,7 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile) include(CTest) include(CPack) +include(cmake/Catch.cmake) if(NOT MINGW) find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib) @@ -337,37 +338,6 @@ endif() if(BUILD_TESTING) - # Add catch tests macro - macro(ADD_CATCH_TESTS executable) - if (MSVC) - file(TO_NATIVE_PATH "${QT_LIBRARY_DIR}" QT_LIB_PATH) - set(NEWPATH "${QT_LIB_PATH};$ENV{PATH}") - else() - set(NEWPATH $ENV{PATH}) - endif() - - get_target_property(target_files ${executable} SOURCES) - - foreach(source ${target_files}) - if(NOT "${source}" MATCHES "/moc_.*cxx") - string(REGEX MATCH .*cpp source "${source}") - if(source) - file(READ "${source}" contents) - string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents}) - foreach(hit ${found_tests}) - string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit}) - add_test(compiled.${test_name} "${executable}" ${test_name}) - set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}") - endforeach() - endif() - endif() - endforeach() - endmacro() - - - - - option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE) add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }") @@ -425,7 +395,7 @@ if(BUILD_TESTING) if(NOT UNIT_TEST_LIGHT) add_executable(compiled_tests unittests/compiled_tests.cpp) target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS}) - ADD_CATCH_TESTS(compiled_tests) + catch_discover_tests(compiled_tests) add_executable(static_chaiscript_test unittests/static_chaiscript.cpp) target_link_libraries(static_chaiscript_test ${LIBS}) diff --git a/cmake/CatchAddTests.cmake b/cmake/CatchAddTests.cmake index c68921e4..205e2b87 100644 --- a/cmake/CatchAddTests.cmake +++ b/cmake/CatchAddTests.cmake @@ -50,23 +50,21 @@ string(REPLACE "\n" ";" output "${output}") # Parse output foreach(line ${output}) - # Test name; strip spaces to get just the name... - string(REGEX REPLACE " +" "" test "${line}") # ...and add to script add_command(add_test - "${prefix}${test}${suffix}" + "${prefix}${line}${suffix}" ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" - "${test}" + "${line}" ${extra_args} ) add_command(set_tests_properties - "${prefix}${test}${suffix}" + "${prefix}${line}${suffix}" PROPERTIES WORKING_DIRECTORY "${TEST_WORKING_DIR}" ${properties} ) - list(APPEND tests "${prefix}${test}${suffix}") + list(APPEND tests "${prefix}${line}${suffix}") endforeach() # Create a list of all discovered tests, which users may use to e.g. set