Merge remote-tracking branch 'origin/method_missing' into develop

This commit is contained in:
Jason Turner 2015-04-23 09:13:28 -06:00
commit 606c1d9d00
5 changed files with 135 additions and 16 deletions

View File

@ -431,9 +431,18 @@ namespace chaiscript
m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
m->add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object");
m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
m->add(fun(&dispatch::Dynamic_Object::get_attr), "get_attr");
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
m->eval("def Dynamic_Object::clone() { auto &new_o = Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");

View File

@ -813,19 +813,65 @@ namespace chaiscript
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);
const auto do_attribute_call =
[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> 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<dispatch::Proxy_Function_Base>())) {
return (*boxed_cast<const dispatch::Proxy_Function_Base *>(bv))(remaining_params, l_conversions);
} else {
return bv;
}
};
if (is_attribute_call(funs, params, t_has_params)) {
std::vector<Boxed_Value> attr_params{params[0]};
std::vector<Boxed_Value> 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<dispatch::Proxy_Function_Base>())) {
return (*boxed_cast<const dispatch::Proxy_Function_Base *>(bv))(remaining_params, m_conversions);
} else {
return bv;
}
return do_attribute_call(1, params, funs, m_conversions);
} else {
return dispatch::dispatch(funs, params, m_conversions);
std::exception_ptr except;
if (!funs.empty()) {
try {
return dispatch::dispatch(funs, params, m_conversions);
} catch(chaiscript::exception::dispatch_error&) {
except = std::current_exception();
}
}
// If we get here we know that either there was no method with that name,
// or there was no matching method
const auto functions = get_function("method_missing");
const bool is_no_param = [&]()->bool{
for (const auto &f : functions) {
if (f->get_arity() != 2) {
return false;
}
}
return true;
}();
if (!functions.empty()) {
std::vector<Boxed_Value> tmp_params(params);
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
if (is_no_param) {
return do_attribute_call(2, tmp_params, functions, m_conversions);
} else {
return dispatch::dispatch(functions, tmp_params, m_conversions);
}
}
// If we get all the way down here we know there was no "method_missing"
// method at all.
if (except) {
std::rethrow_exception(except);
} else {
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.begin(), funs.end()));
}
}
}

View File

@ -40,16 +40,42 @@ namespace chaiscript
{
}
Dynamic_Object() : m_type_name("")
{
}
std::string get_type_name() const
{
return m_type_name;
}
Boxed_Value get_attr(const std::string &t_attr_name)
const Boxed_Value &get_attr(const std::string &t_attr_name) const
{
auto a = m_attrs.find(t_attr_name);
if (a != m_attrs.end()) {
return a->second;
} else {
throw std::range_error("Attr not found '" + t_attr_name + "' and cannot be added to const obj");
}
}
Boxed_Value &get_attr(const std::string &t_attr_name)
{
return m_attrs[t_attr_name];
}
Boxed_Value &method_missing(const std::string &t_method_name)
{
return get_attr(t_method_name);
}
const Boxed_Value &method_missing(const std::string &t_method_name) const
{
return get_attr(t_method_name);
}
std::map<std::string, Boxed_Value> get_attrs() const
{
return m_attrs;

View File

@ -726,6 +726,7 @@ namespace chaiscript
try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
t_ss.add_object("this", retval);
retval = t_ss.call_member(fun_name, std::move(params), has_function_params);
}
catch(const exception::dispatch_error &e){
@ -1533,10 +1534,11 @@ namespace chaiscript
t_ss.add(
std::make_shared<dispatch::detail::Dynamic_Object_Function>(
std::move(class_name),
fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::Dynamic_Object::get_attr,
std::placeholders::_1,
this->children[static_cast<size_t>(1 + class_offset)]->text
))
fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(
std::bind(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr),
std::placeholders::_1,
this->children[static_cast<size_t>(1 + class_offset)]->text
))
),
true

View File

@ -0,0 +1,36 @@
class MyClass {
def MyClass()
{
}
def mult(double d) {
this.y * d
}
};
var o = MyClass();
o.f = fun(x,y) { x * y; }
assert_true(o.f(3,4) == 12);
o.f2 = fun(x) { x * 3; }
assert_true(o.f2(3) == 9);
o.y = 15;
o.f3 = fun(x) { x * this.y; }
assert_true(o.f3(4) == 60);
assert_true(o.mult(3.0) == 45.0);
def method_missing(int i, string method_name, x, y) {
"method_missing called : " + to_string(i) + "." + method_name + "(" + to_string(x) + ", " + to_string(y) + ")";
}
assert_true(5.bob(3,4) == "method_missing called : 5.bob(3, 4)" )
var o2 = Dynamic_Object();
o2.a = 15
assert_true(o2.a == 15)
assert_true(o2["a"] == 15)