diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index cb80acf..3b9478d 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -793,6 +793,42 @@ namespace chaiscript return m_conversions; } + bool is_attribute_call(const std::vector &t_funs, const std::vector &t_params, + bool t_has_params) const + { + if (!t_has_params || t_params.empty()) { + return false; + } + + for (const auto &fun : t_funs) { + if (fun->is_attribute_function()) { + if (fun->compare_first_type(t_params[0], m_conversions)) { + return true; + } + } + } + + return false; + } + + Boxed_Value call_member(const std::string &t_name, const std::vector ¶ms, bool t_has_params) const + { + auto funs = get_function(t_name); + + if (is_attribute_call(funs, params, t_has_params)) { + std::vector attr_params{params[0]}; + std::vector remaining_params{params.begin() + 1, params.end()}; + Boxed_Value bv = dispatch::dispatch(funs, attr_params, m_conversions); + if (!remaining_params.empty() || bv.get_type_info().bare_equal(user_type())) { + return (*boxed_cast(bv))(remaining_params, m_conversions); + } else { + return bv; + } + } else { + return dispatch::dispatch(funs, params, m_conversions); + } + } + Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const { Boxed_Value bv = dispatch::dispatch(get_function(t_name), params, m_conversions); diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 67c9543..b9ddda1 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -44,9 +44,11 @@ namespace chaiscript public: Dynamic_Object_Function( std::string t_type_name, - const Proxy_Function &t_func) + const Proxy_Function &t_func, + bool t_is_attribute = false) : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()), - m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type()) + m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type()), + m_is_attribute(t_is_attribute) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); @@ -55,9 +57,11 @@ namespace chaiscript Dynamic_Object_Function( std::string t_type_name, const Proxy_Function &t_func, - const Type_Info &t_ti) + const Type_Info &t_ti, + bool t_is_attribute = false) : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()), - m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(t_ti.is_undef()?nullptr:new Type_Info(t_ti)), m_doti(user_type()) + m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(t_ti.is_undef()?nullptr:new Type_Info(t_ti)), m_doti(user_type()), + m_is_attribute(t_is_attribute) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); @@ -78,6 +82,8 @@ namespace chaiscript } } + virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return m_is_attribute; } + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) @@ -164,6 +170,7 @@ namespace chaiscript Proxy_Function m_func; std::unique_ptr m_ti; const Type_Info m_doti; + bool m_is_attribute; }; diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index c8dfc5b..536eb9c 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -162,6 +162,8 @@ namespace chaiscript virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const = 0; + virtual bool is_attribute_function() const { return false; } + bool has_arithmetic_param() const { return m_has_arithmetic_param; @@ -219,6 +221,12 @@ namespace chaiscript return false; } } + + virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const + { + return compare_type_to_param(m_types[1], bv, t_conversions); + } + protected: virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const = 0; @@ -236,10 +244,6 @@ namespace chaiscript } - virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const - { - return compare_type_to_param(m_types[1], bv, t_conversions); - } static bool compare_types(const std::vector &tis, const std::vector &bvs) { @@ -654,6 +658,8 @@ namespace chaiscript virtual ~Attribute_Access() {} + virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return true; } + virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE { const Attribute_Access * aa diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 59e09ba..a8440df 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -704,7 +704,10 @@ namespace chaiscript for (size_t i = 2; i < this->children.size(); i+=2) { std::vector params{retval}; + bool has_function_params = false; + if (this->children[i]->children.size() > 1) { + has_function_params = true; for (const auto &child : this->children[i]->children[1]->children) { params.push_back(child->eval(t_ss)); } @@ -723,7 +726,7 @@ namespace chaiscript try { chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); - retval = t_ss.call_function(fun_name, std::move(params)); + retval = t_ss.call_member(fun_name, std::move(params), has_function_params); } catch(const exception::dispatch_error &e){ if (e.functions.empty()) @@ -1534,7 +1537,9 @@ namespace chaiscript std::placeholders::_1, this->children[static_cast(1 + class_offset)]->text )) - ) + ), + true + ), this->children[static_cast(1 + class_offset)]->text); } diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 73a33e2..c77e61e 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1319,9 +1319,10 @@ namespace chaiscript } } while (Char(',')); } - build_match(std::make_shared(), prev_stack_top); } + build_match(std::make_shared(), prev_stack_top); + SkipWS(true); return retval; diff --git a/unittests/function_attributes.chai b/unittests/function_attributes.chai index a346fb1..8f9dbbd 100644 --- a/unittests/function_attributes.chai +++ b/unittests/function_attributes.chai @@ -18,3 +18,6 @@ assert_true(func_member(t0)(2) == 6) assert_true((func_member(t0))(2) == 6) assert_true(t0.func_member(2) == 6) +t0.func_member = fun() { 12; }; + +assert_true(t0.func_member() == 12);