Merge branch 'develop' of github.com:ChaiScript/ChaiScript into typed_function_ordering

This commit is contained in:
Jason Turner 2015-08-26 18:58:34 -06:00
commit 2d2251c1da
3 changed files with 80 additions and 36 deletions

View File

@ -482,24 +482,31 @@ namespace chaiscript
add_object(name, std::move(obj)); 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<std::string, Boxed_Value> &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 /// Adds a named object to the current scope
/// \warning This version does not check the validity of the name /// \warning This version does not check the validity of the name
/// it is meant for internal use only /// it is meant for internal use only
void add_object(const std::string &name, Boxed_Value obj) void add_object(const std::string &name, Boxed_Value obj)
{ {
auto &stack_elem = get_stack_data().back(); add_object(name, std::move(obj), get_stack_holder());
if (std::any_of(stack_elem.begin(), stack_elem.end(),
[&](const std::pair<std::string, Boxed_Value> &o) {
return o.first == name;
}))
{
throw chaiscript::exception::name_conflict_error(name);
}
get_stack_data().back().emplace_back(name, std::move(obj));
} }
/// Adds a new global shared object, between all the threads /// Adds a new global shared object, between all the threads
@ -895,7 +902,7 @@ namespace chaiscript
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4715) #pragma warning(disable : 4715)
#endif #endif
Boxed_Value call_member(const std::string &t_name, const std::vector<Boxed_Value> &params, bool t_has_params) const Boxed_Value call_member(const std::string &t_name, const std::vector<Boxed_Value> &params, bool t_has_params)
{ {
const auto funs = get_function(t_name); const auto funs = get_function(t_name);
@ -903,17 +910,31 @@ namespace chaiscript
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions &l_conversions)->Boxed_Value [this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions &l_conversions)->Boxed_Value
{ {
std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params}; std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params};
std::vector<Boxed_Value> remaining_params{l_params.begin() + l_num_params, l_params.end()};
Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions);
if (!remaining_params.empty() || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) { if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
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<Dispatch_Engine> m_e;
};
This_Foist fi(*this, l_params.front());
auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv); auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv);
try { 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::bad_boxed_cast &) {
} catch (const chaiscript::exception::arity_error &) { } catch (const chaiscript::exception::arity_error &) {
} catch (const chaiscript::exception::guard_error &) { } catch (const chaiscript::exception::guard_error &) {
} }
throw chaiscript::exception::dispatch_error(remaining_params, std::vector<Const_Proxy_Function>{func}); throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector<Const_Proxy_Function>{func});
} else { } else {
return bv; return bv;
} }
@ -1212,7 +1233,6 @@ namespace chaiscript
return *m_stack_holder; return *m_stack_holder;
} }
private:
/// Returns the current stack /// Returns the current stack
/// make const/non const versions /// make const/non const versions
const StackData &get_stack_data() const const StackData &get_stack_data() const
@ -1230,6 +1250,8 @@ namespace chaiscript
return m_stack_holder->stacks.back(); return m_stack_holder->stacks.back();
} }
private:
const std::map<std::string, Boxed_Value> &get_boxed_functions_int() const const std::map<std::string, Boxed_Value> &get_boxed_functions_int() const
{ {
return m_state.m_boxed_functions; return m_state.m_boxed_functions;
@ -1516,6 +1538,10 @@ namespace chaiscript
return m_stack_holder.get(); 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: private:
std::reference_wrapper<Dispatch_Engine> m_engine; std::reference_wrapper<Dispatch_Engine> m_engine;
std::reference_wrapper<Stack_Holder> m_stack_holder; std::reference_wrapper<Stack_Holder> m_stack_holder;

View File

@ -44,16 +44,32 @@ namespace chaiscript
namespace detail namespace detail
{ {
/// Helper function that will set up the scope around a function call, including handling the named function parameters /// 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<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> &t_locals=std::map<std::string, Boxed_Value>()) { static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr) {
chaiscript::detail::Dispatch_State state(t_ss); 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 (thisobj) state.add_object("this", *thisobj);
chaiscript::eval::detail::Scope_Push_Pop spp(state); chaiscript::eval::detail::Scope_Push_Pop spp(state);
for (const auto &local : t_locals) { if (t_locals) {
t_ss.add_object(local.first, local.second); for (const auto &local : *t_locals) {
state.add_object(local.first, local.second);
}
} }
for (size_t i = 0; i < t_param_names.size(); ++i) { for (size_t i = 0; i < t_param_names.size(); ++i) {
t_ss.add_object(t_param_names[i], t_vals[i]); state.add_object(t_param_names[i], t_vals[i]);
} }
try { try {
@ -101,7 +117,6 @@ namespace chaiscript
} else { } else {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
fpp.save_params({t_lhs, t_rhs}); fpp.save_params({t_lhs, t_rhs});
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
return t_ss->call_function(t_oper_string, t_lhs, t_rhs); return t_ss->call_function(t_oper_string, t_lhs, t_rhs);
} }
} }
@ -236,7 +251,6 @@ namespace chaiscript
Boxed_Value fn(this->children[0]->eval(t_ss)); Boxed_Value fn(this->children[0]->eval(t_ss));
try { try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
return (*t_ss->boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss->conversions()); return (*t_ss->boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss->conversions());
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
@ -494,7 +508,7 @@ namespace chaiscript
try { try {
Boxed_Value bv; Boxed_Value bv;
t_ss->add_object(idname, bv); t_ss.add_object(idname, bv);
return bv; return bv;
} }
catch (const exception::reserved_word_error &) { catch (const exception::reserved_word_error &) {
@ -525,7 +539,6 @@ namespace chaiscript
std::vector<Boxed_Value> params{children[0]->eval(t_ss), children[1]->eval(t_ss)}; std::vector<Boxed_Value> params{children[0]->eval(t_ss), children[1]->eval(t_ss)};
try { try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
fpp.save_params(params); fpp.save_params(params);
return t_ss->call_function("[]", params); return t_ss->call_function("[]", params);
} }
@ -578,8 +591,6 @@ namespace chaiscript
fpp.save_params(params); fpp.save_params(params);
try { try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
t_ss->add_object("this", retval);
retval = t_ss->call_member(m_fun_name, std::move(params), has_function_params); retval = t_ss->call_member(m_fun_name, std::move(params), has_function_params);
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
@ -680,7 +691,7 @@ namespace chaiscript
dispatch::make_dynamic_proxy_function( dispatch::make_dynamic_proxy_function(
[engine, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params) [engine, lambda_node, param_names, captures](const std::vector<Boxed_Value> &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<int>(numparams), lambda_node, param_types static_cast<int>(numparams), lambda_node, param_types
) )
@ -811,7 +822,7 @@ namespace chaiscript
/// \todo do this better /// \todo do this better
// put class name in current scope so it can be looked up by the attrs and methods // 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); children[1]->eval(t_ss);
@ -1083,7 +1094,7 @@ namespace chaiscript
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
try { try {
Boxed_Value bv; Boxed_Value bv;
t_ss->add_object(this->children[0]->text, bv); t_ss.add_object(this->children[0]->text, bv);
return bv; return bv;
} }
catch (const exception::reserved_word_error &) { catch (const exception::reserved_word_error &) {
@ -1112,7 +1123,6 @@ namespace chaiscript
return Boxed_Number::do_oper(m_oper, bv); return Boxed_Number::do_oper(m_oper, bv);
} else { } else {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
fpp.save_params({bv}); fpp.save_params({bv});
return t_ss->call_function(children[0]->text, std::move(bv)); return t_ss->call_function(children[0]->text, std::move(bv));
} }
@ -1232,7 +1242,7 @@ namespace chaiscript
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)} std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)}
).match(std::vector<Boxed_Value>{t_except}, t_ss->conversions())) ).match(std::vector<Boxed_Value>{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) { if (catch_block->children.size() == 2) {
//Variable capture, no guards //Variable capture, no guards
@ -1369,7 +1379,7 @@ namespace chaiscript
if (guardnode) { if (guardnode) {
guard = dispatch::make_dynamic_proxy_function( guard = dispatch::make_dynamic_proxy_function(
[engine, t_param_names, guardnode](const std::vector<Boxed_Value> &t_params) { [engine, t_param_names, guardnode](const std::vector<Boxed_Value> &t_params) {
return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params, std::map<std::string, Boxed_Value>()); return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params);
}, },
static_cast<int>(numparams), guardnode); static_cast<int>(numparams), guardnode);
} }
@ -1386,7 +1396,7 @@ namespace chaiscript
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name, std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
dispatch::make_dynamic_proxy_function( dispatch::make_dynamic_proxy_function(
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) { [engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map<std::string, Boxed_Value>()); return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
}, },
static_cast<int>(numparams), node, param_types, l_annotation, guard static_cast<int>(numparams), node, param_types, l_annotation, guard
) )
@ -1402,7 +1412,7 @@ namespace chaiscript
t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name, t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
dispatch::make_dynamic_proxy_function( dispatch::make_dynamic_proxy_function(
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) { [engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map<std::string, Boxed_Value>()); return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
}, },
static_cast<int>(numparams), node, param_types, l_annotation, guard), type), static_cast<int>(numparams), node, param_types, l_annotation, guard), type),
function_name); function_name);

View File

@ -778,4 +778,12 @@ TEST_CASE("Variable Scope When Calling From C++")
CHECK_THROWS(func()); CHECK_THROWS(func());
} }
TEST_CASE("Variable Scope When Calling From C++ 2")
{
chaiscript::ChaiScript chai;
chai.eval("var obj = 2;");
auto func = chai.eval<std::function<void()>>("fun(){ return obj; }");
CHECK_THROWS(func());
}