Enable optional typing of function params

This commit is contained in:
Jason Turner
2015-01-13 11:24:40 -07:00
parent 12533ce3e1
commit 4761a68d06
6 changed files with 240 additions and 246 deletions

View File

@@ -19,7 +19,6 @@
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "proxy_functions.hpp"
#include "type_info.hpp"
namespace chaiscript {
@@ -62,217 +61,6 @@ namespace chaiscript
std::map<std::string, Boxed_Value> m_attrs;
};
namespace detail
{
/// A Proxy_Function implementation designed for calling a function
/// that is automatically guarded based on the first param based on the
/// param's type name
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func)
: 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>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func,
const Type_Info &t_ti)
: 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(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
virtual ~Dynamic_Object_Function() {}
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else {
return false;
}
}
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))
{
return m_func->call_match(vals, t_conversions);
} else {
return false;
}
}
virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
{
return {m_func};
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{
return (*m_func)(params, t_conversions);
} else {
throw exception::guard_error();
}
}
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
}
private:
static std::vector<Type_Info> build_param_types(
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
{
std::vector<Type_Info> types(t_inner_types);
assert(types.size() > 1);
assert(types[1].bare_equal(user_type<Boxed_Value>()));
types[1] = t_objectti;
return types;
}
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{
if (bv.get_type_info().bare_equal(m_doti))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
if (ti)
{
return bv.get_type_info().bare_equal(*ti);
} else {
return false;
}
}
}
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{
if (bvs.size() > 0)
{
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
m_type_name(std::move(t_type_name)), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
auto begin = tl.begin();
auto end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
if (dc)
{
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions);
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
auto bv = var(Dynamic_Object(m_type_name));
std::vector<Boxed_Value> new_params{bv};
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params, t_conversions);
return bv;
}
private:
std::string m_type_name;
Proxy_Function m_func;
};
}
}
}
#endif

View File

@@ -8,6 +8,8 @@
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include "proxy_functions.hpp"
namespace chaiscript
{
namespace dispatch

View File

@@ -24,6 +24,7 @@
#include "boxed_value.hpp"
#include "proxy_functions_detail.hpp"
#include "type_info.hpp"
#include "dynamic_object.hpp"
namespace chaiscript {
class Type_Conversions;
@@ -42,6 +43,91 @@ namespace chaiscript
namespace dispatch
{
class Param_Types
{
public:
Param_Types()
{}
Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
: m_types(std::move(t_types))
{
update_has_types();
}
void push_front(std::string t_name, Type_Info t_ti)
{
m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti));
update_has_types();
}
bool operator==(const Param_Types &t_rhs) const
{
return m_types == t_rhs.m_types;
}
bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
{
if (!m_has_types) return true;
if (vals.size() != m_types.size()) return false;
for (size_t i = 0; i < vals.size(); ++i)
{
const auto &name = m_types[i].first;
if (!name.empty()) {
const auto &bv = vals[i];
if (bv.get_type_info().bare_equal(m_doti))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
const auto &ti = m_types[i].second;
if (!ti.is_undef())
{
if (!bv.get_type_info().bare_equal(ti)) {
return false;
}
} else {
return false;
}
}
}
}
return true;
}
const std::vector<std::pair<std::string, Type_Info>> &types() const
{
return m_types;
}
private:
void update_has_types()
{
for (const auto &type : m_types)
{
if (!type.first.empty())
{
m_has_types = true;
return;
}
}
m_has_types = false;
}
std::vector<std::pair<std::string, Type_Info>> m_types;
bool m_has_types = false;
Type_Info m_doti = user_type<Dynamic_Object>();
};
/**
* Pure virtual base class for all Proxy_Function implementations
* Proxy_Functions are a type erasure of type safe C++
@@ -215,10 +301,12 @@ namespace chaiscript
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> t_f,
int t_arity=-1,
AST_NodePtr t_parsenode = AST_NodePtr(),
Param_Types t_param_types = Param_Types(),
std::string t_description = "",
Proxy_Function t_guard = Proxy_Function())
: Proxy_Function_Base(build_param_type_list(t_arity), t_arity),
m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
m_f(std::move(t_f)), m_arity(t_arity), m_param_types(std::move(t_param_types)),
m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
{
}
@@ -231,14 +319,15 @@ namespace chaiscript
return this == &rhs
|| (prhs
&& this->m_arity == prhs->m_arity
&& !this->m_guard && !prhs->m_guard);
&& !this->m_guard && !prhs->m_guard
&& this->m_param_types == prhs->m_param_types);
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return (m_arity < 0 || vals.size() == size_t(m_arity))
return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions)))
&& test_guard(vals, t_conversions);
}
}
Proxy_Function get_guard() const
@@ -261,8 +350,7 @@ namespace chaiscript
{
if (m_arity < 0 || params.size() == size_t(m_arity))
{
if (test_guard(params, t_conversions))
if (call_match(params, t_conversions) && test_guard(params, t_conversions))
{
return m_f(params);
} else {
@@ -291,18 +379,19 @@ namespace chaiscript
}
}
static std::vector<Type_Info> build_param_type_list(int arity)
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
{
std::vector<Type_Info> types;
// For the return type
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
if (arity > 0)
for (const auto &t : t_types.types())
{
for (int i = 0; i < arity; ++i)
{
if (t.second.is_undef()) {
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
} else {
types.push_back(t.second);
}
}
@@ -311,6 +400,7 @@ namespace chaiscript
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
int m_arity;
Param_Types m_param_types;
std::string m_description;
Proxy_Function m_guard;
AST_NodePtr m_parsenode;