Add function meta data functions, plus related tests, and some various cleanups for how functions are constructed internally

This commit is contained in:
Jason Turner
2010-10-14 14:33:17 +00:00
parent 0caa782437
commit 2cdfac4e47
8 changed files with 243 additions and 27 deletions

View File

@@ -12,6 +12,7 @@
#include "register_function.hpp" #include "register_function.hpp"
#include "operators.hpp" #include "operators.hpp"
#include "boxed_pod_value.hpp" #include "boxed_pod_value.hpp"
#include <boost/function_types/result_type.hpp>
namespace chaiscript namespace chaiscript
{ {
@@ -505,6 +506,32 @@ namespace chaiscript
} }
} }
template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(const boost::function<FunctionType> &f,
const Proxy_Function_Base *b)
{
typedef typename boost::function_types::result_type<FunctionType>::type Vector;
Vector v = f(b);
std::vector<Boxed_Value> vbv;
for (typename Vector::const_iterator itr = v.begin();
itr != v.end();
++itr)
{
vbv.push_back(const_var(*itr));
}
return vbv;
}
template<typename Function>
static boost::function<std::vector<Boxed_Value> (const Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
{
typedef typename boost::function_types::result_type<Function>::type Vector;
boost::function<Vector (const Proxy_Function_Base *)> func(f);
return boost::bind(&do_return_boxed_value_vector<Vector (const Proxy_Function_Base *)>, func, _1);
}
public: public:
/** /**
* perform all common bootstrap functions for std::string, void and POD types * perform all common bootstrap functions for std::string, void and POD types
@@ -518,6 +545,16 @@ namespace chaiscript
m->add(user_type<Proxy_Function>(), "function"); m->add(user_type<Proxy_Function>(), "function");
m->add(user_type<std::exception>(), "exception"); m->add(user_type<std::exception>(), "exception");
m->add(fun(&Proxy_Function_Base::get_arity), "get_arity");
m->add(fun(&Proxy_Function_Base::annotation), "get_annotation");
m->add(fun(&Proxy_Function_Base::operator()), "call");
m->add(fun(&Proxy_Function_Base::operator==), "==");
m->add(fun(return_boxed_value_vector(&Proxy_Function_Base::get_param_types)), "get_param_types");
m->add(fun(return_boxed_value_vector(&Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
m->add(user_type<std::runtime_error>(), "runtime_error"); m->add(user_type<std::runtime_error>(), "runtime_error");
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error"); m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
m->add(fun(boost::function<std::string (const std::runtime_error &)>(&what)), "what"); m->add(fun(boost::function<std::string (const std::runtime_error &)>(&what)), "what");
@@ -550,6 +587,9 @@ namespace chaiscript
m->add(fun(&Type_Info::name), "cpp_name"); m->add(fun(&Type_Info::name), "cpp_name");
m->add(fun(&Type_Info::bare_name), "cpp_bare_name"); m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
m->add(fun(&Type_Info::bare_equal), "bare_equal"); m->add(fun(&Type_Info::bare_equal), "bare_equal");
typedef bool (Type_Info::*typeinfocompare)(const Type_Info &) const;
m->add(fun(typeinfocompare(&Type_Info::operator==)), "==");
m->add(fun(&Type_Info::bare_equal), "bare_equal");
basic_constructors<bool>("bool", m); basic_constructors<bool>("bool", m);

View File

@@ -449,7 +449,8 @@ namespace detail {
assignable_type<VectorType>(type, m); assignable_type<VectorType>(type, m);
input_range_type<VectorType>(type, m); input_range_type<VectorType>(type, m);
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \ m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \
if ( rhs.size() != this.size() ) { \ if ( rhs.size() != this.size() ) { \
return false; \ return false; \
@@ -468,7 +469,7 @@ namespace detail {
return true; \ return true; \
} \ } \
}"); }");
}
return m; return m;
} }

View File

@@ -120,24 +120,72 @@ namespace chaiscript
{ {
public: public:
Dispatch_Function(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs) Dispatch_Function(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs)
: Proxy_Function_Base(std::vector<Type_Info>()), : Proxy_Function_Base(build_type_infos(t_funcs)),
m_funcs(t_funcs) m_funcs(t_funcs)
{ {
} }
virtual bool operator==(const Proxy_Function_Base &) const virtual bool operator==(const Proxy_Function_Base &rhs) const
{ {
try {
const Dispatch_Function &dispatchfun = dynamic_cast<const Dispatch_Function &>(rhs);
return m_funcs == dispatchfun.m_funcs;
} catch (const std::bad_cast &) {
return false; return false;
} }
}
virtual ~Dispatch_Function() {} virtual ~Dispatch_Function() {}
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
{
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
function_vec::const_iterator begin = m_funcs.begin();
const function_vec::const_iterator end = m_funcs.end();
std::vector<Const_Proxy_Function> fs;
while (begin != end)
{
fs.push_back(begin->second);
++begin;
}
return fs;
}
virtual int get_arity() const virtual int get_arity() const
{ {
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
function_vec::const_iterator begin = m_funcs.begin();
const function_vec::const_iterator end = m_funcs.end();
if (begin != end)
{
int arity = begin->second->get_arity();
++begin;
while (begin != end)
{
if (arity != begin->second->get_arity())
{
// The arities in the list do not match, so it's unspecified
return -1; return -1;
} }
++begin;
}
return arity;
}
return -1; // unknown arity
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{ {
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec; typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
@@ -160,7 +208,7 @@ namespace chaiscript
virtual std::string annotation() const virtual std::string annotation() const
{ {
return ""; return "Multiple method dispatch function wrapper.";
} }
protected: protected:
@@ -171,6 +219,54 @@ namespace chaiscript
private: private:
std::vector<std::pair<std::string, Proxy_Function > > m_funcs; std::vector<std::pair<std::string, Proxy_Function > > m_funcs;
static std::vector<Type_Info> build_type_infos(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs)
{
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
function_vec::const_iterator begin = t_funcs.begin();
const function_vec::const_iterator end = t_funcs.end();
if (begin != end)
{
std::vector<Type_Info> type_infos = begin->second->get_param_types();
++begin;
bool sizemismatch = false;
while (begin != end)
{
std::vector<Type_Info> param_types = begin->second->get_param_types();
if (param_types.size() != type_infos.size())
{
sizemismatch = true;
}
for (size_t i = 0; i < type_infos.size() && i < param_types.size(); ++i)
{
if (!(type_infos[i] == param_types[i]))
{
type_infos[i] = detail::Get_Type_Info<Boxed_Value>::get();
}
}
++begin;
}
assert(type_infos.size() > 0 && " type_info vector size is < 0, this is only possible if something else is broken");
if (sizemismatch)
{
type_infos.resize(1);
}
return type_infos;
}
return std::vector<Type_Info>();
}
}; };
@@ -412,6 +508,15 @@ namespace chaiscript
{ {
throw std::range_error("Object not known: " + name); throw std::range_error("Object not known: " + name);
} else { } else {
if (funcs.size() == 1)
{
// Return the first item if there is only one,
// no reason to take the cast of the extra level of dispatch
return const_var(funcs.begin()->second);
}
Boxed_Value f(Const_Proxy_Function(new Dispatch_Function(funcs))); Boxed_Value f(Const_Proxy_Function(new Dispatch_Function(funcs)));
return f; return f;
} }

View File

@@ -90,6 +90,13 @@ namespace chaiscript
} }
} }
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
{
std::vector<Const_Proxy_Function> fs;
fs.push_back(m_func);
return fs;
}
virtual int get_arity() const virtual int get_arity() const
{ {

View File

@@ -77,6 +77,11 @@ 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 = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0;
virtual std::vector<boost::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
{
return std::vector<boost::shared_ptr<const Proxy_Function_Base> >();
}
//! Return true if the function is a possible match //! Return true if the function is a possible match
//! to the passed in values //! to the passed in values
@@ -192,9 +197,9 @@ namespace chaiscript
{ {
} }
virtual bool operator==(const Proxy_Function_Base &) const virtual bool operator==(const Proxy_Function_Base &rhs) const
{ {
return false; return this == &rhs;
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals) const virtual bool call_match(const std::vector<Boxed_Value> &vals) const
@@ -255,6 +260,7 @@ namespace chaiscript
{ {
std::vector<Type_Info> types; std::vector<Type_Info> types;
// For the return type
types.push_back(detail::Get_Type_Info<Boxed_Value>::get()); types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
if (arity >= 0) if (arity >= 0)
@@ -263,8 +269,6 @@ namespace chaiscript
{ {
types.push_back(detail::Get_Type_Info<Boxed_Value>::get()); types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
} }
} else {
types.push_back(detail::Get_Type_Info<std::vector<Boxed_Value> >::get());
} }
return types; return types;
@@ -318,6 +322,14 @@ namespace chaiscript
return (*m_f)(build_param_list(params)); return (*m_f)(build_param_list(params));
} }
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
{
std::vector<Const_Proxy_Function> fs;
fs.push_back(m_f);
return fs;
}
std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> &params) const std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> &params) const
{ {
typedef std::vector<Boxed_Value>::const_iterator pitr; typedef std::vector<Boxed_Value>::const_iterator pitr;

View File

@@ -0,0 +1,11 @@
assert_equal(`==`, `==`);
assert_not_equal(`==`, `<`);
assert_equal(`<`.get_arity(), 2);
assert_equal(`+`.get_annotation(), "Multiple method dispatch function wrapper.");
assert_equal(get_arity.get_contained_functions().size(), 0);
assert_equal(get_arity.get_arity(), 1);
assert_equal(get_arity.get_param_types().size(), 2);
var paramtypes = get_arity.get_param_types();
assert_equal(true, paramtypes[1].bare_equal(function_type));

View File

@@ -0,0 +1,28 @@
#Test Function Description
def test_function(a)
{
return a;
}
assert_equal(test_function.get_arity(), 1);
assert_equal(test_function.get_annotation(), "#Test Function Description\n");
assert_equal(test_function.get_contained_functions().size(), 0);
assert_equal(test_function.get_param_types().size(), 2);
assert_equal(test_function, test_function);
assert_not_equal(test_function, `+`);
assert_equal(test_function.call([1]), 1);
assert_equal(2, `==`.get_arity());
// < should be the merging of two functions bool <(PODObject, PODObject) and bool <(string, string)
// we want to peel it apart and make sure that's true
var types = `<`.get_param_types();
assert_equal(3, types.size());
assert_equal(true, types[0].bare_equal(bool_type));
assert_equal(true, types[1].bare_equal(Object_type));
assert_equal(true, types[2].bare_equal(Object_type));
assert_equal(2, `<`.get_contained_functions().size());

View File

@@ -10,6 +10,18 @@ def assert_equal(x, y)
} }
} }
def assert_not_equal(x, y)
{
if (!(x == y))
{
// Passes
} else {
// Fails
print("assert_not_equal failure: got " + to_string(y) + " which was not expected.");
exit(-1);
}
}
def assert_throws(desc, x) def assert_throws(desc, x)
{ {
if (throws_exception(x)) if (throws_exception(x))