diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 9d69120a..aefa0644 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -7,6 +7,8 @@ #ifndef _CHAISCRIPT_COMMON_HPP #define _CHAISCRIPT_COMMON_HPP +#include + namespace chaiscript { typedef ModulePtr (*Create_Module_Func)(); @@ -65,9 +67,6 @@ namespace chaiscript std::vector children; TokenPtr annotation; - Token(const std::string &token_text, int id, const char *fname) : - text(token_text), identifier(id), filename(fname), is_cached(false) { } - Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : text(token_text), identifier(id), filename(fname), is_cached(false) { @@ -76,6 +75,298 @@ namespace chaiscript end.line = end_line; end.column = end_col; } + Token(const std::string &token_text, int id, const char *fname) : + text(token_text), identifier(id), filename(fname), is_cached(false) { } + + + void cache_const(const Boxed_Value &value) { + this->cached_value = value; + this->is_cached = true; + } + + virtual Boxed_Value eval(Dispatch_Engine &) { + Boxed_Value bv; + throw std::runtime_error("Undispatched token (internal error)"); + return bv; + } + }; + + struct Error_Token : public Token { + public: + Error_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Int_Token : public Token { + public: + Int_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Float_Token : public Token { + public: + Float_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Id_Token : public Token { + public: + Id_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Char_Token : public Token { + public: + Char_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Str_Token : public Token { + public: + Str_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Eol_Token : public Token { + public: + Eol_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Fun_Call_Token : public Token { + public: + Fun_Call_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Inplace_Fun_Call_Token : public Token { + public: + Inplace_Fun_Call_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Arg_List_Token : public Token { + public: + Arg_List_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Variable_Token : public Token { + public: + Variable_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Equation_Token : public Token { + public: + Equation_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Var_Decl_Token : public Token { + public: + Var_Decl_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Comparison_Token : public Token { + public: + Comparison_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Additive_Token : public Token { + public: + Additive_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Multiplicative_Token : public Token { + public: + Multiplicative_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Array_Call_Token : public Token { + public: + Array_Call_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Dot_Access_Token : public Token { + public: + Dot_Access_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Quoted_String_Token : public Token { + public: + Quoted_String_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Single_Quoted_String_Token : public Token { + public: + Single_Quoted_String_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Lambda_Token : public Token { + public: + Lambda_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Block_Token : public Token { + public: + Block_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Def_Token : public Token { + public: + Def_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct While_Token : public Token { + public: + While_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct If_Token : public Token { + public: + If_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct For_Token : public Token { + public: + For_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Inline_Array_Token : public Token { + public: + Inline_Array_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Inline_Map_Token : public Token { + public: + Inline_Map_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Return_Token : public Token { + public: + Return_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct File_Token : public Token { + public: + File_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Prefix_Token : public Token { + public: + Prefix_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Break_Token : public Token { + public: + Break_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Map_Pair_Token : public Token { + public: + Map_Pair_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Value_Range_Token : public Token { + public: + Value_Range_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Inline_Range_Token : public Token { + public: + Inline_Range_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Annotation_Token : public Token { + public: + Annotation_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Try_Token : public Token { + public: + Try_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Catch_Token : public Token { + public: + Catch_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Finally_Token : public Token { + public: + Finally_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + }; + struct Method_Token : public Token { + public: + Method_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Attr_Decl_Token : public Token { + public: + Attr_Decl_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Shift_Token : public Token { + public: + Shift_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Equality_Token : public Token { + public: + Equality_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Bitwise_And_Token : public Token { + public: + Bitwise_And_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Bitwise_Xor_Token : public Token { + public: + Bitwise_Xor_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Bitwise_Or_Token : public Token { + public: + Bitwise_Or_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Logical_And_Token : public Token { + public: + Logical_And_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); + }; + struct Logical_Or_Token : public Token { + public: + Logical_Or_Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) : + Token(token_text, id, fname, start_line, start_col, end_line, end_col) { } + Boxed_Value eval(Dispatch_Engine &ss); }; /** @@ -86,6 +377,7 @@ namespace chaiscript File_Position start_position; File_Position end_position; const char *filename; + std::vector call_stack; Eval_Error(const std::string &why, const File_Position &where, const char *fname) : std::runtime_error("Error: \"" + why + "\" " + @@ -95,13 +387,9 @@ namespace chaiscript reason(why), start_position(where), end_position(where), filename(fname) { } - Eval_Error(const std::string &why, const TokenPtr &where) - : std::runtime_error("Error: \"" + why + "\" " + - (std::string(where->filename) != "__EVAL__" ? ("in '" + std::string(where->filename) + "' ") : "during evaluation ") + - "at (" + boost::lexical_cast(where->start.line) + ", " + - boost::lexical_cast(where->start.column) + ")"), - reason(why), start_position(where->start), end_position(where->end), filename(where->filename) { - } + Eval_Error(const std::string &why) + : std::runtime_error("Error: \"" + why + "\" "), + reason(why) {} virtual ~Eval_Error() throw() {} }; @@ -123,18 +411,15 @@ namespace chaiscript */ struct Return_Value { Boxed_Value retval; - TokenPtr location; - Return_Value(const Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { } + Return_Value(const Boxed_Value &return_value) : retval(return_value) { } }; /** * Special type indicating a call to 'break' */ struct Break_Loop { - TokenPtr location; - - Break_Loop(const TokenPtr where) : location(where) { } + Break_Loop() { } }; } diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 9677ea00..c9ec792c 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -263,7 +263,7 @@ namespace chaiscript l.unlock(); #endif //parser.show_match_stack(); - value = eval_token(engine, parser.ast()); + value = parser.ast()->eval(engine);//eval_token(engine, parser.ast()); } } catch (const Return_Value &rv) { @@ -281,7 +281,7 @@ namespace chaiscript if (parser.parse(input, fname)) { //parser.show_match_stack(); - value = eval_token(engine, parser.ast()); + value = parser.ast()->eval(engine); } } catch (const Return_Value &rv) { diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index dc48fe9f..17d499ae 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -25,12 +25,16 @@ namespace chaiscript } try { - Boxed_Value retval(eval_token(ss, node)); + Boxed_Value retval(node->eval(ss)); ss.pop_scope(); return retval; } catch (const Return_Value &rv) { ss.pop_scope(); return rv.retval; + } catch (Eval_Error &ee) { + ee.call_stack.push_back(node); + ss.pop_scope(); + throw; } catch (...) { ss.pop_scope(); throw; @@ -40,64 +44,57 @@ namespace chaiscript /** * Evaluates the top-level file node */ - template - Boxed_Value eval_file(Eval_System &ss, const TokenPtr &node) { - const unsigned int size = node->children.size(); + Boxed_Value File_Token::eval(Dispatch_Engine &ss) { + const unsigned int size = this->children.size(); for (unsigned int i = 0; i < size; ++i) { - const Boxed_Value &retval = eval_token(ss, node->children[i]); - if (i + 1 == size) - { + try { + const Boxed_Value &retval = this->children[i]->eval(ss); + if (i + 1 == size) { return retval; } + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i]); + throw; + } } return Boxed_Value(); } - template - void cache_const(Eval_System &/*ss*/, const TokenPtr &node, const Boxed_Value &value) { - node->cached_value = value; - node->is_cached = true; - } /** * Evaluates a variable or function name identifier */ - template - Boxed_Value eval_id(Eval_System &ss, const TokenPtr &node) { - - if (node->text == "true") { - //return const_var(true); - if (!node->is_cached) { - cache_const(ss, node, const_var(true)); + Boxed_Value Id_Token::eval(Dispatch_Engine &ss) { + if (this->text == "true") { + if (!this->is_cached) { + cache_const(const_var(true)); } - return node->cached_value; + return this->cached_value; } - else if (node->text == "false") { - //return const_var(false); - if (!node->is_cached) { - cache_const(ss, node, const_var(false)); + else if (this->text == "false") { + if (!this->is_cached) { + cache_const(const_var(false)); } - return node->cached_value; + return this->cached_value; } - else if (node->text == "Infinity") { - //return const_var(false); - if (!node->is_cached) { - cache_const(ss, node, const_var(std::numeric_limits::infinity())); + else if (this->text == "Infinity") { + if (!this->is_cached) { + cache_const(const_var(std::numeric_limits::infinity())); } - return node->cached_value; + return this->cached_value; } - else if (node->text == "NaN") { - //return const_var(false); - if (!node->is_cached) { - cache_const(ss, node, const_var(std::numeric_limits::quiet_NaN())); + else if (this->text == "NaN") { + if (!this->is_cached) { + cache_const(const_var(std::numeric_limits::quiet_NaN())); } - return node->cached_value; + return this->cached_value; } else { try { - return ss.get_object(node->text); + return ss.get_object(this->text); } catch (std::exception &) { - throw Eval_Error("Can not find object: " + node->text, node); + throw Eval_Error("Can not find object: " + this->text); } } } @@ -105,34 +102,27 @@ namespace chaiscript /** * Evaluates a floating point number */ - template - Boxed_Value eval_float(Eval_System &ss, const TokenPtr &node) { - //return const_var(double(atof(node->text.c_str()))); - - if (!node->is_cached) { - cache_const(ss, node, const_var(double(atof(node->text.c_str())))); + Boxed_Value Float_Token::eval(Dispatch_Engine &) { + if (!this->is_cached) { + cache_const(const_var(double(atof(this->text.c_str())))); } - return node->cached_value; + return this->cached_value; } /** * Evaluates an integer */ - template - Boxed_Value eval_int(Eval_System &ss, const TokenPtr &node) { - //return const_var(atoi(node->text.c_str())); - - if (!node->is_cached) { - cache_const(ss, node, const_var(int(atoi(node->text.c_str())))); + Boxed_Value Int_Token::eval(Dispatch_Engine &) { + if (!this->is_cached) { + cache_const(const_var(int(atoi(this->text.c_str())))); } - return node->cached_value; + return this->cached_value; } /** * Evaluates a quoted string */ - template - Boxed_Value eval_quoted_string(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Quoted_String_Token::eval(Dispatch_Engine &) { //return const_var(node->text); /* @@ -144,67 +134,89 @@ namespace chaiscript return ss.call_function("eval", plb); } */ - if (!node->is_cached) { - cache_const(ss, node, const_var(node->text)); + if (!this->is_cached) { + cache_const(const_var(this->text)); } - return node->cached_value; + return this->cached_value; } /** * Evaluates a char group */ - template - Boxed_Value eval_single_quoted_string(Eval_System &ss, const TokenPtr &node) { - if (!node->is_cached) { - cache_const(ss, node, const_var(char(node->text[0]))); + + Boxed_Value Single_Quoted_String_Token::eval(Dispatch_Engine &) { + if (!this->is_cached) { + cache_const(const_var(char(this->text[0]))); } - return node->cached_value; + return this->cached_value; } /** * Evaluates a string of equations in reverse order so that the right-most side has precedence */ - template - Boxed_Value eval_equation(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Equation_Token::eval(Dispatch_Engine &ss) { int i; - Boxed_Value retval = eval_token(ss, node->children.back()); - if (node->children.size() > 1) { - for (i = node->children.size()-3; i >= 0; i -= 2) { - if (node->children[i+1]->text == "=") { - Boxed_Value lhs = eval_token(ss, node->children[i]); - + Boxed_Value retval; + try { + retval = this->children.back()->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children.back()); + throw; + } + + if (this->children.size() > 1) { + for (i = this->children.size()-3; i >= 0; i -= 2) { + if (this->children[i+1]->text == "=") { try { - if (lhs.is_undef()) - { + Boxed_Value lhs = this->children[i]->eval(ss); + + try { + if (lhs.is_undef()) { retval = ss.call_function("clone", retval); } - try { - retval = ss.call_function(node->children[i+1]->text, lhs, retval); + try { + retval = ss.call_function(this->children[i+1]->text, lhs, retval); + } + catch(const dispatch_error &){ + throw Eval_Error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); + } } catch(const dispatch_error &){ - throw Eval_Error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":"."), node->children[i+1]); + throw Eval_Error("Can not clone right hand side of equation"); } } - catch(const dispatch_error &){ - throw Eval_Error("Can not clone right hand side of equation", node->children[i+1]); + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i]); + throw; } } - else if (node->children[i+1]->text == ":=") { - Boxed_Value lhs = eval_token(ss, node->children[i]); - if (lhs.is_undef() || type_match(lhs, retval)) { - lhs.assign(retval); + else if (this->children[i+1]->text == ":=") { + try { + Boxed_Value lhs = this->children[i]->eval(ss); + if (lhs.is_undef() || type_match(lhs, retval)) { + lhs.assign(retval); + } + else { + throw Eval_Error("Mismatched types in equation"); + } } - else { - throw Eval_Error("Mismatched types in equation", node->children[i+1]); + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i]); + throw; } } else { try { - retval = ss.call_function(node->children[i+1]->text, eval_token(ss, node->children[i]), retval); + retval = ss.call_function(this->children[i+1]->text, this->children[i]->eval(ss), retval); } catch(const dispatch_error &){ - throw Eval_Error("Can not find appropriate '" + node->children[i+1]->text + "'", node->children[i+1]); + throw Eval_Error("Can not find appropriate '" + this->children[i+1]->text + "'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i]); + throw; } } } @@ -215,29 +227,27 @@ namespace chaiscript /** * Evaluates a variable declaration */ - template - Boxed_Value eval_var_decl(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Var_Decl_Token::eval(Dispatch_Engine &ss) { try { - ss.add_object(node->children[0]->text, Boxed_Value()); + ss.add_object(this->children[0]->text, Boxed_Value()); } catch (reserved_word_error &) { - throw Eval_Error("Reserved word used as variable '" + node->children[0]->text + "'", node); + throw Eval_Error("Reserved word used as variable '" + this->children[0]->text + "'"); } - return ss.get_object(node->children[0]->text); + return ss.get_object(this->children[0]->text); } /** * Evaluates an attribute declaration */ - template - Boxed_Value eval_attr_decl(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Attr_Decl_Token::eval(Dispatch_Engine &ss) { try { - ss.add(fun(boost::function(boost::bind(&Dynamic_Object_Attribute::func, node->children[0]->text, - node->children[1]->text, _1))), node->children[1]->text); + ss.add(fun(boost::function(boost::bind(&Dynamic_Object_Attribute::func, this->children[0]->text, + this->children[1]->text, _1))), this->children[1]->text); } catch (reserved_word_error &) { - throw Eval_Error("Reserved word used as attribute '" + node->children[1]->text + "'", node); + throw Eval_Error("Reserved word used as attribute '" + this->children[1]->text + "'"); } return Boxed_Value(); } @@ -245,34 +255,107 @@ namespace chaiscript /** * Evaluates binary boolean operators. Respects short-circuiting rules. */ - template - Boxed_Value eval_logical(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Logical_And_Token::eval(Dispatch_Engine &ss) { unsigned int i; - Boxed_Value retval(eval_token(ss, node->children[0])); - if (node->children.size() > 1) { - for (i = 1; i < node->children.size(); i += 2) { + Boxed_Value retval; + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + if (this->children.size() > 1) { + for (i = 1; i < this->children.size(); i += 2) { bool lhs; try { lhs = boxed_cast(retval); } catch (const bad_boxed_cast &) { - throw Eval_Error("Condition not boolean", node); + throw Eval_Error("Condition not boolean"); } - if (node->children[i]->text == "&&") { + if (this->children[i]->text == "&&") { if (lhs) { - retval = eval_token(ss, node->children[i+1]); + try { + retval = this->children[i+1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } } else { retval = Boxed_Value(false); } } - else if (node->children[i]->text == "||") { + else if (this->children[i]->text == "||") { if (lhs) { retval = Boxed_Value(true); } else { - retval = eval_token(ss, node->children[i+1]); + try { + retval = this->children[i+1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + } + } + } + return retval; + } + + Boxed_Value Logical_Or_Token::eval(Dispatch_Engine &ss) { + unsigned int i; + Boxed_Value retval; + + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + if (this->children.size() > 1) { + for (i = 1; i < this->children.size(); i += 2) { + bool lhs; + try { + lhs = boxed_cast(retval); + } + catch (const bad_boxed_cast &) { + throw Eval_Error("Condition not boolean"); + } + if (this->children[i]->text == "&&") { + if (lhs) { + try { + retval = this->children[i+1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + else { + retval = Boxed_Value(false); + } + } + else if (this->children[i]->text == "||") { + if (lhs) { + retval = Boxed_Value(true); + } + else { + try { + retval = this->children[i+1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } } } } @@ -283,17 +366,217 @@ namespace chaiscript /** * Evaluates comparison, additions, and multiplications and their relatives */ - template - Boxed_Value eval_comp_add_mul(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Bitwise_And_Token::eval(Dispatch_Engine &ss) { unsigned int i; + Boxed_Value retval; - Boxed_Value retval = eval_token(ss, node->children[0]); - for (i = 1; i < node->children.size(); i += 2) { + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + for (i = 1; i < this->children.size(); i += 2) { try { - retval = ss.call_function(node->children[i]->text, retval, eval_token(ss, node->children[i + 1])); + retval = ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(ss)); } catch(const dispatch_error &){ - throw Eval_Error("Can not find appropriate '" + node->children[i]->text + "'", node->children[i]); + throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + + return retval; + } + Boxed_Value Bitwise_Xor_Token::eval(Dispatch_Engine &ss) { + unsigned int i; + Boxed_Value retval; + + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + for (i = 1; i < this->children.size(); i += 2) { + try { + retval = ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(ss)); + } + catch(const dispatch_error &){ + throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + + return retval; + } + Boxed_Value Bitwise_Or_Token::eval(Dispatch_Engine &ss) { + unsigned int i; + Boxed_Value retval; + + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + for (i = 1; i < this->children.size(); i += 2) { + try { + retval = ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(ss)); + } + catch(const dispatch_error &){ + throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + + return retval; + } + Boxed_Value Additive_Token::eval(Dispatch_Engine &ss) { + unsigned int i; + Boxed_Value retval; + + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + for (i = 1; i < this->children.size(); i += 2) { + try { + retval = ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(ss)); + } + catch(const dispatch_error &){ + throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + + return retval; + } + Boxed_Value Multiplicative_Token::eval(Dispatch_Engine &ss) { + unsigned int i; + Boxed_Value retval; + + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + for (i = 1; i < this->children.size(); i += 2) { + try { + retval = ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(ss)); + } + catch(const dispatch_error &){ + throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + + return retval; + } + Boxed_Value Comparison_Token::eval(Dispatch_Engine &ss) { + unsigned int i; + Boxed_Value retval; + + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + for (i = 1; i < this->children.size(); i += 2) { + try { + retval = ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(ss)); + } + catch(const dispatch_error &){ + throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + + return retval; + } + Boxed_Value Equality_Token::eval(Dispatch_Engine &ss) { + unsigned int i; + Boxed_Value retval; + + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + for (i = 1; i < this->children.size(); i += 2) { + try { + retval = ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(ss)); + } + catch(const dispatch_error &){ + throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + + return retval; + } + Boxed_Value Shift_Token::eval(Dispatch_Engine &ss) { + unsigned int i; + Boxed_Value retval; + + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + for (i = 1; i < this->children.size(); i += 2) { + try { + retval = ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(ss)); + } + catch(const dispatch_error &){ + throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; } } @@ -303,20 +586,31 @@ namespace chaiscript /** * Evaluates an array lookup */ - template - Boxed_Value eval_array_call(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Array_Call_Token::eval(Dispatch_Engine &ss) { unsigned int i; + Boxed_Value retval; - Boxed_Value retval = eval_token(ss, node->children[0]); - for (i = 1; i < node->children.size(); ++i) { + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + for (i = 1; i < this->children.size(); ++i) { try { - retval = ss.call_function("[]", retval, eval_token(ss, node->children[i])); + retval = ss.call_function("[]", retval, this->children[i]->eval(ss)); } catch(std::out_of_range &) { - throw Eval_Error("Out of bounds exception", node); + throw Eval_Error("Out of bounds exception"); } catch(const dispatch_error &){ - throw Eval_Error("Can not find appropriate array lookup '[]' " + node->children[i]->text, node->children[i]); + throw Eval_Error("Can not find appropriate array lookup '[]' "); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[i]); + throw; } } @@ -326,32 +620,34 @@ namespace chaiscript /** * Evaluates any unary prefix */ - template - Boxed_Value eval_prefix(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Prefix_Token::eval(Dispatch_Engine &ss) { try { - return ss.call_function(node->children[0]->text, eval_token(ss, node->children[1])); + return ss.call_function(this->children[0]->text, this->children[1]->eval(ss)); } catch(std::exception &){ - throw Eval_Error("Can not find appropriate unary '" + node->children[0]->text + "'", node->children[0]); + throw Eval_Error("Can not find appropriate unary '" + this->children[0]->text + "'"); } } /** * Evaluates (and generates) an inline array initialization */ - template - Boxed_Value eval_inline_array(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Inline_Array_Token::eval(Dispatch_Engine &ss) { unsigned int i; try { Boxed_Value retval = ss.call_function("Vector"); - if (node->children.size() > 0) { - for (i = 0; i < node->children[0]->children.size(); ++i) { + if (this->children.size() > 0) { + for (i = 0; i < this->children[0]->children.size(); ++i) { try { - ss.call_function("push_back", retval, eval_token(ss, node->children[0]->children[i])); + ss.call_function("push_back", retval, this->children[0]->children[i]->eval(ss)); } catch (const dispatch_error &) { - throw Eval_Error("Can not find appropriate 'push_back'", node->children[0]->children[i]); + throw Eval_Error("Can not find appropriate 'push_back'"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]->children[i]); + throw; } } } @@ -359,7 +655,7 @@ namespace chaiscript return retval; } catch (const dispatch_error &) { - throw Eval_Error("Can not find appropriate 'Vector()'", node); + throw Eval_Error("Can not find appropriate 'Vector()'"); } } @@ -367,62 +663,73 @@ namespace chaiscript /** * Evaluates (and generates) an inline range initialization */ - template - Boxed_Value eval_inline_range(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Inline_Range_Token::eval(Dispatch_Engine &ss) { try { - return ss.call_function("generate_range", - eval_token(ss, node->children[0]->children[0]->children[0]), - eval_token(ss, node->children[0]->children[0]->children[1])); + return ss.call_function("generate_range", + this->children[0]->children[0]->children[0]->eval(ss), + this->children[0]->children[0]->children[1]->eval(ss)); } catch (const dispatch_error &) { - throw Eval_Error("Unable to generate range vector", node); + throw Eval_Error("Unable to generate range vector"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]->children[0]); + throw; } } /** * Evaluates (and generates) an inline map initialization */ - template - Boxed_Value eval_inline_map(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Inline_Map_Token::eval(Dispatch_Engine &ss) { unsigned int i; try { Boxed_Value retval = ss.call_function("Map"); - for (i = 0; i < node->children[0]->children.size(); ++i) { + for (i = 0; i < this->children[0]->children.size(); ++i) { try { Boxed_Value slot - = ss.call_function("[]", retval, eval_token(ss, node->children[0]->children[i]->children[0])); - ss.call_function("=", slot, eval_token(ss, node->children[0]->children[i]->children[1])); + = ss.call_function("[]", retval, this->children[0]->children[i]->children[0]->eval(ss)); + ss.call_function("=", slot, this->children[0]->children[i]->children[1]->eval(ss)); } catch (const dispatch_error &) { - throw Eval_Error("Can not find appropriate '=' for map init", node->children[0]->children[i]); + throw Eval_Error("Can not find appropriate '=' for map init"); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]->children[i]); + throw; } } return retval; } catch (const dispatch_error &) { - throw Eval_Error("Can not find appropriate 'Map()'", node); + throw Eval_Error("Can not find appropriate 'Map()'"); } } /** * Evaluates a function call, starting with its arguments. Handles resetting the scope to the previous one after the call. */ - template - Boxed_Value eval_fun_call(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Fun_Call_Token::eval(Dispatch_Engine &ss) { Param_List_Builder plb; Dispatch_Engine::Stack prev_stack = ss.get_stack(); Dispatch_Engine::Stack new_stack = ss.new_stack(); unsigned int i; - if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) { - for (i = 0; i < node->children[1]->children.size(); ++i) { - plb << eval_token(ss, node->children[1]->children[i]); + if ((this->children.size() > 1) && (this->children[1]->identifier == Token_Type::Arg_List)) { + for (i = 0; i < this->children[1]->children.size(); ++i) { + try { + plb << this->children[1]->children[i]->eval(ss); + } + catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[1]->children[i]); + throw; + } } } try { - Boxed_Value fn = eval_token(ss, node->children[0]); + Boxed_Value fn = this->children[0]->eval(ss); try { ss.set_stack(new_stack); @@ -432,7 +739,7 @@ namespace chaiscript } catch(const dispatch_error &e){ ss.set_stack(prev_stack); - throw Eval_Error(std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]); + throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); } catch(Return_Value &rv) { ss.set_stack(prev_stack); @@ -444,8 +751,9 @@ namespace chaiscript } } catch(Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); ss.set_stack(prev_stack); - throw Eval_Error(ee.reason, node->children[0]); + throw Eval_Error(ee.reason); } } @@ -453,25 +761,30 @@ namespace chaiscript /** * Evaluates a function call, starting with its arguments. Does NOT change scope. */ - template - Boxed_Value eval_inplace_fun_call(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Inplace_Fun_Call_Token::eval(Dispatch_Engine &ss) { Param_List_Builder plb; unsigned int i; - if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) { - for (i = 0; i < node->children[1]->children.size(); ++i) { - plb << eval_token(ss, node->children[1]->children[i]); + if ((this->children.size() > 1) && (this->children[1]->identifier == Token_Type::Arg_List)) { + for (i = 0; i < this->children[1]->children.size(); ++i) { + try { + plb << this->children[1]->children[i]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[1]->children[i]); + throw; + } } } try { - Boxed_Value fn = eval_token(ss, node->children[0]); + Boxed_Value fn = this->children[0]->eval(ss); try { return (*boxed_cast(fn))(plb); } catch(const dispatch_error &e){ - throw Eval_Error(std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]); + throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); } catch(Return_Value &rv) { return rv.retval; @@ -481,7 +794,8 @@ namespace chaiscript } } catch(Eval_Error &ee) { - throw Eval_Error(ee.reason, node->children[0]); + ee.call_stack.push_back(this->children[0]); + throw Eval_Error(ee.reason); } } @@ -489,33 +803,44 @@ namespace chaiscript /** * Evaluates a method/attributes invocation */ - template - Boxed_Value eval_dot_access(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Dot_Access_Token::eval(Dispatch_Engine &ss) { Dispatch_Engine::Stack prev_stack = ss.get_stack(); Dispatch_Engine::Stack new_stack = ss.new_stack(); unsigned int i, j; - //todo: Please extract a single way of doing function calls between this and eval_fun_call - - Boxed_Value retval(eval_token(ss, node->children[0])); - if (node->children.size() > 1) { - for (i = 2; i < node->children.size(); i+=2) { + Boxed_Value retval; + try { + retval = this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + if (this->children.size() > 1) { + for (i = 2; i < this->children.size(); i+=2) { Param_List_Builder plb; plb << retval; - if (node->children[i]->children.size() > 1) { - for (j = 0; j < node->children[i]->children[1]->children.size(); ++j) { - plb << eval_token(ss, node->children[i]->children[1]->children[j]); + if (this->children[i]->children.size() > 1) { + for (j = 0; j < this->children[i]->children[1]->children.size(); ++j) { + try { + plb << this->children[i]->children[1]->children[j]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i]->children[1]->children[j]); + throw; + } } } std::string fun_name; std::vector > funs; - if (node->children[i]->identifier == Token_Type::Fun_Call) { - fun_name = node->children[i]->children[0]->text; + if (this->children[i]->identifier == Token_Type::Fun_Call) { + fun_name = this->children[i]->children[0]->text; } else { - fun_name = node->children[i]->text; + fun_name = this->children[i]->text; } try { @@ -525,7 +850,7 @@ namespace chaiscript } catch(const dispatch_error &e){ ss.set_stack(prev_stack); - throw Eval_Error(std::string(e.what()), node->children[i]); + throw Eval_Error(std::string(e.what())); } catch(Return_Value &rv) { ss.set_stack(prev_stack); @@ -544,17 +869,24 @@ namespace chaiscript /** * Evaluates an if/elseif/else block */ - template - Boxed_Value eval_try(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Try_Token::eval(Dispatch_Engine &ss) { Boxed_Value retval; ss.new_scope(); try { - retval = eval_token(ss, node->children[0]); + retval = this->children[0]->eval(ss); } - catch (const Eval_Error &) { - if (node->children.back()->identifier == Token_Type::Finally) { - eval_token(ss, node->children.back()->children[0]); + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + if (this->children.back()->identifier == Token_Type::Finally) { + try { + this->children.back()->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children.back()->children[0]); + ss.pop_scope(); + throw; + } } ss.pop_scope(); throw; @@ -562,22 +894,35 @@ namespace chaiscript catch (const std::exception &e) { Boxed_Value except = Boxed_Value(boost::ref(e)); - unsigned int end_point = node->children.size(); - if (node->children.back()->identifier == Token_Type::Finally) { - end_point = node->children.size() - 1; + unsigned int end_point = this->children.size(); + if (this->children.back()->identifier == Token_Type::Finally) { + end_point = this->children.size() - 1; } for (unsigned int i = 1; i < end_point; ++i) { - TokenPtr catch_block = node->children[i]; + TokenPtr catch_block = this->children[i]; if (catch_block->children.size() == 1) { //No variable capture, no guards - retval = eval_token(ss, catch_block->children[0]); + try { + retval = catch_block->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(catch_block->children[0]); + throw; + } break; } else if (catch_block->children.size() == 2) { //Variable capture, no guards ss.add_object(catch_block->children[0]->text, except); - retval = eval_token(ss, catch_block->children[1]); + try { + retval = catch_block->children[1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(catch_block->children[1]); + throw; + } + break; } else if (catch_block->children.size() == 3) { @@ -586,42 +931,77 @@ namespace chaiscript bool guard; try { - guard = boxed_cast(eval_token(ss, catch_block->children[1])); + guard = boxed_cast(catch_block->children[1]->eval(ss)); } catch (const bad_boxed_cast &) { - if (node->children.back()->identifier == Token_Type::Finally) { - eval_token(ss, node->children.back()->children[0]); + if (this->children.back()->identifier == Token_Type::Finally) { + try { + this->children.back()->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children.back()->children[0]); + ss.pop_scope(); + throw; + } } ss.pop_scope(); - throw Eval_Error("Guard condition not boolean", catch_block->children[1]); + throw Eval_Error("Guard condition not boolean"); } if (guard) { - retval = eval_token(ss, catch_block->children[2]); + try { + retval = catch_block->children[2]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(catch_block->children[2]); + throw; + } + break; } } else { - if (node->children.back()->identifier == Token_Type::Finally) { - eval_token(ss, node->children.back()->children[0]); + if (this->children.back()->identifier == Token_Type::Finally) { + try { + this->children.back()->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children.back()->children[0]); + ss.pop_scope(); + throw; + } } ss.pop_scope(); - throw Eval_Error("Internal error: catch block size unrecognized", catch_block); + throw Eval_Error("Internal error: catch block size unrecognized"); } } } catch (Boxed_Value &bv) { Boxed_Value except = bv; - for (unsigned int i = 1; i < node->children.size(); ++i) { - TokenPtr catch_block = node->children[i]; + for (unsigned int i = 1; i < this->children.size(); ++i) { + TokenPtr catch_block = this->children[i]; if (catch_block->children.size() == 1) { //No variable capture, no guards - retval = eval_token(ss, catch_block->children[0]); + try { + retval = catch_block->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(catch_block->children[0]); + throw; + } + break; } else if (catch_block->children.size() == 2) { //Variable capture, no guards ss.add_object(catch_block->children[0]->text, except); - retval = eval_token(ss, catch_block->children[1]); + try { + retval = catch_block->children[1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(catch_block->children[1]); + throw; + } + break; } else if (catch_block->children.size() == 3) { @@ -630,38 +1010,78 @@ namespace chaiscript bool guard; try { - guard = boxed_cast(eval_token(ss, catch_block->children[1])); - } catch (const bad_boxed_cast &) { - if (node->children.back()->identifier == Token_Type::Finally) { - eval_token(ss, node->children.back()->children[0]); + guard = boxed_cast(catch_block->children[1]->eval(ss)); + } + catch (const bad_boxed_cast &) { + if (this->children.back()->identifier == Token_Type::Finally) { + try { + this->children.back()->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children.back()->children[0]); + ss.pop_scope(); + throw; + } } + ss.pop_scope(); - throw Eval_Error("Guard condition not boolean", catch_block->children[1]); + throw Eval_Error("Guard condition not boolean"); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(catch_block->children[1]); + throw; } if (guard) { - retval = eval_token(ss, catch_block->children[2]); + try { + retval = catch_block->children[2]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(catch_block->children[2]); + throw; + } break; } } else { - if (node->children.back()->identifier == Token_Type::Finally) { - eval_token(ss, node->children.back()->children[0]); + if (this->children.back()->identifier == Token_Type::Finally) { + try { + this->children.back()->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children.back()->children[0]); + ss.pop_scope(); + throw; + } } ss.pop_scope(); - throw Eval_Error("Internal error: catch block size unrecognized", catch_block); + throw Eval_Error("Internal error: catch block size unrecognized"); } } } catch (...) { - if (node->children.back()->identifier == Token_Type::Finally) { - eval_token(ss, node->children.back()->children[0]); + if (this->children.back()->identifier == Token_Type::Finally) { + try { + this->children.back()->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children.back()->children[0]); + ss.pop_scope(); + throw; + } } ss.pop_scope(); throw; } - if (node->children.back()->identifier == Token_Type::Finally) { - retval = eval_token(ss, node->children.back()->children[0]); + if (this->children.back()->identifier == Token_Type::Finally) { + try { + retval = this->children.back()->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children.back()->children[0]); + ss.pop_scope(); + throw; + } } ss.pop_scope(); @@ -672,36 +1092,62 @@ namespace chaiscript /** * Evaluates an if/elseif/else block */ - template - Boxed_Value eval_if(Eval_System &ss, const TokenPtr &node) { + Boxed_Value If_Token::eval(Dispatch_Engine &ss) { unsigned int i; bool cond; try { - cond = boxed_cast(eval_token(ss, node->children[0])); + cond = boxed_cast(this->children[0]->eval(ss)); } catch (const bad_boxed_cast &) { - throw Eval_Error("If condition not boolean", node->children[0]); + throw Eval_Error("If condition not boolean"); } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + if (cond) { - return eval_token(ss, node->children[1]); + try { + return this->children[1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[1]); + throw; + } } else { - if (node->children.size() > 2) { + if (this->children.size() > 2) { i = 2; - while ((!cond) && (i < node->children.size())) { - if (node->children[i]->text == "else") { - return eval_token(ss, node->children[i+1]); - } - else if (node->children[i]->text == "else if") { + while ((!cond) && (i < this->children.size())) { + if (this->children[i]->text == "else") { try { - cond = boxed_cast(eval_token(ss, node->children[i+1])); + return this->children[i+1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; + } + } + else if (this->children[i]->text == "else if") { + try { + cond = boxed_cast(this->children[i+1]->eval(ss)); } catch (const bad_boxed_cast &) { - throw Eval_Error("'else if' condition not boolean", node->children[i+1]); + throw Eval_Error("'else if' condition not boolean"); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+1]); + throw; } if (cond) { - return eval_token(ss, node->children[i+2]); + try { + return this->children[i+2]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i+2]); + throw; + } } } i = i + 3; @@ -715,28 +1161,44 @@ namespace chaiscript /** * Evaluates a while block */ - template - Boxed_Value eval_while(Eval_System &ss, const TokenPtr &node) { + Boxed_Value While_Token::eval(Dispatch_Engine &ss) { bool cond; ss.new_scope(); try { - cond = boxed_cast(eval_token(ss, node->children[0])); + cond = boxed_cast(this->children[0]->eval(ss)); } catch (const bad_boxed_cast &) { ss.pop_scope(); - throw Eval_Error("While condition not boolean", node->children[0]); + throw Eval_Error("While condition not boolean"); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + ss.pop_scope(); + throw; } while (cond) { try { - eval_token(ss, node->children[1]); try { - cond = boxed_cast(eval_token(ss, node->children[0])); + this->children[1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[1]); + throw; + } + + try { + cond = boxed_cast(this->children[0]->eval(ss)); } catch (const bad_boxed_cast &) { ss.pop_scope(); - throw Eval_Error("While condition not boolean", node->children[0]); + throw Eval_Error("While condition not boolean"); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + ss.pop_scope(); + throw; } } catch (Break_Loop &) { @@ -750,41 +1212,101 @@ namespace chaiscript /** * Evaluates a for block, including the for's conditions, from left to right */ - template - Boxed_Value eval_for(Eval_System &ss, const TokenPtr &node) { + Boxed_Value For_Token::eval(Dispatch_Engine &ss) { bool cond; ss.new_scope(); try { - if (node->children.size() == 4) { - eval_token(ss, node->children[0]); - cond = boxed_cast(eval_token(ss, node->children[1])); + if (this->children.size() == 4) { + try { + this->children[0]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } + + try { + cond = boxed_cast(this->children[1]->eval(ss)); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[1]); + throw; + } } else { - cond = boxed_cast(eval_token(ss, node->children[0])); + try { + cond = boxed_cast(this->children[0]->eval(ss)); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + ss.pop_scope(); + throw; + } } } catch (const bad_boxed_cast &) { ss.pop_scope(); - throw Eval_Error("For condition not boolean", node); + throw Eval_Error("For condition not boolean"); } while (cond) { try { - if (node->children.size() == 4) { - eval_token(ss, node->children[3]); - eval_token(ss, node->children[2]); - cond = boxed_cast(eval_token(ss, node->children[1])); + if (this->children.size() == 4) { + try { + this->children[3]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[3]); + throw; + } + + try { + this->children[2]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[2]); + throw; + } + + try { + cond = boxed_cast(this->children[1]->eval(ss)); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[1]); + throw; + } } else { - eval_token(ss, node->children[2]); - eval_token(ss, node->children[1]); - cond = boxed_cast(eval_token(ss, node->children[0])); + try { + this->children[2]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[2]); + throw; + } + + try { + this->children[1]->eval(ss); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[1]); + throw; + } + + try { + cond = boxed_cast(this->children[0]->eval(ss)); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + ss.pop_scope(); + throw; + } } } catch (const bad_boxed_cast &) { ss.pop_scope(); - throw Eval_Error("For condition not boolean", node); + throw Eval_Error("For condition not boolean"); } catch (Break_Loop &) { cond = false; @@ -797,52 +1319,51 @@ namespace chaiscript /** * Evaluates a function definition */ - template - Boxed_Value eval_def(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Def_Token::eval(Dispatch_Engine &ss) { unsigned int i; std::vector param_names; - std::string annotation = node->annotation?node->annotation->text:""; + std::string annotation = this->annotation?this->annotation->text:""; boost::shared_ptr guard; size_t numparams = 0; - std::string function_name = node->children[0]->text; + std::string function_name = this->children[0]->text; TokenPtr guardnode; - if ((node->children.size() > 2) && (node->children[1]->identifier == Token_Type::Arg_List)) { - numparams = node->children[1]->children.size(); + if ((this->children.size() > 2) && (this->children[1]->identifier == Token_Type::Arg_List)) { + numparams = this->children[1]->children.size(); for (i = 0; i < numparams; ++i) { - param_names.push_back(node->children[1]->children[i]->text); + param_names.push_back(this->children[1]->children[i]->text); } - if (node->children.size() > 3) { - guardnode = node->children[2]; + if (this->children.size() > 3) { + guardnode = this->children[2]; } } else { //no parameters numparams = 0; - if (node->children.size() > 2) { - guardnode = node->children[1]; + if (this->children.size() > 2) { + guardnode = this->children[1]; } } if (guardnode) { guard = boost::shared_ptr - (new Dynamic_Proxy_Function(boost::bind(&eval_function, + (new Dynamic_Proxy_Function(boost::bind(&eval_function, boost::ref(ss), guardnode, param_names, _1), numparams)); } try { ss.add(Proxy_Function - (new Dynamic_Proxy_Function(boost::bind(&eval_function, - boost::ref(ss), node->children.back(), + (new Dynamic_Proxy_Function(boost::bind(&eval_function, + boost::ref(ss), this->children.back(), param_names, _1), numparams, annotation, guard)), function_name); } catch (reserved_word_error &) { - throw Eval_Error("Reserved word used as function name '" + function_name + "'", node); + throw Eval_Error("Reserved word used as function name '" + function_name + "'"); } return Boxed_Value(); } @@ -850,36 +1371,34 @@ namespace chaiscript /** * Evaluates a function definition */ - template - Boxed_Value eval_def_method(Eval_System &ss, const TokenPtr &node) { - //TODO: Merge with eval_def cleanly someday? + Boxed_Value Method_Token::eval(Dispatch_Engine &ss) { unsigned int i; std::vector param_names; - std::string annotation = node->annotation?node->annotation->text:""; + std::string annotation = this->annotation?this->annotation->text:""; boost::shared_ptr guard; size_t numparams; - std::string class_name = node->children[0]->text; - std::string function_name = node->children[1]->text; + std::string class_name = this->children[0]->text; + std::string function_name = this->children[1]->text; TokenPtr guardnode; //The first param of a method is always the implied this ptr. param_names.push_back("this"); - if ((node->children.size() > 3) && (node->children[2]->identifier == Token_Type::Arg_List)) { - for (i = 0; i < node->children[2]->children.size(); ++i) { - param_names.push_back(node->children[2]->children[i]->text); + if ((this->children.size() > 3) && (this->children[2]->identifier == Token_Type::Arg_List)) { + for (i = 0; i < this->children[2]->children.size(); ++i) { + param_names.push_back(this->children[2]->children[i]->text); } - if (node->children.size() > 4) { - guardnode = node->children[3]; + if (this->children.size() > 4) { + guardnode = this->children[3]; } } else { //no parameters - if (node->children.size() > 3) { - guardnode = node->children[2]; + if (this->children.size() > 3) { + guardnode = this->children[2]; } } @@ -887,7 +1406,7 @@ namespace chaiscript if (guardnode) { guard = boost::shared_ptr - (new Dynamic_Proxy_Function(boost::bind(&eval_function, + (new Dynamic_Proxy_Function(boost::bind(&eval_function, boost::ref(ss), guardnode, param_names, _1), numparams)); } @@ -896,8 +1415,8 @@ namespace chaiscript if (function_name == class_name) { ss.add(Proxy_Function (new Dynamic_Object_Constructor(class_name, Proxy_Function - (new Dynamic_Proxy_Function(boost::bind(&eval_function, - boost::ref(ss), node->children.back(), + (new Dynamic_Proxy_Function(boost::bind(&eval_function, + boost::ref(ss), this->children.back(), param_names, _1), numparams, annotation, guard)))), function_name); @@ -911,15 +1430,15 @@ namespace chaiscript } ss.add(Proxy_Function (new Dynamic_Object_Function(class_name, Proxy_Function - (new Dynamic_Proxy_Function(boost::bind(&eval_function, - boost::ref(ss), node->children.back(), + (new Dynamic_Proxy_Function(boost::bind(&eval_function, + boost::ref(ss), this->children.back(), param_names, _1), numparams, annotation, guard)), ti)), function_name); } } catch (reserved_word_error &) { - throw Eval_Error("Reserved word used as method name '" + function_name + "'", node); + throw Eval_Error("Reserved word used as method name '" + function_name + "'"); } return Boxed_Value(); } @@ -927,17 +1446,16 @@ namespace chaiscript /** * Evaluates a lambda (anonymous function) */ - template - Boxed_Value eval_lambda(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Lambda_Token::eval(Dispatch_Engine &ss) { unsigned int i; std::vector param_names; size_t numparams = 0; - if ((node->children.size() > 0) && (node->children[0]->identifier == Token_Type::Arg_List)) { - numparams = node->children[0]->children.size(); + if ((this->children.size() > 0) && (this->children[0]->identifier == Token_Type::Arg_List)) { + numparams = this->children[0]->children.size(); for (i = 0; i < numparams; ++i) { - param_names.push_back(node->children[0]->children[i]->text); + param_names.push_back(this->children[0]->children[i]->text); } } @@ -947,22 +1465,21 @@ namespace chaiscript } return Boxed_Value(Proxy_Function(new Dynamic_Proxy_Function - (boost::bind(&eval_function, boost::ref(ss), node->children.back(), param_names, _1), + (boost::bind(&eval_function, boost::ref(ss), this->children.back(), param_names, _1), numparams))); } /** * Evaluates a scoped block. Handles resetting the scope after the block has completed. */ - template - Boxed_Value eval_block(Eval_System &ss, const TokenPtr &node) { + Boxed_Value Block_Token::eval(Dispatch_Engine &ss) { unsigned int i; - unsigned int num_children = node->children.size(); + unsigned int num_children = this->children.size(); ss.new_scope(); for (i = 0; i < num_children; ++i) { try { - const Boxed_Value &retval = eval_token(ss, node->children[i]); + const Boxed_Value &retval = this->children[i]->eval(ss); if (i + 1 == num_children) { @@ -970,7 +1487,12 @@ namespace chaiscript return retval; } } - catch (const chaiscript::Return_Value &/*rv*/) { + catch (const chaiscript::Return_Value &) { + ss.pop_scope(); + throw; + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[i]); ss.pop_scope(); throw; } @@ -987,157 +1509,26 @@ namespace chaiscript /** * Evaluates a return statement */ - template - Boxed_Value eval_return(Eval_System &ss, const TokenPtr &node) { - if (node->children.size() > 0) { - throw Return_Value(eval_token(ss, node->children[0]), node); + Boxed_Value Return_Token::eval(Dispatch_Engine &ss) { + if (this->children.size() > 0) { + try { + throw Return_Value(this->children[0]->eval(ss)); + } + catch (Eval_Error &ee) { + ee.call_stack.push_back(this->children[0]); + throw; + } } else { - throw Return_Value(Boxed_Value(), node); + throw Return_Value(Boxed_Value()); } } /** * Evaluates a break statement */ - template - Boxed_Value eval_break(Eval_System &, const TokenPtr &node) { - throw Break_Loop(node); - } - - /** - * Top-level evaluation dispatch for all AST node types - */ - template - Boxed_Value eval_token(Eval_System &ss, const TokenPtr &node) { - switch (node->identifier) { - case (Token_Type::File) : - return eval_file(ss, node); - break; - - case (Token_Type::Id) : - return eval_id(ss, node); - break; - - case (Token_Type::Float) : - return eval_float(ss, node); - break; - - case (Token_Type::Int) : - return eval_int(ss, node); - break; - - case (Token_Type::Quoted_String) : - return eval_quoted_string(ss, node); - break; - - case (Token_Type::Single_Quoted_String) : - return eval_single_quoted_string(ss, node); - break; - - case (Token_Type::Equation) : - return eval_equation(ss, node); - break; - - case (Token_Type::Var_Decl) : - return eval_var_decl(ss, node); - break; - - case (Token_Type::Logical_And) : - case (Token_Type::Logical_Or) : - return eval_logical(ss, node); - break; - - case (Token_Type::Bitwise_And) : - case (Token_Type::Bitwise_Xor) : - case (Token_Type::Bitwise_Or) : - case (Token_Type::Comparison) : - case (Token_Type::Equality) : - case (Token_Type::Additive) : - case (Token_Type::Multiplicative) : - case (Token_Type::Shift) : - return eval_comp_add_mul(ss, node); - break; - - case (Token_Type::Array_Call) : - return eval_array_call(ss, node); - break; - - case (Token_Type::Prefix) : - return eval_prefix(ss, node); - break; - - case (Token_Type::Inline_Array) : - return eval_inline_array(ss, node); - break; - - case (Token_Type::Inline_Range) : - return eval_inline_range(ss, node); - break; - - case (Token_Type::Inline_Map) : - return eval_inline_map(ss, node); - break; - - case (Token_Type::Fun_Call) : - return eval_fun_call(ss, node); - break; - - case (Token_Type::Inplace_Fun_Call) : - return eval_inplace_fun_call(ss, node); - break; - - case (Token_Type::Dot_Access) : - return eval_dot_access(ss, node); - break; - - case(Token_Type::Try) : - return eval_try(ss, node); - break; - - case(Token_Type::If) : - return eval_if(ss, node); - break; - - case(Token_Type::While) : - return eval_while(ss, node); - break; - - case(Token_Type::For) : - return eval_for(ss, node); - break; - - case (Token_Type::Def) : - return eval_def(ss, node); - break; - - case (Token_Type::Method) : - return eval_def_method(ss, node); - break; - - case (Token_Type::Attr_Decl) : - return eval_attr_decl(ss, node); - break; - - case (Token_Type::Lambda) : - return eval_lambda(ss, node); - break; - - case (Token_Type::Block) : - return eval_block(ss, node); - break; - - case (Token_Type::Return) : - return eval_return(ss, node); - break; - - case (Token_Type::Break) : - return eval_break(ss, node); - break; - - default : - return Boxed_Value(); - } + Boxed_Value Break_Token::eval(Dispatch_Engine &) { + throw Break_Loop(); } } #endif /* CHAISCRIPT_EVAL_HPP_ */ diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index f3e63914..423de13f 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -137,17 +137,183 @@ namespace chaiscript * Helper function that collects tokens from a starting position to the top of the stack into a new AST node */ void build_match(Token_Type::Type match_type, int match_start) { + int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop; + int is_deep = false; + //so we want to take everything to the right of this and make them children if (match_start != int(match_stack.size())) { - TokenPtr t(new Token("", match_type, filename, match_stack[match_start]->start.line, match_stack[match_start]->start.column, line, col)); + pos_line_start = match_stack[match_start]->start.line; + pos_col_start = match_stack[match_start]->start.column; + pos_line_stop = line; + pos_col_stop = col; + is_deep = true; + } + else { + pos_line_start = line; + pos_col_start = col; + pos_line_stop = line; + pos_col_stop = col; + } + + Token *t; + + switch (match_type) { + case(Token_Type::Error) : + t = new Error_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Int) : + t = new Int_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Float) : + t = new Float_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Id) : + t = new Id_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Char) : + t = new Char_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Str) : + t = new Str_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Eol) : + t = new Eol_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Fun_Call) : + t = new Fun_Call_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Inplace_Fun_Call) : + t = new Inplace_Fun_Call_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Arg_List) : + t = new Arg_List_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Variable) : + t = new Variable_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Equation) : + t = new Equation_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Var_Decl) : + t = new Var_Decl_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Comparison) : + t = new Comparison_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Additive) : + t = new Additive_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Multiplicative) : + t = new Multiplicative_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Array_Call) : + t = new Array_Call_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Dot_Access) : + t = new Dot_Access_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Quoted_String) : + t = new Quoted_String_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Single_Quoted_String) : + t = new Single_Quoted_String_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Lambda) : + t = new Lambda_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Block) : + t = new Block_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Def) : + t = new Def_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::While) : + t = new While_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::If) : + t = new If_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::For) : + t = new For_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Inline_Array) : + t = new Inline_Array_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Inline_Map) : + t = new Inline_Map_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Return) : + t = new Return_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::File) : + t = new File_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Prefix) : + t = new Prefix_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Break) : + t = new Break_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Map_Pair) : + t = new Map_Pair_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Value_Range) : + t = new Value_Range_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Inline_Range) : + t = new Inline_Range_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Annotation) : + t = new Annotation_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Try) : + t = new Try_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Catch) : + t = new Catch_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Finally) : + t = new Finally_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Method) : + t = new Method_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Attr_Decl) : + t = new Attr_Decl_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Shift) : + t = new Shift_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Equality) : + t = new Equality_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Bitwise_And) : + t = new Bitwise_And_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Bitwise_Xor) : + t = new Bitwise_Xor_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Bitwise_Or) : + t = new Bitwise_Or_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Logical_And) : + t = new Logical_And_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + case(Token_Type::Logical_Or) : + t = new Logical_Or_Token("", match_type, filename, pos_line_start, pos_col_start, pos_line_stop, pos_col_stop); + break; + } + + TokenPtr tp(t); + + if (is_deep) { t->children.assign(match_stack.begin() + (match_start), match_stack.end()); match_stack.erase(match_stack.begin() + (match_start), match_stack.end()); - match_stack.push_back(t); + match_stack.push_back(tp); } else { //todo: fix the fact that a successful match that captured no tokens doesn't have any real start position - TokenPtr t(new Token("", match_type, filename, line, col, line, col)); - match_stack.push_back(t); + match_stack.push_back(tp); } } @@ -349,7 +515,7 @@ namespace chaiscript std::ostringstream out_int; out_int << int(temp_int); - TokenPtr t(new Token(out_int.str(), Token_Type::Int, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Int_Token(out_int.str(), Token_Type::Int, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } @@ -368,13 +534,13 @@ namespace chaiscript std::ostringstream out_int; out_int << temp_int; - TokenPtr t(new Token(out_int.str(), Token_Type::Int, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Int_Token(out_int.str(), Token_Type::Int, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } if (Float_()) { std::string match(start, input_pos); - TokenPtr t(new Token(match, Token_Type::Float, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Float_Token(match, Token_Type::Float, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } @@ -387,11 +553,11 @@ namespace chaiscript std::ostringstream out_int; out_int << int(temp_int); - TokenPtr t(new Token(out_int.str(), Token_Type::Int, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Int_Token(out_int.str(), Token_Type::Int, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); } else { - TokenPtr t(new Token(match, Token_Type::Int, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Int_Token(match, Token_Type::Int, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); } return true; @@ -462,13 +628,13 @@ namespace chaiscript if (*start == '`') { //Id Literal std::string match(start+1, input_pos-1); - TokenPtr t(new Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Id_Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } else { std::string match(start, input_pos); - TokenPtr t(new Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Id_Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } @@ -501,7 +667,7 @@ namespace chaiscript } while (Symbol("#")); std::string match(start, input_pos); - TokenPtr t(new Token(match, Token_Type::Annotation, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Annotation_Token(match, Token_Type::Annotation, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } @@ -576,23 +742,23 @@ namespace chaiscript if (is_interpolated) { //If we've seen previous interpolation, add on instead of making a new one - TokenPtr plus(new Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col)); + TokenPtr plus(new Str_Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col)); match_stack.push_back(plus); - TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Quoted_String_Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); build_match(Token_Type::Additive, prev_stack_top); } else { - TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Quoted_String_Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); } //We've finished with the part of the string up to this point, so clear it match = ""; - TokenPtr plus(new Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col)); + TokenPtr plus(new Str_Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col)); match_stack.push_back(plus); std::string eval_match; @@ -608,17 +774,17 @@ namespace chaiscript int tostr_stack_top = match_stack.size(); - TokenPtr tostr(new Token("to_string", Token_Type::Id, filename, prev_line, prev_col, line, col)); + TokenPtr tostr(new Id_Token("to_string", Token_Type::Id, filename, prev_line, prev_col, line, col)); match_stack.push_back(tostr); int ev_stack_top = match_stack.size(); - TokenPtr ev(new Token("eval", Token_Type::Id, filename, prev_line, prev_col, line, col)); + TokenPtr ev(new Id_Token("eval", Token_Type::Id, filename, prev_line, prev_col, line, col)); match_stack.push_back(ev); int arg_stack_top = match_stack.size(); - TokenPtr t(new Token(eval_match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Quoted_String_Token(eval_match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); build_match(Token_Type::Arg_List, arg_stack_top); @@ -676,16 +842,16 @@ namespace chaiscript } } if (is_interpolated) { - TokenPtr plus(new Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col)); + TokenPtr plus(new Str_Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col)); match_stack.push_back(plus); - TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Quoted_String_Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); build_match(Token_Type::Additive, prev_stack_top); } else { - TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Quoted_String_Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); } return true; @@ -777,7 +943,7 @@ namespace chaiscript is_escaped = false; } } - TokenPtr t(new Token(match, Token_Type::Single_Quoted_String, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Single_Quoted_String_Token(match, Token_Type::Single_Quoted_String, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } @@ -816,7 +982,7 @@ namespace chaiscript int prev_line = line; if (Char_(c)) { std::string match(start, input_pos); - TokenPtr t(new Token(match, Token_Type::Char, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Char_Token(match, Token_Type::Char, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } @@ -889,7 +1055,7 @@ namespace chaiscript return false; } std::string match(start, input_pos); - TokenPtr t(new Token(match, Token_Type::Str, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Str_Token(match, Token_Type::Str, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } @@ -967,7 +1133,7 @@ namespace chaiscript } else { std::string match(start, input_pos); - TokenPtr t(new Token(match, Token_Type::Str, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Str_Token(match, Token_Type::Str, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } @@ -1011,7 +1177,7 @@ namespace chaiscript int prev_line = line; if (Eol_()) { std::string match(start, input_pos); - TokenPtr t(new Token(match, Token_Type::Eol, filename, prev_line, prev_col, line, col)); + TokenPtr t(new Eol_Token(match, Token_Type::Eol, filename, prev_line, prev_col, line, col)); match_stack.push_back(t); return true; } @@ -1036,7 +1202,7 @@ namespace chaiscript do { while (Eol()); if (!Equation()) { - throw Eval_Error("Unexpected value in parameter list", match_stack.back()); + throw Eval_Error("Unexpected value in parameter list", File_Position(line, col), filename); } } while (retval && Char(',')); } @@ -1065,7 +1231,7 @@ namespace chaiscript do { while (Eol()); if (!Map_Pair()) { - throw Eval_Error("Unexpected value in container", match_stack.back()); + throw Eval_Error("Unexpected value in container", File_Position(line, col), filename); } } while (retval && Char(',')); } @@ -1746,7 +1912,7 @@ namespace chaiscript Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) || Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { if (!Equation()) { - throw Eval_Error("Incomplete equation", match_stack.back()); + throw Eval_Error("Incomplete equation", File_Position(line, col), filename); } build_match(Token_Type::Equation, prev_stack_top); @@ -1767,9 +1933,11 @@ namespace chaiscript while (has_more) { has_more = false; + int prev_line = line; + int prev_col = col; if (Def()) { if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", match_stack.back()); + throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), filename); } has_more = true; retval = true; @@ -1777,7 +1945,7 @@ namespace chaiscript } else if (Try()) { if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", match_stack.back()); + throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), filename); } has_more = true; retval = true; @@ -1785,7 +1953,7 @@ namespace chaiscript } else if (If()) { if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", match_stack.back()); + throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), filename); } has_more = true; retval = true; @@ -1793,7 +1961,7 @@ namespace chaiscript } else if (While()) { if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", match_stack.back()); + throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), filename); } has_more = true; retval = true; @@ -1801,7 +1969,7 @@ namespace chaiscript } else if (For()) { if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", match_stack.back()); + throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), filename); } has_more = true; retval = true; @@ -1809,7 +1977,7 @@ namespace chaiscript } else if (Return()) { if (!saw_eol) { - throw Eval_Error("Two expressions missing line separator", match_stack.back()); + throw Eval_Error("Two expressions missing line separator", File_Position(prev_line, prev_col), filename); } has_more = true; retval = true; @@ -1817,7 +1985,7 @@ namespace chaiscript } else if (Break()) { if (!saw_eol) { - throw Eval_Error("Two expressions missing line separator", match_stack.back()); + throw Eval_Error("Two expressions missing line separator", File_Position(prev_line, prev_col), filename); } has_more = true; retval = true; @@ -1825,7 +1993,7 @@ namespace chaiscript } else if (Equation()) { if (!saw_eol) { - throw Eval_Error("Two expressions missing line separator", match_stack.back()); + throw Eval_Error("Two expressions missing line separator", File_Position(prev_line, prev_col), filename); } has_more = true; retval = true; diff --git a/src/main.cpp b/src/main.cpp index b4b2d51e..89120dd6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,8 +118,16 @@ int main(int argc, char *argv[]) { } } } + catch (chaiscript::Eval_Error &ee) { + std::cout << ee.what(); + if (ee.call_stack.size() > 0) { + std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; + } + std::cout << std::endl; + } catch (std::exception &e) { - std::cout << e.what() << std::endl; + std::cout << e.what(); + std::cout << std::endl; } } @@ -131,6 +139,13 @@ int main(int argc, char *argv[]) { try { chaiscript::Boxed_Value val = chai.eval_file(argv[i]); } + catch (chaiscript::Eval_Error &ee) { + std::cout << ee.what(); + if (ee.call_stack.size() > 0) { + std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; + } + std::cout << std::endl; + } catch (std::exception &e) { std::cout << e.what() << std::endl; return EXIT_FAILURE;