Merge branch 'fix_attr_function_calls' into develop

Conflicts:
	src/test_module.cpp
This commit is contained in:
Jason Turner 2015-04-21 12:45:59 -06:00
commit 059c7bcca1
11 changed files with 274 additions and 13 deletions

View File

@ -409,6 +409,7 @@ namespace chaiscript
m->add(user_type<Boxed_Value>(), "Object"); m->add(user_type<Boxed_Value>(), "Object");
m->add(user_type<Boxed_Number>(), "Number"); m->add(user_type<Boxed_Number>(), "Number");
m->add(user_type<Proxy_Function>(), "Function"); m->add(user_type<Proxy_Function>(), "Function");
m->add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
m->add(user_type<std::exception>(), "exception"); m->add(user_type<std::exception>(), "exception");
m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity"); m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
@ -505,6 +506,13 @@ namespace chaiscript
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone"); m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "="); m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "="); m->add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
m->add(fun<void (dispatch::Assignable_Proxy_Function &, const std::shared_ptr<const dispatch::Proxy_Function_Base> &)>(
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
t_lhs.assign(t_rhs);
}
), "="
);
m->add(fun(&Boxed_Value::type_match), "type_match"); m->add(fun(&Boxed_Value::type_match), "type_match");

View File

@ -793,6 +793,42 @@ namespace chaiscript
return m_conversions; return m_conversions;
} }
bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const std::vector<Boxed_Value> &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<Boxed_Value> &params, bool t_has_params) const
{
auto funs = get_function(t_name);
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;
}
} else {
return dispatch::dispatch(funs, params, m_conversions);
}
}
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
{ {
Boxed_Value bv = dispatch::dispatch(get_function(t_name), params, m_conversions); Boxed_Value bv = dispatch::dispatch(get_function(t_name), params, m_conversions);

View File

@ -44,9 +44,11 @@ namespace chaiscript
public: public:
Dynamic_Object_Function( Dynamic_Object_Function(
std::string t_type_name, 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()), : 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<Dynamic_Object>()) m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>()),
m_is_attribute(t_is_attribute)
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
@ -55,9 +57,11 @@ namespace chaiscript
Dynamic_Object_Function( Dynamic_Object_Function(
std::string t_type_name, std::string t_type_name,
const Proxy_Function &t_func, 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()), : 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<Dynamic_Object>()) 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<Dynamic_Object>()),
m_is_attribute(t_is_attribute)
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "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<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
@ -164,6 +170,7 @@ namespace chaiscript
Proxy_Function m_func; Proxy_Function m_func;
std::unique_ptr<Type_Info> m_ti; std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti; const Type_Info m_doti;
bool m_is_attribute;
}; };

View File

@ -57,7 +57,7 @@ namespace chaiscript
std::function<FunctionType> std::function<FunctionType>
functor(Const_Proxy_Function func, const Type_Conversions *t_conversions) functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
{ {
return functor<FunctionType>(std::vector<Const_Proxy_Function>({func}), t_conversions); return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
} }
/// Helper for automatically unboxing a Boxed_Value that contains a function object /// Helper for automatically unboxing a Boxed_Value that contains a function object

View File

@ -26,6 +26,9 @@ namespace chaiscript
{ {
namespace dispatch namespace dispatch
{ {
template<class T> class Proxy_Function_Impl;
template<class T> class Assignable_Proxy_Function_Impl;
namespace detail namespace detail
{ {
/** /**
@ -49,6 +52,98 @@ namespace chaiscript
} }
}; };
template<typename Ret>
struct Handle_Return<const std::function<Ret> &>
{
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
std::shared_ptr<dispatch::Proxy_Function_Base>(
new dispatch::Proxy_Function_Impl<Ret>(f)
)
);
}
};
template<typename Ret>
struct Handle_Return<std::function<Ret>>
{
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
std::shared_ptr<dispatch::Proxy_Function_Base>(
new Proxy_Function_Impl<Ret>(f)
)
);
}
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>>>
{
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
std::shared_ptr<Proxy_Function_Base>(
new Assignable_Proxy_Function_Impl<Ret>(
std::ref(*f),
f
)
)
);
}
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &>
{
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
std::shared_ptr<Proxy_Function_Base>(
new Assignable_Proxy_Function_Impl<Ret>(
std::ref(*f),
f
)
)
);
}
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<std::function<Ret>>>
{
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
std::shared_ptr<Proxy_Function_Base>(
new Assignable_Proxy_Function_Impl<Ret>(
std::ref(*f),
f
)
)
);
}
};
template<typename Ret>
struct Handle_Return<std::function<Ret> &>
{
static Boxed_Value handle(std::function<Ret> &f) {
return Boxed_Value(
std::shared_ptr<Proxy_Function_Base>(
new Assignable_Proxy_Function_Impl<Ret>(
std::ref(f),
std::shared_ptr<std::function<Ret>>()
)
)
);
}
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
std::shared_ptr<dispatch::Proxy_Function_Base>(
new dispatch::Proxy_Function_Impl<Ret>(f)
)
);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret *> struct Handle_Return<Ret *>
{ {

View File

@ -43,6 +43,9 @@ namespace chaiscript
namespace dispatch namespace dispatch
{ {
template<typename FunctionType>
std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func, const Type_Conversions *t_conversions);
class Param_Types class Param_Types
{ {
public: public:
@ -159,6 +162,8 @@ namespace chaiscript
virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
virtual bool is_attribute_function() const { return false; }
bool has_arithmetic_param() const bool has_arithmetic_param() const
{ {
return m_has_arithmetic_param; return m_has_arithmetic_param;
@ -216,6 +221,12 @@ namespace chaiscript
return false; 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: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const = 0; virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const = 0;
@ -233,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<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs)
{ {
@ -580,11 +587,73 @@ namespace chaiscript
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions); return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions);
} }
private: private:
std::function<Func> m_f; std::function<Func> m_f;
Func *m_dummy_func; Func *m_dummy_func;
}; };
class Assignable_Proxy_Function : public Proxy_Function_Impl_Base
{
public:
Assignable_Proxy_Function(const std::vector<Type_Info> &t_types)
: Proxy_Function_Impl_Base(t_types)
{
}
virtual ~Assignable_Proxy_Function() {}
virtual void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) = 0;
};
template<typename Func>
class Assignable_Proxy_Function_Impl : public Assignable_Proxy_Function
{
public:
Assignable_Proxy_Function_Impl(std::reference_wrapper<std::function<Func>> t_f, std::shared_ptr<std::function<Func>> t_ptr)
: Assignable_Proxy_Function(detail::build_param_type_list(static_cast<Func *>(nullptr))),
m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr)), m_dummy_func(nullptr)
{
assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get());
}
virtual ~Assignable_Proxy_Function_Impl() {}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
}
virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
{
return dynamic_cast<const Assignable_Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
}
std::function<Func> internal_function() const
{
return m_f.get();
}
virtual void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) {
m_f.get() = dispatch::functor<Func>(t_rhs, nullptr);
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
{
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f.get(), params, t_conversions);
}
private:
std::reference_wrapper<std::function<Func>> m_f;
std::shared_ptr<std::function<Func>> m_shared_ptr_holder;
Func *m_dummy_func;
};
/// Attribute getter Proxy_Function implementation /// Attribute getter Proxy_Function implementation
template<typename T, typename Class> template<typename T, typename Class>
class Attribute_Access : public Proxy_Function_Base class Attribute_Access : public Proxy_Function_Base
@ -598,6 +667,8 @@ namespace chaiscript
virtual ~Attribute_Access() {} 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 virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
{ {
const Attribute_Access<T, Class> * aa const Attribute_Access<T, Class> * aa
@ -634,7 +705,7 @@ namespace chaiscript
if (bv.is_const()) if (bv.is_const())
{ {
const Class *o = boxed_cast<const Class *>(bv, &t_conversions); const Class *o = boxed_cast<const Class *>(bv, &t_conversions);
return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr); return detail::Handle_Return<const typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
} else { } else {
Class *o = boxed_cast<Class *>(bv, &t_conversions); Class *o = boxed_cast<Class *>(bv, &t_conversions);
return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr); return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);

View File

@ -704,7 +704,10 @@ namespace chaiscript
for (size_t i = 2; i < this->children.size(); i+=2) { for (size_t i = 2; i < this->children.size(); i+=2) {
std::vector<Boxed_Value> params{retval}; std::vector<Boxed_Value> params{retval};
bool has_function_params = false;
if (this->children[i]->children.size() > 1) { if (this->children[i]->children.size() > 1) {
has_function_params = true;
for (const auto &child : this->children[i]->children[1]->children) { for (const auto &child : this->children[i]->children[1]->children) {
params.push_back(child->eval(t_ss)); params.push_back(child->eval(t_ss));
} }
@ -723,7 +726,7 @@ namespace chaiscript
try { try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); 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){ catch(const exception::dispatch_error &e){
if (e.functions.empty()) if (e.functions.empty())
@ -1534,7 +1537,9 @@ namespace chaiscript
std::placeholders::_1, std::placeholders::_1,
this->children[static_cast<size_t>(1 + class_offset)]->text this->children[static_cast<size_t>(1 + class_offset)]->text
)) ))
) ),
true
), this->children[static_cast<size_t>(1 + class_offset)]->text); ), this->children[static_cast<size_t>(1 + class_offset)]->text);
} }

View File

@ -1319,9 +1319,10 @@ namespace chaiscript
} }
} while (Char(',')); } while (Char(','));
} }
build_match(std::make_shared<eval::Arg_List_AST_Node>(), prev_stack_top);
} }
build_match(std::make_shared<eval::Arg_List_AST_Node>(), prev_stack_top);
SkipWS(true); SkipWS(true);
return retval; return retval;

View File

@ -23,6 +23,7 @@ class TestBaseType
const int const_val; const int const_val;
int mdarray[2][3][5]; int mdarray[2][3][5];
std::function<int (int)> func_member;
private: private:
TestBaseType &operator=(const TestBaseType &); TestBaseType &operator=(const TestBaseType &);
@ -173,6 +174,8 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
// end array types // end array types
#endif #endif
// member that is a function
m->add(chaiscript::fun(&TestBaseType::func_member), "func_member");
m->add(chaiscript::fun(&get_new_int), "get_new_int"); m->add(chaiscript::fun(&get_new_int), "get_new_int");

View File

@ -0,0 +1,23 @@
// Test attributes/members that are functions
load_module("test_module")
class MyClass
{
var func_member;
def MyClass() {}
}
auto t0 = MyClass();
t0.func_member = fun(int i){ i * 3; };
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);

View File

@ -0,0 +1,12 @@
// Test attributes/members that are functions
load_module("test_module")
auto t0 = TestBaseType()
t0.func_member = fun(int i){ i * 3; };
assert_true(func_member(t0)(2) == 6)
assert_true((func_member(t0))(2) == 6)
assert_true(t0.func_member(2) == 6)