Merge remote-tracking branch 'origin/method_missing' into develop
This commit is contained in:
commit
606c1d9d00
@ -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; }");
|
||||
|
||||
|
@ -813,19 +813,65 @@ namespace chaiscript
|
||||
|
||||
Boxed_Value call_member(const std::string &t_name, const std::vector<Boxed_Value> ¶ms, 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
36
unittests/dynamic_object_dynamic_attrs.chai
Normal file
36
unittests/dynamic_object_dynamic_attrs.chai
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user