Merge branch 'develop' into method_missing

This commit is contained in:
Andreas Reischuck
2015-03-27 21:36:25 +01:00
34 changed files with 954 additions and 356 deletions

View File

@@ -10,6 +10,9 @@
#ifdef _MSC_VER
#define CHAISCRIPT_MSVC _MSC_VER
#define CHAISCRIPT_HAS_DECLSPEC
#if _MSC_VER <= 1800
#define CHAISCRIPT_MSVC_12
#endif
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
@@ -45,7 +48,7 @@
namespace chaiscript {
static const int version_major = 5;
static const int version_minor = 6;
static const int version_minor = 7;
static const int version_patch = 0;
}

View File

@@ -158,7 +158,7 @@ namespace chaiscript
if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(new T());
std::shared_ptr<T> new_instance(std::make_shared<T>());
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));

View File

@@ -303,7 +303,7 @@ namespace chaiscript
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&detail::insert_at<ContainerType>),
[](){
[]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
return "insert_ref_at";
} else {
@@ -329,7 +329,7 @@ namespace chaiscript
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
m->add(fun(static_cast<push_back>(&ContainerType::push_back)),
[](){
[]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
return "push_back_ref";
} else {
@@ -357,7 +357,7 @@ namespace chaiscript
m->add(fun(static_cast<constfrontptr>(&ContainerType::front)), "front");
m->add(fun(static_cast<pushptr>(&ContainerType::push_front)),
[](){
[]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
return "push_front_ref";
} else {
@@ -418,7 +418,7 @@ namespace chaiscript
m->add(fun(&detail::insert<ContainerType>), "insert");
m->add(fun(&detail::insert_ref<ContainerType>),
[](){
[]()->std::string{
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
return "insert_ref";
} else {
@@ -538,7 +538,7 @@ namespace chaiscript
//Special case: add push_back to string (which doesn't support other back_insertion operations
m->add(fun(&String::push_back),
[](){
[]()->std::string{
if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
return "push_back_ref";
} else {

View File

@@ -74,46 +74,47 @@ namespace chaiscript
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
{
try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !t_conversions->convertable_type<Type>())) {
try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
}
}
#ifdef CHAISCRIPT_MSVC
//Thank you MSVC, yes we know that a constant value is being used in the if
// statment in THIS VERSION of the template instantiation
//Thank you MSVC, yes we know that a constant value is being used in the if
// statment in THIS VERSION of the template instantiation
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
if (t_conversions && t_conversions->convertable_type<Type>())
{
if (t_conversions && t_conversions->convertable_type<Type>())
{
try {
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
} catch (...) {
try {
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
} catch (...) {
try {
// std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
// try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
// std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
// try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
} else {
// If it's not polymorphic, just throw the error, don't waste the time on the
// attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
} else {
// If it's not polymorphic, just throw the error, don't waste the time on the
// attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
}
}

View File

@@ -641,6 +641,7 @@ namespace chaiscript
/// \throws std::range_error if it does not
Boxed_Value get_function_object(const std::string &t_name) const
{
// std::cout << "Getting function object: " << t_name << '\n';
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto &funs = get_function_objects_int();

View File

@@ -30,7 +30,7 @@ namespace chaiscript
Proxy_Function build_constructor_(Class (*)(Params...))
{
typedef std::shared_ptr<Class> (sig)(Params...);
return Proxy_Function(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>))));
return Proxy_Function(static_cast<Proxy_Function_Impl_Base *>(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>)))));
}
}
}

View File

@@ -180,6 +180,8 @@ namespace chaiscript
if (m_arity == 0)
{
return true;
} else if (m_arity > 1 && m_types.size() > 1) {
return compare_first_type(vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions);
} else {
return compare_first_type(vals[0], t_conversions);
}
@@ -233,14 +235,7 @@ namespace chaiscript
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const
{
const auto &types = get_param_types();
if (types.size() < 2)
{
return true;
}
return compare_type_to_param(types[1], bv, t_conversions);
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)
@@ -779,7 +774,7 @@ namespace chaiscript
Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
{
//std::cout << "starting dispatch: " << funcs.size() << '\n';
std::multimap<size_t, const Proxy_Function_Base *> ordered_funcs;
for (const auto &func : funcs)
@@ -808,11 +803,17 @@ namespace chaiscript
for (const auto &func : ordered_funcs )
{
try {
if (func.second->filter(plist, t_conversions))
if (func.first == 0 || func.second->filter(plist, t_conversions))
{
return (*(func.second))(plist, t_conversions);
}
} catch (const exception::bad_boxed_cast &) {
//std::cout << "Bad Boxed Cast: " << func.second->get_arity() << '(';
//for (const auto &p : plist) {
// std::cout << p.get_type_info().name() << ',';
//}
//std::cout << ")\n";
//parameter failed to cast, try again
} catch (const exception::arity_error &) {
//invalid num params, try again

View File

@@ -40,17 +40,25 @@ namespace chaiscript
template<typename Ret, typename Class, typename ... Args>
std::function<Ret (Class &, Args...) > to_function(Ret (Class::*func)(Args...))
{
#ifdef CHAISCRIPT_MSVC
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
/// std::function for member function pointers seems to be broken in MSVC
return std::function<Ret(Class &, Args...)>(std::mem_fn(func));
#else
return std::function<Ret(Class &, Args...)>(func);
#endif
}
template<typename Ret, typename Class, typename ... Args>
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
{
#ifdef CHAISCRIPT_MSVC
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
/// std::function for member function pointers seems to be broken in MSVC
return std::function<Ret (const Class &, Args...)>(std::mem_fn(func));
return std::function<Ret(const Class &, Args...)>(std::mem_fn(func));
#else
return std::function<Ret(const Class &, Args...)>(func);
#endif
}
template<bool Object>
@@ -61,7 +69,7 @@ namespace chaiscript
{
/// \todo is it possible to reduce the number of templates generated here?
return Proxy_Function(
new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t)));
static_cast<dispatch::Proxy_Function_Impl_Base *>(new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t))));
}
};
@@ -118,7 +126,7 @@ namespace chaiscript
template<typename T>
Proxy_Function fun(const std::function<T> &f)
{
return Proxy_Function(new dispatch::Proxy_Function_Impl<T>(f));
return Proxy_Function(static_cast<dispatch::Proxy_Function_Impl_Base *>(new dispatch::Proxy_Function_Impl<T>(f)));
}

View File

@@ -467,14 +467,14 @@ namespace chaiscript
}
protected:
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname,
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<const std::string> &t_fname,
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname),
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
{
}
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname) :
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<const std::string> &t_fname) :
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname) {}
virtual ~AST_Node() {}
@@ -495,7 +495,6 @@ namespace chaiscript
{
namespace detail
{
/// Special type for returned values
struct Return_Value {
Boxed_Value retval;

View File

@@ -276,7 +276,7 @@ namespace chaiscript
parser::ChaiScript_Parser parser;
if (parser.parse(t_input, t_filename)) {
//parser.show_match_stack();
return parser.ast()->eval(m_engine);
return parser.optimized_ast()->eval(m_engine);
} else {
return Boxed_Value();
}

View File

@@ -47,9 +47,13 @@ namespace chaiscript
namespace detail
{
/// Helper function that will set up the scope around a function call, including handling the named function parameters
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals) {
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> &t_locals=std::map<std::string, Boxed_Value>()) {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
for (const auto &local : t_locals) {
t_ss.add_object(local.first, local.second);
}
for (size_t i = 0; i < t_param_names.size(); ++i) {
t_ss.add_object(t_param_names[i], t_vals[i]);
}
@@ -214,6 +218,7 @@ namespace chaiscript
}
};
struct Fun_Call_AST_Node : public AST_Node {
public:
Fun_Call_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
@@ -222,14 +227,13 @@ namespace chaiscript
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params;
if ((this->children.size() > 1)) {
const AST_Node &first_child(*(this->children[1]));
if (first_child.identifier == AST_Node_Type::Arg_List) {
for (const auto &child : first_child.children) {
params.push_back(child->eval(t_ss));
}
params.reserve(this->children[1]->children.size());
for (const auto &child : this->children[1]->children) {
params.push_back(child->eval(t_ss));
}
}
@@ -286,6 +290,96 @@ namespace chaiscript
};
struct Fun_Lookup_AST_Node : public AST_Node {
public:
Fun_Lookup_AST_Node(const std::string &t_fun_name)
: AST_Node(t_fun_name, 0, std::make_shared<std::string>("<EVAL>"))
{
}
virtual ~Fun_Lookup_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
try {
Boxed_Value bv = t_ss.get_object(text);
t_ss.add_object(text, bv);
std::cout << " Saved fun lookup: " << text << '\n';
return bv;
} catch (...) {
return Boxed_Value();
}
}
};
struct Unary_Fun_Call_AST_Node : public AST_Node {
public:
Unary_Fun_Call_AST_Node(const Fun_Call_AST_Node &t_fc)
: AST_Node(t_fc.text, t_fc.identifier, t_fc.filename, t_fc.start.line, t_fc.start.column, t_fc.end.line, t_fc.end.column)
{
this->children = t_fc.children;
}
virtual ~Unary_Fun_Call_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params{children[1]->children[0]->eval(t_ss)};
fpp.save_params(params);
Boxed_Value fn(this->children[0]->eval(t_ss));
try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
return (*t_ss.boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss.conversions());
}
catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
}
catch(const exception::bad_boxed_cast &){
try {
Const_Proxy_Function f = t_ss.boxed_cast<const Const_Proxy_Function &>(fn);
// handle the case where there is only 1 function to try to call and dispatch fails on it
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, t_ss);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
}
}
catch(const exception::arity_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(const exception::guard_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(detail::Return_Value &rv) {
return rv.retval;
}
}
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
{
std::ostringstream oss;
int count = 0;
for (const auto &child : this->children) {
oss << child->pretty_print();
if (count == 0)
{
oss << "(";
}
++count;
}
oss << ")";
return oss.str();
}
};
/// Used in the context of in-string ${} evals, so that no new scope is created
struct Inplace_Fun_Call_AST_Node : public AST_Node {
public:
@@ -446,26 +540,28 @@ namespace chaiscript
struct Equation_AST_Node : public AST_Node {
public:
Equation_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Equation, t_fname, t_start_line, t_start_col, t_end_line, t_end_col)
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Equation, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_oper(Operators::invalid)
{}
Operators::Opers m_oper;
virtual ~Equation_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value rhs = this->children.back()->eval(t_ss);
Boxed_Value rhs = this->children[2]->eval(t_ss);
Boxed_Value lhs = this->children[0]->eval(t_ss);
Operators::Opers oper = Operators::to_operator(this->children[1]->text);
if (oper != Operators::invalid && lhs.get_type_info().is_arithmetic() &&
if (m_oper != Operators::invalid && lhs.get_type_info().is_arithmetic() &&
rhs.get_type_info().is_arithmetic())
{
try {
return Boxed_Number::do_oper(oper, lhs, rhs);
return Boxed_Number::do_oper(m_oper, lhs, rhs);
} catch (const std::exception &) {
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
}
} else if (oper == Operators::assign) {
} else if (m_oper == Operators::assign) {
try {
if (lhs.is_undef()) {
if (!this->children.empty() &&
@@ -701,28 +797,31 @@ namespace chaiscript
virtual ~Lambda_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
std::vector<std::string> t_param_names;
size_t numparams = 0;
dispatch::Param_Types param_types;
const auto captures = [&]()->std::map<std::string, Boxed_Value>{
std::map<std::string, Boxed_Value> named_captures;
for (const auto &capture : children[0]->children) {
named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss)));
}
return named_captures;
}();
if (!this->children.empty() && (this->children[0]->identifier == AST_Node_Type::Arg_List)) {
numparams = this->children[0]->children.size();
t_param_names = Arg_List_AST_Node::get_arg_names(this->children[0]);
param_types = Arg_List_AST_Node::get_arg_types(this->children[0], t_ss);
}
const auto numparams = this->children[1]->children.size();
const auto param_names = Arg_List_AST_Node::get_arg_names(this->children[1]);
const auto param_types = Arg_List_AST_Node::get_arg_types(this->children[1], t_ss);
const auto &lambda_node = this->children.back();
return Boxed_Value(Proxy_Function(new dispatch::Dynamic_Proxy_Function(
[&t_ss, lambda_node, t_param_names](const std::vector<Boxed_Value> &t_params)
[&t_ss, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params)
{
return detail::eval_function(t_ss, lambda_node, t_param_names, t_params);
return detail::eval_function(t_ss, lambda_node, param_names, t_params, captures);
},
static_cast<int>(numparams), lambda_node, param_types)));
}
};
struct Block_AST_Node : public AST_Node {
@@ -732,25 +831,14 @@ namespace chaiscript
virtual ~Block_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
const auto num_children = this->children.size();
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
for (size_t i = 0; i < num_children; ++i) {
try {
if (i + 1 < num_children)
{
this->children[i]->eval(t_ss);
} else {
return this->children[i]->eval(t_ss);
}
}
catch (const chaiscript::eval::detail::Return_Value &) {
throw;
}
const auto num_children = children.size();
for (size_t i = 0; i < num_children-1; ++i) {
children[i]->eval(t_ss);
}
return children.back()->eval(t_ss);
return Boxed_Value();
}
};
@@ -883,8 +971,7 @@ namespace chaiscript
if (get_bool_condition(this->children[0]->eval(t_ss))) {
return this->children[1]->eval(t_ss);
}
else {
} else {
if (this->children.size() > 2) {
size_t i = 2;
bool cond = false;
@@ -917,26 +1004,22 @@ namespace chaiscript
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
// initial expression
this->children[0]->eval(t_ss);
try {
// while condition evals to true
while (get_bool_condition(this->children[1]->eval(t_ss))) {
for (
children[0]->eval(t_ss);
get_bool_condition(children[1]->eval(t_ss));
children[2]->eval(t_ss)
) {
try {
// Body of Loop
this->children[3]->eval(t_ss);
children[3]->eval(t_ss);
} catch (detail::Continue_Loop &) {
// we got a continue exception, which means all of the remaining
// loop implementation is skipped and we just need to continue to
// the next iteration step
}
// loop expression
this->children[2]->eval(t_ss);
}
}
catch (detail::Break_Loop &) {
} catch (detail::Break_Loop &) {
// loop broken
}
@@ -1388,7 +1471,7 @@ namespace chaiscript
guard = std::make_shared<dispatch::Dynamic_Proxy_Function>
(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), guardnode,
t_param_names, std::placeholders::_1), static_cast<int>(numparams), guardnode);
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), guardnode);
}
try {
@@ -1399,7 +1482,7 @@ namespace chaiscript
if (function_name == class_name) {
param_types.push_front(class_name, Type_Info());
t_ss.add(std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name, std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1),
std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()),
static_cast<int>(numparams), this->children.back(), param_types, l_annotation, guard)),
function_name);
@@ -1415,7 +1498,7 @@ namespace chaiscript
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), this->children.back(),
t_param_names, std::placeholders::_1), static_cast<int>(numparams), this->children.back(),
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), this->children.back(),
param_types, l_annotation, guard), type), function_name);
} catch (const std::range_error &) {
param_types.push_front(class_name, Type_Info());
@@ -1424,7 +1507,7 @@ namespace chaiscript
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), this->children.back(),
t_param_names, std::placeholders::_1), static_cast<int>(numparams), this->children.back(),
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), this->children.back(),
param_types, l_annotation, guard)), function_name);
}
}

View File

@@ -196,6 +196,127 @@ namespace chaiscript
return m_match_stack.front();
}
static std::map<std::string, int> count_fun_calls(const AST_NodePtr &p, bool in_loop) {
if (p->identifier == AST_Node_Type::Fun_Call) {
if (p->children[0]->identifier == AST_Node_Type::Id) {
return std::map<std::string, int>{{p->children[0]->text, in_loop?99:1}};
}
return std::map<std::string, int>();
} else {
std::map<std::string, int> counts;
for (const auto &child : p->children) {
auto childcounts = count_fun_calls(child, in_loop || p->identifier == AST_Node_Type::For || p->identifier == AST_Node_Type::While);
for (const auto &count : childcounts) {
counts[count.first] += count.second;
}
}
return counts;
}
}
static void optimize_fun_lookups(AST_NodePtr &p)
{
for (auto &c : p->children)
{
if (c->identifier == AST_Node_Type::Def
|| c->identifier == AST_Node_Type::Method
|| c->identifier == AST_Node_Type::Lambda) {
std::vector<AST_NodePtr> children_to_add;
auto counts = count_fun_calls(c, false);
for (const auto &count : counts) {
// std::cout << " Fun Call Count: " << count.first << " " << count.second << '\n';
if (count.second > 1) {
children_to_add.push_back(std::make_shared<eval::Fun_Lookup_AST_Node>(count.first));
}
}
c->children.back()->children.insert(c->children.back()->children.begin(), children_to_add.begin(), children_to_add.end());
}
optimize_fun_lookups(c);
}
}
static void optimize_blocks(AST_NodePtr &p)
{
for (auto &c : p->children)
{
if (c->identifier == AST_Node_Type::Block) {
if (c->children.size() == 1) {
// std::cout << "swapping out block child for block\n";
c = c->children[0];
}
}
optimize_blocks(c);
}
}
static void optimize_returns(AST_NodePtr &p)
{
for (auto &c : p->children)
{
if (c->identifier == AST_Node_Type::Def && c->children.size() > 0) {
auto &lastchild = c->children.back();
if (lastchild->identifier == AST_Node_Type::Block) {
auto &blocklastchild = lastchild->children.back();
if (blocklastchild->identifier == AST_Node_Type::Return) {
if (blocklastchild->children.size() == 1) {
blocklastchild = blocklastchild->children[0];
}
}
}
}
optimize_returns(c);
}
}
static void optimize_fun_calls(AST_NodePtr &p)
{
for (auto &c : p->children)
{
if (c->identifier == AST_Node_Type::Fun_Call && c->children.size() == 2 && c->children[1]->children.size() == 1) {
c = std::make_shared<eval::Unary_Fun_Call_AST_Node>(dynamic_cast<eval::Fun_Call_AST_Node &>(*c));
// std::cout << "optimized unary fun call\n";
}
optimize_fun_calls(c);
}
}
static void fixup_opers(AST_NodePtr &p)
{
if (p->identifier == AST_Node_Type::Equation)
{
dynamic_cast<eval::Equation_AST_Node &>(*p).m_oper = Operators::to_operator(p->children[1]->text);
}
for (auto &c : p->children) {
fixup_opers(c);
}
}
static int count_nodes(const AST_NodePtr &p)
{
int count = 1;
for (auto &c : p->children) {
count += count_nodes(c);
}
return count;
}
AST_NodePtr optimized_ast(bool t_optimize_blocks = false, bool t_optimize_returns = true, bool t_optimize_fun_lookups = false,
bool t_optimize_fun_calls = false) {
AST_NodePtr p = m_match_stack.front();
fixup_opers(p);
//Note, optimize_blocks is currently broken; it breaks stack management
if (t_optimize_blocks) { optimize_blocks(p); }
if (t_optimize_returns) { optimize_returns(p); }
if (t_optimize_fun_lookups) { optimize_fun_lookups(p); }
if (t_optimize_fun_calls) { optimize_fun_calls(p); }
return p;
}
/// Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node
void build_match(AST_NodePtr t_t, size_t t_match_start) {
int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop;
@@ -692,7 +813,7 @@ namespace chaiscript
}
/// Reads an argument from input
bool Arg() {
bool Arg(const bool t_type_allowed = true) {
const auto prev_stack_top = m_match_stack.size();
SkipWS();
@@ -701,7 +822,10 @@ namespace chaiscript
}
SkipWS();
Id(true);
if (t_type_allowed) {
Id(true);
}
build_match(std::make_shared<eval::Arg_AST_Node>(), prev_stack_top);
@@ -1120,6 +1244,32 @@ namespace chaiscript
}
}
/// Reads a comma-separated list of values from input. Id's only, no types allowed
bool Id_Arg_List() {
SkipWS(true);
bool retval = false;
const auto prev_stack_top = m_match_stack.size();
if (Arg(false)) {
retval = true;
while (Eol()) {}
if (Char(',')) {
do {
while (Eol()) {}
if (!Arg(false)) {
throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename);
}
} while (Char(','));
}
}
build_match(std::make_shared<eval::Arg_List_AST_Node>(), prev_stack_top);
SkipWS(true);
return retval;
}
/// Reads a comma-separated list of values from input, for function declarations
bool Decl_Arg_List() {
SkipWS(true);
@@ -1138,8 +1288,8 @@ namespace chaiscript
}
} 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);
@@ -1223,13 +1373,26 @@ namespace chaiscript
if (Keyword("fun")) {
retval = true;
if (Char('[')) {
Id_Arg_List();
if (!Char(']')) {
throw exception::eval_error("Incomplete anonymous function bind", File_Position(m_line, m_col), *m_filename);
}
} else {
// make sure we always have the same number of nodes
build_match(std::make_shared<eval::Arg_List_AST_Node>(), prev_stack_top);
}
if (Char('(')) {
Decl_Arg_List();
if (!Char(')')) {
throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename);
}
} else {
throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename);
}
while (Eol()) {}
if (!Block()) {
@@ -1645,6 +1808,10 @@ namespace chaiscript
throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename);
}
if (m_match_stack.size() == prev_stack_top) {
m_match_stack.push_back(std::make_shared<eval::Noop_AST_Node>());
}
build_match(std::make_shared<eval::Block_AST_Node>(), prev_stack_top);
}
@@ -1665,6 +1832,10 @@ namespace chaiscript
throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename);
}
if (m_match_stack.size() == prev_stack_top) {
m_match_stack.push_back(std::make_shared<eval::Noop_AST_Node>());
}
build_match(std::make_shared<eval::Block_AST_Node>(), prev_stack_top);
}

View File

@@ -38,7 +38,24 @@ def eq(l, r) {
def new(x) {
eval(type_name(x))();
}
}
def clone(double x) {
double(x).copy_var_attrs(x)
}
def clone(string x) {
string(x).copy_var_attrs(x)
}
def clone(vector x) {
vector(x).copy_var_attrs(x)
}
def clone(int x) {
int(x).copy_var_attrs(x)
}
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
{