From a8ea5f151d6442559df205af4d02d4e21dd0b7c7 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 25 Jun 2012 06:31:34 -0600 Subject: [PATCH 1/4] Extreme error reporting capabilities update and bug fixes --- include/chaiscript/dispatchkit/bootstrap.hpp | 1 + .../dispatchkit/proxy_functions.hpp | 12 +- .../chaiscript/language/chaiscript_common.hpp | 218 ++++++++++++++++-- .../chaiscript/language/chaiscript_eval.hpp | 179 ++++++++++++-- src/main.cpp | 13 +- 5 files changed, 373 insertions(+), 50 deletions(-) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 426263e..6897dd5 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -426,6 +426,7 @@ namespace chaiscript m->add(fun(&Type_Info::is_void), "is_type_void"); m->add(fun(&Type_Info::is_undef), "is_type_undef"); m->add(fun(&Type_Info::is_pointer), "is_type_pointer"); + m->add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic"); m->add(fun(&Type_Info::name), "cpp_name"); m->add(fun(&Type_Info::bare_name), "cpp_bare_name"); m->add(fun(&Type_Info::bare_equal), "bare_equal"); diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index f28fa60..4008b90 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -25,7 +25,6 @@ namespace chaiscript typedef boost::shared_ptr AST_NodePtr; - namespace dispatch { /** @@ -591,14 +590,16 @@ namespace chaiscript class dispatch_error : public std::runtime_error { public: - dispatch_error(const std::vector &t_bvs) - : std::runtime_error("Error with function dispatch"), parameters(t_bvs) + dispatch_error(const std::vector &t_parameters, + const std::vector &t_functions) + : std::runtime_error("Error with function dispatch"), parameters(t_parameters), functions(t_functions) { } virtual ~dispatch_error() throw() {} std::vector parameters; + std::vector functions; }; } @@ -611,9 +612,10 @@ namespace chaiscript * function is found or throw dispatch_error if no matching function is found */ template - Boxed_Value dispatch(InItr begin, InItr end, + Boxed_Value dispatch(InItr begin, const InItr &end, const std::vector &plist) { + InItr orig(begin); while (begin != end) { try { @@ -632,7 +634,7 @@ namespace chaiscript ++begin; } - throw exception::dispatch_error(plist); + throw exception::dispatch_error(plist, std::vector(orig, end)); } /** diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index fd00c87..911ac95 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -69,18 +69,23 @@ namespace chaiscript File_Position start_position; File_Position end_position; std::string filename; + std::string detail; std::vector call_stack; eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, - const std::vector &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) : - std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_ss)), - reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname) + const std::vector &t_parameters, const std::vector &t_functions, + bool t_dot_notation, + const chaiscript::detail::Dispatch_Engine &t_ss) : + std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)), + reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss)) {} eval_error(const std::string &t_why, - const std::vector &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) : - std::runtime_error(format(t_why, t_parameters, t_ss)), - reason(t_why) + const std::vector &t_parameters, const std::vector &t_functions, + bool t_dot_notation, + const chaiscript::detail::Dispatch_Engine &t_ss) : + std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)), + reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss)) {} @@ -94,19 +99,181 @@ namespace chaiscript reason(t_why) {} + std::string pretty_print() const + { + std::ostringstream ss; + + ss << what(); + if (call_stack.size() > 0) { + ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")" << std::endl; + ss << std::endl << detail << std::endl; + ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'"; + for (size_t j = 1; j < call_stack.size(); ++j) { + if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block + && id(call_stack[j]) != chaiscript::AST_Node_Type::File) + { + ss << std::endl; + ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'"; + } + } + } + ss << std::endl; + return ss.str(); + } + virtual ~eval_error() throw() {} private: + + template + static int id(const T& t) + { + return t->identifier; + } + + template + static std::string pretty(const T& t) + { + return t->pretty_print(); + } + + template + static std::string fname(const T& t) + { + return *t->filename; + } + + template + static std::string startpos(const T& t) + { + std::ostringstream oss; + oss << t->start.line << ", " << t->start.column; + return oss.str(); + } + static std::string format_why(const std::string &t_why) { return "Error: \"" + t_why + "\""; } - static std::string format_parameters(const std::vector &t_parameters, + static std::string format_types(const Const_Proxy_Function &t_func, + bool t_dot_notation, + const chaiscript::detail::Dispatch_Engine &t_ss) + { + int arity = t_func->get_arity(); + std::vector types = t_func->get_param_types(); + + std::string retval; + if (arity == -1) + { + retval = "(...)"; + if (t_dot_notation) + { + retval = "(Object)." + retval; + } + } else if (types.size() <= 1) { + retval = "()"; + } else { + std::stringstream ss; + ss << "("; + + std::string paramstr; + + for (size_t index = 1; + index != types.size(); + ++index) + { + paramstr += (types[index].is_const()?"const ":""); + paramstr += t_ss.get_type_name(types[index]); + + if (index == 1 && t_dot_notation) + { + paramstr += ").("; + if (types.size() == 2) + { + paramstr += ", "; + } + } else { + paramstr += ", "; + } + } + + ss << paramstr.substr(0, paramstr.size() - 2); + + ss << ")"; + retval = ss.str(); + } + + + boost::shared_ptr dynfun + = boost::dynamic_pointer_cast(t_func); + + if (dynfun) + { + Proxy_Function f = dynfun->get_guard(); + + if (f) + { + boost::shared_ptr dynfunguard + = boost::dynamic_pointer_cast(f); + if (dynfunguard) + { + retval += " : " + format_guard(dynfunguard->get_parse_tree()); + } + } + + retval += "\n Defined at " + format_location(dynfun->get_parse_tree()); + } + + return retval; + } + + template + static std::string format_guard(const T &t) + { + return t->pretty_print(); + } + + template + static std::string format_location(const T &t) + { + std::ostringstream oss; + oss << "(" << *t->filename << " " << t->start.line << ", " << t->start.column << ")"; + + return oss.str(); + + } + + static std::string format_detail(const std::vector &t_functions, + bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) { std::stringstream ss; - ss << "With parameters: ("; + if (t_functions.size() == 1) + { + ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl; + } else { + ss << " " << t_functions.size() << " overloads available:" << std::endl; + + for (std::vector::const_iterator itr = t_functions.begin(); + itr != t_functions.end(); + ++itr) + { + ss << " " << format_types((*itr), t_dot_notation, t_ss) << std::endl; + } + + } + + return ss.str(); + + } + + static std::string format_parameters(const std::vector &t_parameters, + bool t_dot_notation, + const chaiscript::detail::Dispatch_Engine &t_ss) + { + std::stringstream ss; + ss << "("; if (!t_parameters.empty()) { @@ -118,7 +285,17 @@ namespace chaiscript { paramstr += (itr->is_const()?"const ":""); paramstr += t_ss.type_name(*itr); - paramstr += ", "; + + if (itr == t_parameters.begin() && t_dot_notation) + { + paramstr += ").("; + if (t_parameters.size() == 1) + { + paramstr += ", "; + } + } else { + paramstr += ", "; + } } ss << paramstr.substr(0, paramstr.size() - 2); @@ -150,14 +327,14 @@ namespace chaiscript } static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, - const std::vector &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) + const std::vector &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) { std::stringstream ss; ss << format_why(t_why); ss << " "; - ss << format_parameters(t_parameters, t_ss); + ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss); ss << " "; ss << format_filename(t_fname); @@ -169,14 +346,16 @@ namespace chaiscript } static std::string format(const std::string &t_why, - const std::vector &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) + const std::vector &t_parameters, + bool t_dot_notation, + const chaiscript::detail::Dispatch_Engine &t_ss) { std::stringstream ss; ss << format_why(t_why); ss << " "; - ss << format_parameters(t_parameters, t_ss); + ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss); ss << " "; return ss.str(); @@ -222,6 +401,19 @@ namespace chaiscript std::vector children; AST_NodePtr annotation; + virtual std::string pretty_print() const + { + std::ostringstream oss; + + oss << text; + + for (unsigned int j = 0; j < this->children.size(); ++j) { + oss << this->children[j]->pretty_print(); + } + + return oss.str(); + } + /** * Prints the contents of an AST node, including its children, recursively */ diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index f78b53c..66a34c7 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -49,6 +49,16 @@ namespace chaiscript this->children[2]->eval(t_ss)); } + virtual std::string pretty_print() const + { + if (children.size() == 3) + { + return "(" + this->children[0]->pretty_print() + " " + this->children[1]->text + " " + this->children[2]->pretty_print() + ")"; + } else { + return "(" + this->children[0]->pretty_print() + " " + text + " " + this->children[1]->pretty_print() + ")"; + } + } + protected: Boxed_Value do_oper(chaiscript::detail::Dispatch_Engine &t_ss, Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) @@ -75,7 +85,7 @@ namespace chaiscript } } catch(const exception::dispatch_error &e){ - throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, t_ss); + throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, t_ss); } } }; @@ -181,6 +191,11 @@ namespace chaiscript Eol_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Eol, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Eol_AST_Node() {} + + virtual std::string pretty_print() const + { + return "\n"; + } }; struct Fun_Call_AST_Node : public AST_Node { @@ -208,13 +223,45 @@ namespace chaiscript return retval; } catch(const exception::dispatch_error &e){ - throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, t_ss); + 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 = boxed_cast(fn); + // handle the case where there is only 1 function to try to call and dispatch fails on it + std::vector funcs; + funcs.push_back(f); + throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", plb.objects, funcs, false, t_ss); + } catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("'" + this->children[0]->text + "' is not a function."); + } + } + catch(const exception::arity_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 + { + std::ostringstream oss; + + for (unsigned int j = 0; j < this->children.size(); ++j) { + oss << this->children[j]->pretty_print(); + + if (j == 0) + { + oss << "("; + } + } + + oss << ")"; + + return oss.str(); + } + }; struct Inplace_Fun_Call_AST_Node : public AST_Node { @@ -231,18 +278,50 @@ namespace chaiscript } } + Boxed_Value bv; + Const_Proxy_Function fn; + try { - return (*boxed_cast(this->children[0]->eval(t_ss)))(plb); + bv = this->children[0]->eval(t_ss); + try { + fn = boxed_cast(bv); + } catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("'" + this->children[0]->text + "' is not a function."); + } + return (*fn)(plb); } catch(const exception::dispatch_error &e){ - throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, t_ss); + 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 &){ + // handle the case where there is only 1 function to try to call and dispatch fails on it + std::vector funcs; + funcs.push_back(fn); + throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", plb.objects, funcs, false, t_ss); + } + catch(const exception::arity_error &e){ + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); } catch(detail::Return_Value &rv) { return rv.retval; } - catch(...) { - throw; + } + + virtual std::string pretty_print() const + { + std::ostringstream oss; + for (unsigned int j = 0; j < this->children.size(); ++j) { + oss << this->children[j]->pretty_print(); + + if (j == 0) + { + oss << "("; + } } + + oss << ")"; + + return oss.str(); } }; @@ -252,6 +331,21 @@ namespace chaiscript Arg_List_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Arg_List, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Arg_List_AST_Node() {} + + virtual std::string pretty_print() const + { + std::ostringstream oss; + for (unsigned int j = 0; j < this->children.size(); ++j) { + if (j != 0) + { + oss << ", "; + } + + oss << this->children[j]->pretty_print(); + } + + return oss.str(); + } }; struct Variable_AST_Node : public AST_Node { @@ -295,11 +389,11 @@ namespace chaiscript retval = t_ss.call_function(this->children[1]->text, lhs, retval); } catch(const exception::dispatch_error &e){ - throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, t_ss); + throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss); } } catch(const exception::dispatch_error &e){ - throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, t_ss); + throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, t_ss); } } else if (this->children[1]->text == ":=") { @@ -313,7 +407,7 @@ namespace chaiscript try { retval = t_ss.call_function(this->children[1]->text, lhs, retval); } catch(const exception::dispatch_error &e){ - throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, t_ss); + throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss); } } } @@ -338,6 +432,11 @@ namespace chaiscript return t_ss.get_object(this->children[0]->text); } + virtual std::string pretty_print() const + { + return "var " + this->children[0]->text; + } + }; struct Comparison_AST_Node : public Binary_Operator_AST_Node { @@ -349,7 +448,7 @@ namespace chaiscript struct Addition_AST_Node : public Binary_Operator_AST_Node { public: - Addition_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Addition, + Addition_AST_Node(const std::string &t_ast_node_text = "+", int t_id = AST_Node_Type::Addition, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } @@ -361,7 +460,7 @@ namespace chaiscript struct Subtraction_AST_Node : public Binary_Operator_AST_Node { public: - Subtraction_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Subtraction, + Subtraction_AST_Node(const std::string &t_ast_node_text = "-", int t_id = AST_Node_Type::Subtraction, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } @@ -373,7 +472,7 @@ namespace chaiscript struct Multiplication_AST_Node : public Binary_Operator_AST_Node { public: - Multiplication_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Multiplication, + Multiplication_AST_Node(const std::string &t_ast_node_text = "*", int t_id = AST_Node_Type::Multiplication, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } @@ -385,7 +484,7 @@ namespace chaiscript struct Division_AST_Node : public Binary_Operator_AST_Node { public: - Division_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Division, + Division_AST_Node(const std::string &t_ast_node_text = "/", int t_id = AST_Node_Type::Division, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } @@ -397,7 +496,7 @@ namespace chaiscript struct Modulus_AST_Node : public Binary_Operator_AST_Node { public: - Modulus_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Modulus, + Modulus_AST_Node(const std::string &t_ast_node_text = "%", int t_id = AST_Node_Type::Modulus, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } @@ -432,12 +531,27 @@ namespace chaiscript throw exception::eval_error("Out of bounds exception"); } catch(const exception::dispatch_error &e){ - throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, t_ss ); + throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, t_ss ); } } return retval; } + + virtual std::string pretty_print() const + { + std::ostringstream oss; + oss << this->children[0]->pretty_print(); + + for (size_t i = 1; i < this->children.size(); ++i) + { + oss << "["; + oss << this->children[i]->pretty_print(); + oss << "]"; + } + + return oss.str(); + } }; struct Dot_Access_AST_Node : public AST_Node { @@ -475,7 +589,12 @@ namespace chaiscript retval = t_ss.call_function(fun_name, plb); } catch(const exception::dispatch_error &e){ - throw exception::eval_error(std::string(e.what()) + " for function: " + fun_name, e.parameters, t_ss); + if (e.functions.empty()) + { + throw exception::eval_error("'" + fun_name + "' is not a function."); + } else { + throw exception::eval_error(std::string(e.what()) + " for function '" + fun_name + "'", e.parameters, e.functions, true, t_ss); + } } catch(detail::Return_Value &rv) { retval = rv.retval; @@ -490,7 +609,7 @@ namespace chaiscript throw exception::eval_error("Out of bounds exception"); } catch(const exception::dispatch_error &e){ - throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, t_ss); + throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, t_ss); } } } @@ -512,6 +631,11 @@ namespace chaiscript return m_value; } + virtual std::string pretty_print() const + { + return "\"" + text + "\""; + } + private: Boxed_Value m_value; @@ -527,6 +651,11 @@ namespace chaiscript return m_value; } + virtual std::string pretty_print() const + { + return "'" + text + "'"; + } + private: Boxed_Value m_value; }; @@ -909,7 +1038,7 @@ namespace chaiscript return const_var(retval); } catch (const exception::dispatch_error &e) { - throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, t_ss); + throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, t_ss); } } @@ -972,7 +1101,7 @@ namespace chaiscript return t_ss.call_function(this->children[0]->text, bv); } } catch (const exception::dispatch_error &e) { - throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, t_ss); + throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, t_ss); } } @@ -1014,7 +1143,7 @@ namespace chaiscript this->children[0]->children[0]->children[1]->eval(t_ss)); } catch (const exception::dispatch_error &e) { - throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, t_ss); + throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, t_ss); } } @@ -1340,6 +1469,11 @@ namespace chaiscript } return retval; } + + virtual std::string pretty_print() const + { + return "(" + AST_Node::pretty_print() + ")"; + } }; struct Logical_Or_AST_Node : public AST_Node { @@ -1367,6 +1501,11 @@ namespace chaiscript return retval; } + virtual std::string pretty_print() const + { + return "(" + AST_Node::pretty_print() + ")"; + } + }; } diff --git a/src/main.cpp b/src/main.cpp index 3cdb09e..aa2abb9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -230,18 +230,7 @@ int main(int argc, char *argv[]) } } catch (const chaiscript::exception::eval_error &ee) { - std::cout << ee.what(); - if (ee.call_stack.size() > 0) { - std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; - for (size_t j = 1; j < ee.call_stack.size(); ++j) { - if (ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::Block - && ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::File) - { - 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 << ee.pretty_print(); std::cout << std::endl; return EXIT_FAILURE; } From 5e6a51ba631843e55200f6433474d60914e1b78b Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 25 Jun 2012 07:44:14 -0600 Subject: [PATCH 2/4] Add failing unit test for remaining error condition to check for. --- CMakeLists.txt | 4 + unittests/expected_eval_errors_test.cpp | 111 ++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 unittests/expected_eval_errors_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b0ffc54..8f21280 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,6 +192,10 @@ if(BUILD_TESTING) target_link_libraries(short_comparison_test ${LIBS}) add_test(NAME Short_Comparison_Test COMMAND short_comparison_test) + add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp) + target_link_libraries(expected_eval_errors_test ${LIBS}) + add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test) + add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp unittests/multifile_test_module.cpp) diff --git a/unittests/expected_eval_errors_test.cpp b/unittests/expected_eval_errors_test.cpp new file mode 100644 index 0000000..698639a --- /dev/null +++ b/unittests/expected_eval_errors_test.cpp @@ -0,0 +1,111 @@ +// Tests to make sure no arity, dispatch or guard errors leak up past eval + +#include + +int test_one(const int &) +{ + return 1; +} + +int main() +{ + chaiscript::ChaiScript chai; + chai.add(chaiscript::fun(&test_one), "test_fun"); + + chai.eval("def guard_fun(i) : i.get_type_info().is_type_arithmetic() {} "); + + bool eval_error = true; + + // Dot notation + + try { + // non-existant function + chai.eval("\"test\".test_one()"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + try { + // wrong parameter type + chai.eval("\"test\".test_fun()"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + try { + // wrong number of parameters + chai.eval("\"test\".test_fun(1)"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + try { + // guard failure + chai.eval("\"test\".guard_fun(1)"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + + + // regular notation + + try { + // non-existant function + chai.eval("test_one(\"test\")"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + try { + // wrong parameter type + chai.eval("test_fun(\"test\")"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + try { + // wrong number of parameters + chai.eval("test_fun(\"test\")"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + try { + // guard failure + chai.eval("guard_fun(\"test\")"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + + // index operator + try { + chai.eval("var a = [1,2,3]; a[\"bob\"];"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + // unary operator + try { + chai.eval("++\"bob\""); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + // binary operator + try { + chai.eval("\"bob\" + 1"); + eval_error = false; + } catch (const chaiscript::exception::eval_error &) { + } + + + if (eval_error) + { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + +} From 7a25625fddc1fe3fc402ebff5a45cd5153276017 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 25 Jun 2012 07:53:15 -0600 Subject: [PATCH 3/4] Fix failing error reporting for solitary (non-dispatched) guarded function --- include/chaiscript/language/chaiscript_eval.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 66a34c7..4d21147 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -239,6 +239,9 @@ namespace chaiscript 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; } @@ -302,6 +305,9 @@ namespace chaiscript 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; } From 39d817469ce60d2d21a98fd9b9c31eaaac154b83 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 25 Jun 2012 08:05:58 -0600 Subject: [PATCH 4/4] Optionally allow the user to specify the file name to report to end users when calling "eval" --- include/chaiscript/language/chaiscript_engine.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index b970d12..4f61f31 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -652,6 +652,8 @@ namespace chaiscript /// \tparam T Type to extract from the result value of the script execution /// \param[in] t_input Script to execute /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions + /// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful + /// in special cases where you are loading a file internally instead of using eval_file /// /// \return result of the script execution /// @@ -659,10 +661,10 @@ namespace chaiscript /// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted /// to the requested type. template - T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler()) + T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__") { try { - return boxed_cast(do_eval(t_input)); + return boxed_cast(do_eval(t_input, t_filename)); } catch (Boxed_Value &bv) { if (t_handler) { t_handler->handle(bv); @@ -675,14 +677,16 @@ namespace chaiscript /// /// \param[in] t_input Script to execute /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions + /// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful + /// in special cases where you are loading a file internally instead of using eval_file /// /// \return result of the script execution /// /// \throw exception::eval_error In the case that evaluation fails. - Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler()) + Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__") { try { - return do_eval(t_input); + return do_eval(t_input, t_filename); } catch (Boxed_Value &bv) { if (t_handler) { t_handler->handle(bv);