diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 1a16cb8..622bf7a 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -478,6 +478,33 @@ namespace chaiscript return Boxed_Value(f->call_match(std::vector(params.begin() + 1, params.end()))); } + static bool has_guard(const Const_Proxy_Function &t_pf) + { + boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); + if (pf) + { + return pf->get_guard(); + } else { + return false; + } + } + + static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) + { + boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); + if (pf) + { + if (pf->get_guard()) + { + return pf->get_guard(); + } else { + throw std::runtime_error("Function does not have a guard"); + } + } else { + throw std::runtime_error("Function does not have a guard"); + } + } + static void throw_exception(const Boxed_Value &bv) { throw bv; } @@ -562,8 +589,12 @@ namespace chaiscript m->add(fun(&Dynamic_Object::get_type_name), "get_type_name"); m->add(fun(&Dynamic_Object::get_attrs), "get_attrs"); m->add(fun(&Dynamic_Object::get_attr), "get_attr"); + m->eval("def Dynamic_Object::clone() { var new_o := Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }"); + m->add(fun(&has_guard), "has_guard"); + m->add(fun(&get_guard), "get_guard"); + m->add(fun(&Boxed_Value::is_undef), "is_var_undef"); m->add(fun(&Boxed_Value::is_null), "is_var_null"); m->add(fun(&Boxed_Value::is_const), "is_var_const"); diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 112e836..96f7a81 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -108,6 +108,7 @@ namespace chaiscript return m_func->annotation(); } + protected: virtual Boxed_Value do_call(const std::vector ¶ms) const { diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 0710fe7..728428a 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -21,6 +21,10 @@ namespace chaiscript { struct Boxed_POD_Value; + struct AST_Node; + + typedef boost::shared_ptr AST_NodePtr; + /** * Helper for building a list of parameters for calling a Proxy_Function @@ -195,10 +199,11 @@ namespace chaiscript Dynamic_Proxy_Function( const boost::function &)> &t_f, int t_arity=-1, + const AST_NodePtr &t_parsenode = AST_NodePtr(), const std::string &t_description = "", const Proxy_Function &t_guard = Proxy_Function()) : Proxy_Function_Base(build_param_type_list(t_arity)), - m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard) + m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard), m_parsenode(t_parsenode) { } @@ -226,6 +231,11 @@ namespace chaiscript return m_guard; } + AST_NodePtr get_parse_tree() const + { + return m_parsenode; + } + virtual std::string annotation() const { return m_description; @@ -288,6 +298,7 @@ namespace chaiscript int m_arity; std::string m_description; Proxy_Function m_guard; + AST_NodePtr m_parsenode; }; /** diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 91b172e..ff37c7f 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -252,13 +252,15 @@ namespace chaiscript } + const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast) { return t_ast->eval(m_engine); } + /** - * Evaluates the given boxed string, used during eval() inside of a script + * Evaluates the given string, used during eval() inside of a script */ const Boxed_Value internal_eval(const std::string &t_e) { return do_eval(t_e, "__EVAL__", true); diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index a5f3b83..8467c9d 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -550,7 +550,7 @@ namespace chaiscript return Boxed_Value(Proxy_Function(new Dynamic_Proxy_Function (boost::bind(&eval_function, boost::ref(t_ss), this->children.back(), t_param_names, _1), - static_cast(numparams)))); + static_cast(numparams), this->children.back()))); } }; @@ -629,7 +629,7 @@ namespace chaiscript guard = boost::shared_ptr (new Dynamic_Proxy_Function(boost::bind(&eval_function, boost::ref(t_ss), guardnode, - t_param_names, _1), static_cast(numparams))); + t_param_names, _1), static_cast(numparams), guardnode)); } try { @@ -638,7 +638,7 @@ namespace chaiscript t_ss.add(Proxy_Function (new Dynamic_Proxy_Function(boost::bind(&eval_function, boost::ref(t_ss), this->children.back(), - t_param_names, _1), static_cast(numparams), + t_param_names, _1), static_cast(numparams), this->children.back(), annotation, guard)), function_name); } catch (reserved_word_error &e) { @@ -1330,7 +1330,7 @@ namespace chaiscript guard = boost::shared_ptr (new Dynamic_Proxy_Function(boost::bind(&eval_function, boost::ref(t_ss), guardnode, - t_param_names, _1), static_cast(numparams))); + t_param_names, _1), static_cast(numparams), guardnode)); } try { @@ -1342,7 +1342,7 @@ namespace chaiscript (new Dynamic_Object_Constructor(class_name, Proxy_Function (new Dynamic_Proxy_Function(boost::bind(&eval_function, boost::ref(t_ss), this->children.back(), - t_param_names, _1), static_cast(numparams), + t_param_names, _1), static_cast(numparams), this->children.back(), annotation, guard)))), function_name); } @@ -1357,7 +1357,7 @@ namespace chaiscript (new Dynamic_Object_Function(class_name, Proxy_Function (new Dynamic_Proxy_Function(boost::bind(&eval_function, boost::ref(t_ss), this->children.back(), - t_param_names, _1), static_cast(numparams), + t_param_names, _1), static_cast(numparams), this->children.back(), annotation, guard)), ti)), function_name); } diff --git a/src/main.cpp b/src/main.cpp index 9057bdd..24054d4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -151,7 +151,7 @@ int main(int argc, char *argv[]) { std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; for (unsigned int j = 1; j < ee.call_stack.size(); ++j) { std::cout << std::endl; - std::cout << " from " << ee.call_stack[j]->filename << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")"; + std::cout << " from " << *(ee.call_stack[j]->filename) << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")"; } } std::cout << std::endl; diff --git a/src/reflection.cpp b/src/reflection.cpp index ad87148..2a64348 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -11,10 +11,43 @@ #pragma warning(disable : 4190) #endif + +bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) +{ + boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); + if (pf) + { + return pf->get_parse_tree(); + } else { + return false; + } +} + +chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) +{ + boost::shared_ptr pf = boost::dynamic_pointer_cast(t_pf); + if (pf) + { + if (pf->get_parse_tree()) + { + return pf->get_parse_tree(); + } else { + throw std::runtime_error("Function does not have a parse tree"); + } + } else { + throw std::runtime_error("Function does not have a parse tree"); + } +} + + CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflection() { chaiscript::ModulePtr m(new chaiscript::Module()); + m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); + m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); + + chaiscript::bootstrap::vector_type > >("AST_NodeVector", m); CHAISCRIPT_CLASS( m, diff --git a/unittests/function_introspection.chai b/unittests/function_introspection.chai index 7f8e730..bd8bc0b 100644 --- a/unittests/function_introspection.chai +++ b/unittests/function_introspection.chai @@ -48,3 +48,29 @@ 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()); + + +// guard existence tests + +def with_guard(x) : x > 3 {} +def without_guard(x) {} + +def group_guard(x) {} +def group_guard(x) : x > 3 {} + +assert_equal(true, with_guard.has_guard()); +assert_equal(false, without_guard.has_guard()); + +assert_equal(2, group_guard.get_contained_functions().size()); +var group = group_guard.get_contained_functions(); + +assert_equal(true, group[0].has_guard()) +assert_equal(false, group[1].has_guard()) + +assert_throws("Function does not have a guard", fun() { group[0].get_guard(); } ); +assert_throws("Function does not have a guard", fun() { without_guard.get_guard(); } ); + +var guard = with_guard.get_guard(); + +assert_equal(false, guard.has_guard()); +assert_throws("Function does not have a guard", fun() { guard.get_guard(); } ); diff --git a/unittests/reflection_test.chai b/unittests/reflection_test.chai index a9f9472..7841f23 100644 --- a/unittests/reflection_test.chai +++ b/unittests/reflection_test.chai @@ -12,3 +12,22 @@ node.text = "9" assert_equal(eval(a), 13) assert_equal(node.filename, "INPUT") + + + +def my_fun() +{ + return 1; +} + + +assert_equal(true, my_fun.has_parse_tree()); +assert_equal(false, `+`.has_parse_tree()); + +assert_throws("Function does not have a parse tree", fun() { `+`.get_parse_tree(); } ); + +var parsetree := my_fun.get_parse_tree(); + +assert_equal(1, eval(parsetree)); + +print(parsetree.text());