From c9625b09b0e0b0ff89ef452dc103914f95f125fb Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 26 Aug 2015 18:41:46 -0600 Subject: [PATCH] Fix magic 'this' values --- .../chaiscript/dispatchkit/dispatchkit.hpp | 62 +++++++++++++------ .../chaiscript/language/chaiscript_eval.hpp | 40 +++++++----- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 43cb7b1..4557870 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -482,24 +482,31 @@ namespace chaiscript add_object(name, std::move(obj)); } + /// Adds a named object to the current scope + /// \warning This version does not check the validity of the name + /// it is meant for internal use only + void add_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder) + { + auto &stack_elem = get_stack_data(t_holder).back(); + + if (std::any_of(stack_elem.begin(), stack_elem.end(), + [&](const std::pair &o) { + return o.first == t_name; + })) + { + throw chaiscript::exception::name_conflict_error(t_name); + } + + get_stack_data(t_holder).back().emplace_back(t_name, std::move(obj)); + } + /// Adds a named object to the current scope /// \warning This version does not check the validity of the name /// it is meant for internal use only void add_object(const std::string &name, Boxed_Value obj) { - auto &stack_elem = get_stack_data().back(); - - if (std::any_of(stack_elem.begin(), stack_elem.end(), - [&](const std::pair &o) { - return o.first == name; - })) - { - throw chaiscript::exception::name_conflict_error(name); - } - - get_stack_data().back().emplace_back(name, std::move(obj)); - + add_object(name, std::move(obj), get_stack_holder()); } /// Adds a new global shared object, between all the threads @@ -896,7 +903,7 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4715) #endif - Boxed_Value call_member(const std::string &t_name, const std::vector ¶ms, bool t_has_params) const + Boxed_Value call_member(const std::string &t_name, const std::vector ¶ms, bool t_has_params) { const auto funs = get_function(t_name); @@ -904,17 +911,31 @@ namespace chaiscript [this](int l_num_params, const std::vector &l_params, const std::vector &l_funs, const Type_Conversions &l_conversions)->Boxed_Value { std::vector attr_params{l_params.begin(), l_params.begin() + l_num_params}; - std::vector remaining_params{l_params.begin() + l_num_params, l_params.end()}; Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); - if (!remaining_params.empty() || bv.get_type_info().bare_equal(user_type())) { + if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type())) { + struct This_Foist { + This_Foist(Dispatch_Engine &e, const Boxed_Value &t_bv) : m_e(e) { + m_e.get().new_scope(); + m_e.get().add_object("__this", t_bv); + } + + ~This_Foist() { + m_e.get().pop_scope(); + } + + std::reference_wrapper m_e; + }; + + This_Foist fi(*this, l_params.front()); + auto func = boxed_cast>(bv); try { - return (*func)(remaining_params, l_conversions); + return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions); } catch (const chaiscript::exception::bad_boxed_cast &) { } catch (const chaiscript::exception::arity_error &) { } catch (const chaiscript::exception::guard_error &) { } - throw chaiscript::exception::dispatch_error(remaining_params, std::vector{func}); + throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector{func}); } else { return bv; } @@ -1205,7 +1226,6 @@ namespace chaiscript return *m_stack_holder; } - private: /// Returns the current stack /// make const/non const versions const StackData &get_stack_data() const @@ -1223,6 +1243,8 @@ namespace chaiscript return m_stack_holder->stacks.back(); } + private: + const std::map &get_boxed_functions_int() const { return m_state.m_boxed_functions; @@ -1440,6 +1462,10 @@ namespace chaiscript return m_stack_holder.get(); } + void add_object(const std::string &t_name, Boxed_Value obj) const { + m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get()); + } + private: std::reference_wrapper m_engine; std::reference_wrapper m_stack_holder; diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 5581fc1..53d8e41 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -44,19 +44,32 @@ namespace chaiscript namespace detail { /// Helper function that will set up the scope around a function call, including handling the named function parameters - static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector &t_param_names, const std::vector &t_vals, const std::map &t_locals=std::map()) { + static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector &t_param_names, const std::vector &t_vals, const std::map *t_locals=nullptr) { chaiscript::detail::Dispatch_State state(t_ss); + const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{ + auto &stack = t_ss.get_stack_data(state.stack_holder()).back(); + if (!stack.empty() && stack.back().first == "__this") { + return &stack.back().second; + } else if (!t_vals.empty()) { + return &t_vals[0]; + } else { + return nullptr; + } + }(); + chaiscript::eval::detail::Stack_Push_Pop tpp(state); - if (!t_vals.empty()) t_ss.add_object("this", t_vals[0]); + if (thisobj) state.add_object("this", *thisobj); chaiscript::eval::detail::Scope_Push_Pop spp(state); - for (const auto &local : t_locals) { - t_ss.add_object(local.first, local.second); + if (t_locals) { + for (const auto &local : *t_locals) { + state.add_object(local.first, local.second); + } } for (size_t i = 0; i < t_param_names.size(); ++i) { - t_ss.add_object(t_param_names[i], t_vals[i]); + state.add_object(t_param_names[i], t_vals[i]); } try { @@ -495,7 +508,7 @@ namespace chaiscript try { Boxed_Value bv; - t_ss->add_object(idname, bv); + t_ss.add_object(idname, bv); return bv; } catch (const exception::reserved_word_error &) { @@ -578,7 +591,6 @@ namespace chaiscript fpp.save_params(params); try { -// t_ss->add_object("this", retval); retval = t_ss->call_member(m_fun_name, std::move(params), has_function_params); } catch(const exception::dispatch_error &e){ @@ -679,7 +691,7 @@ namespace chaiscript dispatch::make_dynamic_proxy_function( [engine, lambda_node, param_names, captures](const std::vector &t_params) { - return detail::eval_function(engine, lambda_node, param_names, t_params, captures); + return detail::eval_function(engine, lambda_node, param_names, t_params, &captures); }, static_cast(numparams), lambda_node, param_types ) @@ -810,7 +822,7 @@ namespace chaiscript /// \todo do this better // put class name in current scope so it can be looked up by the attrs and methods - t_ss->add_object("_current_class_name", const_var(children[0]->text)); + t_ss.add_object("_current_class_name", const_var(children[0]->text)); children[1]->eval(t_ss); @@ -1082,7 +1094,7 @@ namespace chaiscript virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ try { Boxed_Value bv; - t_ss->add_object(this->children[0]->text, bv); + t_ss.add_object(this->children[0]->text, bv); return bv; } catch (const exception::reserved_word_error &) { @@ -1230,7 +1242,7 @@ namespace chaiscript std::vector>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)} ).match(std::vector{t_except}, t_ss->conversions())) { - t_ss->add_object(name, t_except); + t_ss.add_object(name, t_except); if (catch_block->children.size() == 2) { //Variable capture, no guards @@ -1367,7 +1379,7 @@ namespace chaiscript if (guardnode) { guard = dispatch::make_dynamic_proxy_function( [engine, t_param_names, guardnode](const std::vector &t_params) { - return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params, std::map()); + return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params); }, static_cast(numparams), guardnode); } @@ -1384,7 +1396,7 @@ namespace chaiscript std::make_shared(class_name, dispatch::make_dynamic_proxy_function( [engine, t_param_names, node](const std::vector &t_params) { - return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map()); + return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params); }, static_cast(numparams), node, param_types, l_annotation, guard ) @@ -1400,7 +1412,7 @@ namespace chaiscript t_ss->add(std::make_shared(class_name, dispatch::make_dynamic_proxy_function( [engine, t_param_names, node](const std::vector &t_params) { - return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map()); + return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params); }, static_cast(numparams), node, param_types, l_annotation, guard), type), function_name);