Compare commits

...

14 Commits

Author SHA1 Message Date
Jason Turner
93bc6109e7 Merge branch 'develop' into typed_function_ordering 2016-12-05 19:19:41 -07:00
Jason Turner
4119e6e7d8 Merge branch 'develop' into typed_function_ordering 2016-10-26 14:33:33 -06:00
Jason Turner
7d11b7c5f1 Merge branch 'develop' into typed_function_ordering 2016-04-20 06:41:37 -06:00
Jason Turner
82a69ca043 Merge branch 'develop' into typed_function_ordering 2016-03-15 12:46:47 -06:00
Jason Turner
dfb2394b0b Merge branch 'update_travis_toolchain' into typed_function_ordering 2016-03-11 15:00:28 -07:00
Jason Turner
c07f413694 Merge branch 'develop' into typed_function_ordering 2016-03-04 13:33:29 -07:00
Jason Turner
172ab7b8e4 Merge branch 'develop' into typed_function_ordering 2016-02-18 08:57:55 -07:00
Jason Turner
fe8ddd1869 Merge branch 'develop' into typed_function_ordering 2016-01-20 18:32:16 -07:00
Jason Turner
5cb6f6a1a2 Merge branch 'develop' into typed_function_ordering 2016-01-20 18:28:28 -07:00
Jason Turner
95256417ac Merge branch 'add_performance_tests' of github.com:ChaiScript/ChaiScript into typed_function_ordering 2015-10-25 15:00:08 -06:00
Jason Turner
2d2251c1da Merge branch 'develop' of github.com:ChaiScript/ChaiScript into typed_function_ordering 2015-08-26 18:58:34 -06:00
Jason Turner
0adacc0b5e Merge branch 'develop' of github.com:ChaiScript/ChaiScript into typed_function_ordering 2015-08-26 18:47:43 -06:00
Jason Turner
818fd0b823 Add function ordering test 2015-08-26 18:47:32 -06:00
Jason Turner
bd9af5eff4 Order typed functions over untyped
specifically the chaiscript defined ones
2015-08-14 21:58:54 -06:00
5 changed files with 260 additions and 83 deletions

View File

@ -1100,22 +1100,30 @@ namespace chaiscript
{
std::vector<Type_Info> params = f.second->get_param_types();
std::vector<std::pair<std::string, Type_Info>> typed_params;
auto func(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(f.second));
if (func) {
typed_params = func->get_dynamic_param_types().types();
}
dump_type(params.front());
std::cout << " " << f.first << "(";
for (std::vector<Type_Info>::const_iterator itr = params.begin() + 1;
itr != params.end();
)
for (size_t i = 1; i < params.size(); ++i)
{
dump_type(*itr);
++itr;
if (!typed_params.empty() && !typed_params[i-1].first.empty()) {
std::cout << typed_params[i-1].first;
} else {
dump_type(params[i]);
}
if (itr != params.end())
{
if (i != params.size() - 1) {
std::cout << ", ";
}
}
std::cout << ") \n";
}
@ -1327,88 +1335,156 @@ namespace chaiscript
return m_state.m_functions;
}
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
static std::vector<Type_Info> param_types(const Proxy_Function &t_f)
{
assert(t_f);
return t_f->get_param_types();
}
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
static std::vector<std::pair<std::string, Type_Info>> param_types(const std::shared_ptr<const dispatch::Dynamic_Function_Interface> &t_f)
{
assert(t_f);
const auto types = t_f->get_dynamic_param_types().types();
std::vector<std::pair<std::string, Type_Info>> ret(1);
ret.insert(ret.end(), types.begin(), types.end());
return ret;
}
if (dynamic_lhs && dynamic_rhs)
static Type_Info type_info(const std::pair<std::string, Type_Info> &t_ti)
{
return t_ti.second;
}
static Type_Info type_info(const Type_Info &t_ti)
{
return t_ti;
}
static std::string dynamic_type_name(const std::pair<std::string, Type_Info> &t_ti)
{
return t_ti.first.empty()?t_ti.second.name():t_ti.first;
}
static std::string dynamic_type_name(const Type_Info &ti)
{
return ti.name();
}
template<typename LHS, typename RHS>
static bool params_less_than(const LHS &t_lhs, const RHS &t_rhs)
{
if (dynamic_lhs->get_guard())
assert(t_lhs);
assert(t_rhs);
const auto lhsparamtypes = param_types(t_lhs);
const auto rhsparamtypes = param_types(t_rhs);
const auto lhssize = lhsparamtypes.size();
const auto rhssize = rhsparamtypes.size();
constexpr auto boxed_type = user_type<Boxed_Value>();
constexpr auto boxed_pod_type = user_type<Boxed_Number>();
constexpr auto dynamic_type = user_type<dispatch::Dynamic_Object>();
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
{
return dynamic_rhs->get_guard() ? false : true;
} else {
return false;
}
}
const Type_Info lt = type_info(lhsparamtypes[i]);
const Type_Info rt = type_info(rhsparamtypes[i]);
const std::string ln = dynamic_type_name(lhsparamtypes[i]);
const std::string rn = dynamic_type_name(rhsparamtypes[i]);
if ( (lt.bare_equal(dynamic_type) || lt.is_undef())
&& (rt.bare_equal(dynamic_type) || rt.is_undef()))
{
if (!ln.empty() && rn.empty()) {
return true;
} else if (ln.empty() && !rn.empty()) {
return false;
} else if (!ln.empty() && !rn.empty()) {
if (ln < rn) {
return true;
} else if (rn < ln) {
return false;
}
// the remaining cases are handled by the is_const rules below
}
}
if (lt.bare_equal(rt) && lt.is_const() == rt.is_const())
{
continue; // The first two types are essentially the same, next iteration
}
// const is after non-const for the same type
if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const())
{
return false;
}
if (lt.bare_equal(rt) && !lt.is_const())
{
return true;
}
// boxed_values are sorted last
if (lt.bare_equal(boxed_type))
{
return false;
}
if (rt.bare_equal(boxed_type))
{
return true;
}
if (lt.bare_equal(boxed_pod_type))
{
return false;
}
if (rt.bare_equal(boxed_pod_type))
{
return true;
}
// otherwise, we want to sort by typeid
return lt < rt;
}
// if everything else checks out, sort on guard
//
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_lhs));
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_rhs));
if (dynamic_lhs && dynamic_rhs) {
if (dynamic_lhs->get_guard() && !dynamic_rhs->get_guard()) {
return true;
} else if (dynamic_rhs->get_guard()) {
return false;
}
}
if (dynamic_lhs && !dynamic_rhs)
{
return false;
}
if (!dynamic_lhs && dynamic_rhs)
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
{
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(lhs));
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(rhs));
if (dynamic_lhs && dynamic_rhs)
{
return true;
return params_less_than(dynamic_lhs, dynamic_rhs);
} else if (dynamic_lhs) {
return params_less_than(dynamic_lhs, rhs);
} else if (dynamic_rhs) {
return params_less_than(lhs, dynamic_rhs);
} else {
return params_less_than(lhs, rhs);
}
const auto &lhsparamtypes = lhs->get_param_types();
const auto &rhsparamtypes = rhs->get_param_types();
const auto lhssize = lhsparamtypes.size();
const auto rhssize = rhsparamtypes.size();
static const auto boxed_type = user_type<Boxed_Value>();
static const auto boxed_pod_type = user_type<Boxed_Number>();
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
{
const Type_Info &lt = lhsparamtypes[i];
const Type_Info &rt = rhsparamtypes[i];
if (lt.bare_equal(rt) && lt.is_const() == rt.is_const())
{
continue; // The first two types are essentially the same, next iteration
}
// const is after non-const for the same type
if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const())
{
return false;
}
if (lt.bare_equal(rt) && !lt.is_const())
{
return true;
}
// boxed_values are sorted last
if (lt.bare_equal(boxed_type))
{
return false;
}
if (rt.bare_equal(boxed_type))
{
return true;
}
if (lt.bare_equal(boxed_pod_type))
{
return false;
}
if (rt.bare_equal(boxed_pod_type))
{
return true;
}
// otherwise, we want to sort by typeid
return lt < rt;
}
return false;
}

View File

@ -39,7 +39,7 @@ namespace chaiscript
/// 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 final : public Proxy_Function_Base
class Dynamic_Object_Function : public Proxy_Function_Base, public Dynamic_Function_Interface
{
public:
Dynamic_Object_Function(
@ -71,6 +71,17 @@ namespace chaiscript
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
Param_Types get_dynamic_param_types() const override {
auto dynamic(std::dynamic_pointer_cast<dispatch::Dynamic_Function_Interface>(m_func));
if (dynamic) {
return dynamic->get_dynamic_param_types();
} else {
return Param_Types(get_param_types());
}
}
bool operator==(const Proxy_Function_Base &f) const override
{
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
@ -173,7 +184,7 @@ namespace chaiscript
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor final : public Proxy_Function_Base
class Dynamic_Object_Constructor final : public Proxy_Function_Base, public Dynamic_Function_Interface
{
public:
Dynamic_Object_Constructor(
@ -182,6 +193,7 @@ namespace chaiscript
: 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 );
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
@ -199,6 +211,18 @@ namespace chaiscript
return std::vector<Type_Info>(begin, end);
}
Param_Types get_dynamic_param_types() const override {
auto dynamic(std::dynamic_pointer_cast<dispatch::Dynamic_Function_Interface>(m_func));
if (dynamic) {
return dynamic->get_dynamic_param_types();
} else {
return Param_Types(get_param_types());
}
}
bool operator==(const Proxy_Function_Base &f) const override
{
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);

View File

@ -53,6 +53,13 @@ namespace chaiscript
m_doti(user_type<Dynamic_Object>())
{}
explicit Param_Types(const std::vector<Type_Info> &t_types)
: m_types(build_param_types(t_types)),
m_has_types(false),
m_doti(user_type<Dynamic_Object>())
{
}
explicit Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
: m_types(std::move(t_types)),
m_has_types(false),
@ -61,6 +68,18 @@ namespace chaiscript
update_has_types();
}
static std::vector<std::pair<std::string, Type_Info>> build_param_types(const std::vector<Type_Info> &t_types)
{
std::vector<std::pair<std::string, Type_Info>> retval;
std::transform(t_types.begin(), t_types.end(), std::back_inserter(retval),
[](const Type_Info &ti){
return std::make_pair(std::string(), ti);
}
);
return retval;
}
void push_front(std::string t_name, Type_Info t_ti)
{
m_types.emplace(m_types.begin(), std::move(t_name), t_ti);
@ -288,11 +307,18 @@ namespace chaiscript
namespace dispatch
{
class Dynamic_Function_Interface
{
public:
virtual ~Dynamic_Function_Interface() {}
virtual Param_Types get_dynamic_param_types() const = 0;
};
/**
* A Proxy_Function implementation that is not type safe, the called function
* is expecting a vector<Boxed_Value> that it works with how it chooses.
*/
class Dynamic_Proxy_Function : public Proxy_Function_Base
class Dynamic_Proxy_Function : public Proxy_Function_Base, public Dynamic_Function_Interface
{
public:
Dynamic_Proxy_Function(
@ -335,6 +361,9 @@ namespace chaiscript
return m_parsenode;
}
Param_Types get_dynamic_param_types() const override {
return m_param_types;
}
protected:
bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const
@ -353,6 +382,8 @@ namespace chaiscript
}
}
private:
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
{
@ -855,6 +886,9 @@ namespace chaiscript
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
ordered_funcs.reserve(funcs.size());
const constexpr auto boxed_type = user_type<Boxed_Value>();
const constexpr auto dynamic_type = user_type<Dynamic_Object>();
for (const auto &func : funcs)
{
const auto arity = func->get_arity();
@ -866,7 +900,10 @@ namespace chaiscript
size_t numdiffs = 0;
for (size_t i = 0; i < plist.size(); ++i)
{
if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
const auto &p_type = plist[i].get_type_info();
const auto &f_type = func->get_param_types()[i+1];
if (!(f_type.bare_equal(boxed_type) && p_type.bare_equal(dynamic_type)) && !f_type.bare_equal(p_type))
{
++numdiffs;
}

View File

@ -0,0 +1,38 @@
GLOBAL clone_count = 0;
class Cloneable
{
def Cloneable() {
}
}
def clone(Cloneable c)
{
print("Clone called");
++clone_count;
return c;
}
class MyObject
{
def MyObject() {
this.data = Cloneable();
}
var data;
}
assert_equal(0, clone_count);
var o = MyObject();
assert_equal(0, clone_count);
var p = o;
assert_equal(1, clone_count);

View File

@ -319,7 +319,8 @@ TEST_CASE("Function ordering")
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
chai.eval("def test_fun(x) { return 3; }");
chai.eval("def test_fun(x) : x == \"hi\" { return 4; }");
// chai.eval("def test_fun(x) { return 5; }");
chai.eval("def test_fun(double d) { return 5; }");
chai.add(chaiscript::fun(&function_ordering_test_one), "test_fun");
chai.add(chaiscript::fun(&function_ordering_test_two), "test_fun");
@ -327,6 +328,7 @@ TEST_CASE("Function ordering")
CHECK(chai.eval<int>("auto i = 1; test_fun(i)") == 2);
CHECK(chai.eval<int>("test_fun(\"bob\")") == 3);
CHECK(chai.eval<int>("test_fun(\"hi\")") == 4);
CHECK(chai.eval<int>("test_fun(5.0)") == 5);
}