From 9a7d03df05ab4fe6632330be5d59f833c63a82d6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 4 Oct 2014 09:37:33 -0600 Subject: [PATCH] Modernization of chaiscript_parser --- .../chaiscript/language/chaiscript_parser.hpp | 3143 ++++++++--------- include/chaiscript/utility/utility.hpp | 27 +- 2 files changed, 1477 insertions(+), 1693 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index e50a5d0..29ee4b9 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -57,94 +57,63 @@ namespace chaiscript std::vector m_match_stack; bool m_alphabet[detail::max_alphabet][detail::lengthof_alphabet]; - std::vector > m_operator_matches; + std::vector> m_operator_matches; std::vector m_operators; public: ChaiScript_Parser() : m_line(-1), m_col(-1), - m_multiline_comment_begin("/*"), + m_multiline_comment_begin("/*"), m_multiline_comment_end("*/"), m_singleline_comment("//") { setup_operators(); } - ChaiScript_Parser(const ChaiScript_Parser &); // explicitly unimplemented copy constructor - ChaiScript_Parser &operator=(const ChaiScript_Parser &); // explicitly unimplemented assignment operator + ChaiScript_Parser(const ChaiScript_Parser &) = delete; + ChaiScript_Parser &operator=(const ChaiScript_Parser &) = delete; void setup_operators() { - m_operators.push_back(AST_Node_Type::Ternary_Cond); - std::vector ternary_cond; - ternary_cond.push_back("?"); - m_operator_matches.push_back(ternary_cond); + m_operators.emplace_back(AST_Node_Type::Ternary_Cond); + m_operator_matches.emplace_back(std::initializer_list({"?"})); - m_operators.push_back(AST_Node_Type::Logical_Or); - std::vector logical_or; - logical_or.push_back("||"); - m_operator_matches.push_back(logical_or); + m_operators.emplace_back(AST_Node_Type::Logical_Or); + m_operator_matches.emplace_back(std::initializer_list({"||"})); - m_operators.push_back(AST_Node_Type::Logical_And); - std::vector logical_and; - logical_and.push_back("&&"); - m_operator_matches.push_back(logical_and); + m_operators.emplace_back(AST_Node_Type::Logical_And); + m_operator_matches.emplace_back(std::initializer_list({"&&"})); - m_operators.push_back(AST_Node_Type::Bitwise_Or); - std::vector bitwise_or; - bitwise_or.push_back("|"); - m_operator_matches.push_back(bitwise_or); + m_operators.emplace_back(AST_Node_Type::Bitwise_Or); + m_operator_matches.emplace_back(std::initializer_list({"|"})); - m_operators.push_back(AST_Node_Type::Bitwise_Xor); - std::vector bitwise_xor; - bitwise_xor.push_back("^"); - m_operator_matches.push_back(bitwise_xor); + m_operators.emplace_back(AST_Node_Type::Bitwise_Xor); + m_operator_matches.emplace_back(std::initializer_list({"^"})); - m_operators.push_back(AST_Node_Type::Bitwise_And); - std::vector bitwise_and; - bitwise_and.push_back("&"); - m_operator_matches.push_back(bitwise_and); + m_operators.emplace_back(AST_Node_Type::Bitwise_And); + m_operator_matches.emplace_back(std::initializer_list({"&"})); - m_operators.push_back(AST_Node_Type::Equality); - std::vector equality; - equality.push_back("=="); - equality.push_back("!="); - m_operator_matches.push_back(equality); + m_operators.emplace_back(AST_Node_Type::Equality); + m_operator_matches.emplace_back(std::initializer_list({"==", "!="})); - m_operators.push_back(AST_Node_Type::Comparison); - std::vector comparison; - comparison.push_back("<"); - comparison.push_back("<="); - comparison.push_back(">"); - comparison.push_back(">="); - m_operator_matches.push_back(comparison); + m_operators.emplace_back(AST_Node_Type::Comparison); + m_operator_matches.emplace_back(std::initializer_list({"<", "<=", ">", ">="})); - m_operators.push_back(AST_Node_Type::Shift); - std::vector shift; - shift.push_back("<<"); - shift.push_back(">>"); - m_operator_matches.push_back(shift); + m_operators.emplace_back(AST_Node_Type::Shift); + m_operator_matches.emplace_back(std::initializer_list({"<<", ">>"})); //We share precedence here but then separate them later - m_operators.push_back(AST_Node_Type::Addition); - std::vector addition; - addition.push_back("+"); - addition.push_back("-"); - m_operator_matches.push_back(addition); + m_operators.emplace_back(AST_Node_Type::Addition); + m_operator_matches.emplace_back(std::initializer_list({"+", "-"})); //We share precedence here but then separate them later - m_operators.push_back(AST_Node_Type::Multiplication); - std::vector multiplication; - multiplication.push_back("*"); - multiplication.push_back("/"); - multiplication.push_back("%"); - m_operator_matches.push_back(multiplication); + m_operators.emplace_back(AST_Node_Type::Multiplication); + m_operator_matches.emplace_back(std::initializer_list({"*", "/", "%"})); - for ( int c = 0 ; c < detail::lengthof_alphabet ; ++c ) { - for (auto & elem : m_alphabet) { - elem[c]=false; - } + for (auto & elem : m_alphabet) { + std::fill(std::begin(elem), std::end(elem), false); } + m_alphabet[detail::symbol_alphabet][static_cast('?')]=true; m_alphabet[detail::symbol_alphabet][static_cast('+')]=true; m_alphabet[detail::symbol_alphabet][static_cast('-')]=true; @@ -194,17 +163,12 @@ namespace chaiscript m_alphabet[detail::float_suffix_alphabet][static_cast('L')] = true; m_alphabet[detail::float_suffix_alphabet][static_cast('f')] = true; m_alphabet[detail::float_suffix_alphabet][static_cast('F')] = true; - } - /** - * test a char in an m_alphabet - */ - bool char_in_alphabet(char c, detail::Alphabet a) { return m_alphabet[a][static_cast(c)]; } + /// test a char in an m_alphabet + bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast(c)]; } - /** - * Prints the parsed ast_nodes as a tree - */ + /// Prints the parsed ast_nodes as a tree /* void debug_print(AST_NodePtr t, std::string prepend = "") { std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl; @@ -214,9 +178,7 @@ namespace chaiscript } */ - /** - * Shows the current stack of matched ast_nodes - */ + /// Shows the current stack of matched ast_nodes void show_match_stack() const { for (auto & elem : m_match_stack) { //debug_print(match_stack[i]); @@ -224,26 +186,20 @@ namespace chaiscript } } - /** - * Clears the stack of matched ast_nodes - */ + /// Clears the stack of matched ast_nodes void clear_match_stack() { m_match_stack.clear(); } - /** - * Returns the front-most AST node - */ - AST_NodePtr ast() { + /// Returns the front-most AST node + AST_NodePtr ast() const { return m_match_stack.front(); } - /** - * Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node - */ + /// Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node void build_match(AST_NodePtr t_t, size_t t_match_start) { int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop; - int is_deep = false; + bool is_deep = false; //so we want to take everything to the right of this and make them children if (t_match_start != m_match_stack.size()) { @@ -269,72 +225,57 @@ namespace chaiscript if (is_deep) { t_t->children.assign(m_match_stack.begin() + t_match_start, m_match_stack.end()); m_match_stack.erase(m_match_stack.begin() + t_match_start, m_match_stack.end()); - m_match_stack.push_back(t_t); - } - else { - /// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position - m_match_stack.push_back(t_t); } + + /// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position + m_match_stack.push_back(std::move(t_t)); } - /** - * Check to see if there is more text parse - */ + /// Check to see if there is more text parse inline bool has_more_input() const { return (m_input_pos != m_input_end); } - /** - * Skips any multi-line or single-line comment - */ + /// Skips any multi-line or single-line comment bool SkipComment() { - bool retval = false; - if (Symbol_(m_multiline_comment_begin.c_str())) { while (m_input_pos != m_input_end) { if (Symbol_(m_multiline_comment_end.c_str())) { break; - } - else if (!Eol_()) { + } else if (!Eol_()) { ++m_col; ++m_input_pos; } } - retval = true; - } - else if (Symbol_(m_singleline_comment.c_str())) { + return true; + } else if (Symbol_(m_singleline_comment.c_str())) { while (m_input_pos != m_input_end) { if (Symbol_("\r\n")) { m_input_pos -= 2; break; - } - else if (Char_('\n')) { + } else if (Char_('\n')) { --m_input_pos; break; - } - else { + } else { ++m_col; ++m_input_pos; } } - retval = true; + return true; } - return retval; + return false; } - /** - * Skips ChaiScript whitespace, which means space and tab, but not cr/lf - * jespada: Modified SkipWS to skip optionally CR ('\n') - */ - bool SkipWS(bool skip_cr=false) { + /// Skips ChaiScript whitespace, which means space and tab, but not cr/lf + /// jespada: Modified SkipWS to skip optionally CR ('\n') + bool SkipWS(const bool skip_cr=false) { bool retval = false; while (has_more_input()) { if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && (*m_input_pos == '\n'))) { if(*m_input_pos == '\n') { m_col = 1; ++m_line; - } - else { + } else { ++m_col; } ++m_input_pos; @@ -351,22 +292,18 @@ namespace chaiscript return retval; } - /** - * Reads a floating point value from input, without skipping initial whitespace - */ + /// Reads a floating point value from input, without skipping initial whitespace bool Float_() { - bool retval = false; - if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { ++m_input_pos; ++m_col; } + if (has_more_input() && (*m_input_pos == '.')) { ++m_input_pos; ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet)) { - retval = true; while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { ++m_input_pos; ++m_col; @@ -377,21 +314,19 @@ namespace chaiscript ++m_input_pos; ++m_col; } - } - else { + + return true; + } else { --m_input_pos; --m_col; } } } - return retval; + return false; } - /** - * Reads a hex value from input, without skipping initial whitespace - */ + /// Reads a hex value from input, without skipping initial whitespace bool Hex_() { - bool retval = false; if (has_more_input() && (*m_input_pos == '0')) { ++m_input_pos; ++m_col; @@ -400,7 +335,6 @@ namespace chaiscript ++m_input_pos; ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet)) { - retval = true; while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) { ++m_input_pos; ++m_col; @@ -410,6 +344,8 @@ namespace chaiscript ++m_input_pos; ++m_col; } + + return true; } else { --m_input_pos; @@ -422,9 +358,10 @@ namespace chaiscript } } - return retval; + return false; } + /// Reads an integer suffix void IntSuffix_() { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) { @@ -433,11 +370,8 @@ namespace chaiscript } } - /** - * Reads a binary value from input, without skipping initial whitespace - */ + /// Reads a binary value from input, without skipping initial whitespace bool Binary_() { - bool retval = false; if (has_more_input() && (*m_input_pos == '0')) { ++m_input_pos; ++m_col; @@ -446,32 +380,31 @@ namespace chaiscript ++m_input_pos; ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { - retval = true; while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { ++m_input_pos; ++m_col; } - } - else { + return true; + } else { --m_input_pos; --m_col; } - } - else { + } else { --m_input_pos; --m_col; } } - return retval; + return false; } + /// Parses a floating point value and returns a Boxed_Value representation of it static Boxed_Value buildFloat(const std::string &t_val) { bool float_ = false; bool long_ = false; - size_t i = t_val.size(); + auto i = t_val.size(); for (; i > 0; --i) { @@ -492,16 +425,16 @@ namespace chaiscript if (float_) { float f; - ss >> f; - return Boxed_Value(const_var(f)); + ss >> f; + return const_var(f); } else if (long_) { long double f; - ss >> f; - return Boxed_Value(const_var(f)); + ss >> f; + return const_var(f); } else { double f; - ss >> f; - return Boxed_Value(const_var(f)); + ss >> f; + return const_var(f); } } @@ -514,11 +447,11 @@ namespace chaiscript bool long_ = false; bool longlong_ = false; - size_t i = t_val.size(); + auto i = t_val.size(); for (; i > 0; --i) { - char val = t_val[i-1]; + const char val = t_val[i-1]; if (val == 'u' || val == 'U') { @@ -543,7 +476,6 @@ namespace chaiscript testu >> t_type >> u; bool unsignedrequired = false; - size_t size = sizeof(int) * 8; if ((u >> (sizeof(int) * 8)) > 0) { @@ -561,6 +493,8 @@ namespace chaiscript } + size_t size = sizeof(int) * 8; + if (longlong_) { size = sizeof(int64_t) * 8; @@ -595,60 +529,57 @@ namespace chaiscript if (longlong_) { uint64_t val; - ss >> val; - return Boxed_Value(const_var(val)); + ss >> val; + return const_var(val); } else if (long_) { unsigned long val; ss >> val; - return Boxed_Value(const_var(val)); + return const_var(val); } else { unsigned int val; ss >> val; - return Boxed_Value(const_var(val)); + return const_var(val); } } else { if (longlong_) { int64_t val; - ss >> val; - return Boxed_Value(const_var(val)); + ss >> val; + return const_var(val); } else if (long_) { long val; ss >> val; - return Boxed_Value(const_var(val)); + return const_var(val); } else { int val; ss >> val; - return Boxed_Value(const_var(val)); + return const_var(val); } } } - /** - * Reads a number from the input, detecting if it's an integer or floating point - */ - bool Num(bool t_capture = false) { + /// Reads a number from the input, detecting if it's an integer or floating point + bool Num(const bool t_capture = false) { SkipWS(); if (!t_capture) { return Hex_() || Float_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; + } else { + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) { if (Hex_()) { std::string match(start, m_input_pos); - Boxed_Value i = buildInt(std::hex, match); - AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.emplace_back(std::make_shared(std::move(match), buildInt(std::hex, match), m_filename, prev_line, prev_col, m_line, m_col)); return true; } + if (Binary_()) { std::string match(start, m_input_pos); int64_t temp_int = 0; - size_t pos = 0, end = match.length(); + size_t pos = 0; + const auto end = match.length(); while ((pos < end) && (pos < (2 + sizeof(int) * 8))) { temp_int <<= 1; @@ -661,34 +592,27 @@ namespace chaiscript Boxed_Value i; if (match.length() <= sizeof(int) * 8) { - i = Boxed_Value(const_var(int(temp_int))); + i = const_var(static_cast(temp_int)); } else { - i = Boxed_Value(const_var(temp_int)); + i = const_var(temp_int); } - AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), std::move(i), m_filename, prev_line, prev_col, m_line, m_col)); return true; } if (Float_()) { std::string match(start, m_input_pos); - Boxed_Value f = buildFloat(match); - AST_NodePtr t(new eval::Float_AST_Node(match, f, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), buildFloat(match), m_filename, prev_line, prev_col, m_line, m_col)); return true; } else { IntSuffix_(); std::string match(start, m_input_pos); - if ((match.size() > 0) && (match[0] == '0')) { - Boxed_Value i = buildInt(std::oct, match); - AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + if (!match.empty() && (match[0] == '0')) { + m_match_stack.push_back(std::make_shared(std::move(match), buildInt(std::oct, match), m_filename, prev_line, prev_col, m_line, m_col)); } else { - Boxed_Value i = buildInt(std::dec, match); - AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), buildInt(std::dec, match), m_filename, prev_line, prev_col, m_line, m_col)); } return true; } @@ -699,23 +623,19 @@ namespace chaiscript } } - /** - * Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace - */ + /// Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace bool Id_() { - bool retval = false; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::id_alphabet)) { - retval = true; while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { ++m_input_pos; ++m_col; } - } - else if (has_more_input() && (*m_input_pos == '`')) { - retval = true; + + return true; + } else if (has_more_input() && (*m_input_pos == '`')) { ++m_col; ++m_input_pos; - std::string::const_iterator start = m_input_pos; + const auto start = m_input_pos; while (has_more_input() && (*m_input_pos != '`')) { if (Eol()) { @@ -736,52 +656,44 @@ namespace chaiscript ++m_col; ++m_input_pos; + + return true; } - return retval; + return false; } - /** - * Reads (and potentially captures) an identifier from input - */ - bool Id(bool t_capture = false) { + /// Reads (and potentially captures) an identifier from input + bool Id(const bool t_capture = false) { SkipWS(); if (!t_capture) { return Id_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; + } else { + const auto start = m_input_pos; + const int prev_col = m_col; + const int prev_line = m_line; if (Id_()) { + std::string match; if (*start == '`') { //Id Literal - std::string match(start+1, m_input_pos-1); - AST_NodePtr t(new eval::Id_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; + match = std::string(start+1, m_input_pos-1); + } else { + match = std::string(start, m_input_pos); } - else { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Id_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - } - else { + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + return true; + } else { return false; } } } - /** - * Checks for a node annotation of the form "#" - */ + /// Checks for a node annotation of the form "#" bool Annotation() { SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; if (Symbol_("#")) { do { while (m_input_pos != m_input_end) { @@ -796,8 +708,7 @@ namespace chaiscript } while (Symbol("#")); std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Annotation_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); return true; } else { @@ -805,13 +716,9 @@ namespace chaiscript } } - /** - * Reads a quoted string from input, without skipping initial whitespace - */ + /// Reads a quoted string from input, without skipping initial whitespace bool Quoted_String_() { - bool retval = false; if (has_more_input() && (*m_input_pos == '\"')) { - retval = true; char prev_char = *m_input_pos; ++m_input_pos; ++m_col; @@ -820,8 +727,7 @@ namespace chaiscript if (!Eol_()) { if (prev_char == '\\') { prev_char = 0; - } - else { + } else { prev_char = *m_input_pos; } ++m_input_pos; @@ -832,33 +738,32 @@ namespace chaiscript if (has_more_input()) { ++m_input_pos; ++m_col; - } - else { + } else { throw exception::eval_error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); } + + return true; } - return retval; + return false; } - /** - * Reads (and potentially captures) a quoted string from input. Translates escaped sequences. - */ - bool Quoted_String(bool t_capture = false) { + /// Reads (and potentially captures) a quoted string from input. Translates escaped sequences. + bool Quoted_String(const bool t_capture = false) { SkipWS(); if (!t_capture) { return Quoted_String_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; + } else { + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + if (Quoted_String_()) { std::string match; bool is_escaped = false; bool is_interpolated = false; bool saw_interpolation_marker = false; - size_t prev_stack_top = m_match_stack.size(); + const auto prev_stack_top = m_match_stack.size(); std::string::const_iterator s = start + 1, end = m_input_pos - 1; @@ -869,76 +774,62 @@ namespace chaiscript if (is_interpolated) { //If we've seen previous interpolation, add on instead of making a new one + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - - build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); - } - else { - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + build_match(std::make_shared(), prev_stack_top); + } else { + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); } //We've finished with the part of the string up to this point, so clear it - match = ""; + match.clear(); std::string eval_match; ++s; - while ((*s != '}') && (s != end)) { + while ((s != end) && (*s != '}')) { eval_match.push_back(*s); ++s; } + if (*s == '}') { is_interpolated = true; ++s; - size_t tostr_stack_top = m_match_stack.size(); + const auto tostr_stack_top = m_match_stack.size(); - AST_NodePtr tostr(new eval::Id_AST_Node("to_string", m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(tostr); + m_match_stack.push_back(std::make_shared("to_string", m_filename, prev_line, prev_col, m_line, m_col)); - size_t ev_stack_top = m_match_stack.size(); + const auto ev_stack_top = m_match_stack.size(); - AST_NodePtr ev(new eval::Id_AST_Node("eval", m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(ev); + /// \todo can we evaluate this in place and save the runtime cost of evaluating with each execution of the node? + m_match_stack.push_back(std::make_shared("eval", m_filename, prev_line, prev_col, m_line, m_col)); - size_t arg_stack_top = m_match_stack.size(); + const auto arg_stack_top = m_match_stack.size(); - AST_NodePtr t(new eval::Quoted_String_AST_Node(eval_match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(eval_match, m_filename, prev_line, prev_col, m_line, m_col)); - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), arg_stack_top); - - build_match(AST_NodePtr(new eval::Inplace_Fun_Call_AST_Node()), ev_stack_top); - - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), ev_stack_top); - - build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), tostr_stack_top); - - build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); - } - else { + build_match(std::make_shared(), arg_stack_top); + build_match(std::make_shared(), ev_stack_top); + build_match(std::make_shared(), ev_stack_top); + build_match(std::make_shared(), tostr_stack_top); + build_match(std::make_shared(), prev_stack_top); + } else { throw exception::eval_error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); } - } - else { + } else { match.push_back('$'); } saw_interpolation_marker = false; - } - else { + } else { if (*s == '\\') { if (is_escaped) { match.push_back('\\'); is_escaped = false; - } - else { + } else { is_escaped = true; } - } - else { + } else { if (is_escaped) { switch (*s) { case ('b') : match.push_back('\b'); break; @@ -947,15 +838,13 @@ namespace chaiscript case ('r') : match.push_back('\r'); break; case ('t') : match.push_back('\t'); break; case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; + case ('\"') : match.push_back('\"'); break; case ('$') : match.push_back('$'); break; default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); } - } - else if (*s == '$') { + } else if (*s == '$') { saw_interpolation_marker = true; - } - else { + } else { match.push_back(*s); } is_escaped = false; @@ -963,1551 +852,1425 @@ namespace chaiscript ++s; } } - if (is_interpolated) { - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); + if (is_interpolated) { + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); + + build_match(std::make_shared(), prev_stack_top); + } else { + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); } - else { - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + return true; + } else { + return false; + } + } + } + + /// Reads a character group from input, without skipping initial whitespace + bool Single_Quoted_String_() { + bool retval = false; + if (has_more_input() && (*m_input_pos == '\'')) { + retval = true; + char prev_char = *m_input_pos; + ++m_input_pos; + ++m_col; + + while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { + if (!Eol_()) { + if (prev_char == '\\') { + prev_char = 0; + } else { + prev_char = *m_input_pos; + } + ++m_input_pos; + ++m_col; } + } + + if (m_input_pos != m_input_end) { + ++m_input_pos; + ++m_col; + } else { + throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); + } + } + return retval; + } + + /// Reads (and potentially captures) a char group from input. Translates escaped sequences. + bool Single_Quoted_String(const bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Single_Quoted_String_(); + } else { + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + if (Single_Quoted_String_()) { + std::string match; + bool is_escaped = false; + for (auto s = start + 1, end = m_input_pos - 1; s != end; ++s) { + if (*s == '\\') { + if (is_escaped) { + match.push_back('\\'); + is_escaped = false; + } else { + is_escaped = true; + } + } else { + if (is_escaped) { + switch (*s) { + case ('b') : match.push_back('\b'); break; + case ('f') : match.push_back('\f'); break; + case ('n') : match.push_back('\n'); break; + case ('r') : match.push_back('\r'); break; + case ('t') : match.push_back('\t'); break; + case ('\'') : match.push_back('\''); break; + case ('\"') : match.push_back('\"'); break; + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); + } + } else { + match.push_back(*s); + } + is_escaped = false; + } + } + m_match_stack.push_back(std::make_shared(match, m_filename, prev_line, prev_col, m_line, m_col)); return true; } else { return false; } - } } + } - /** - * Reads a character group from input, without skipping initial whitespace - */ - bool Single_Quoted_String_() { - bool retval = false; - if (has_more_input() && (*m_input_pos == '\'')) { - retval = true; - char prev_char = *m_input_pos; - ++m_input_pos; - ++m_col; - - while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { - if (!Eol_()) { - if (prev_char == '\\') { - prev_char = 0; - } - else { - prev_char = *m_input_pos; - } - ++m_input_pos; - ++m_col; - } - } - - if (m_input_pos != m_input_end) { - ++m_input_pos; - ++m_col; - } - else { - throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); - } - } - return retval; + /// Reads a char from input if it matches the parameter, without skipping initial whitespace + bool Char_(const char c) { + if (has_more_input() && (*m_input_pos == c)) { + ++m_input_pos; + ++m_col; + return true; + } else { + return false; } + } - /** - * Reads (and potentially captures) a char group from input. Translates escaped sequences. - */ - bool Single_Quoted_String(bool t_capture = false) { - SkipWS(); + /// Reads (and potentially captures) a char from input if it matches the parameter + bool Char(const char t_c, bool t_capture = false) { + SkipWS(); - if (!t_capture) { - return Single_Quoted_String_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Single_Quoted_String_()) { - std::string match; - bool is_escaped = false; - for (std::string::const_iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { - if (*s == '\\') { - if (is_escaped) { - match.push_back('\\'); - is_escaped = false; - } - else { - is_escaped = true; - } - } - else { - if (is_escaped) { - switch (*s) { - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); - } - } - else { - match.push_back(*s); - } - is_escaped = false; - } - } - AST_NodePtr t(new eval::Single_Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - return false; - } - } - } - - /** - * Reads a char from input if it matches the parameter, without skipping initial whitespace - */ - bool Char_(char c) { - bool retval = false; - if (has_more_input() && (*m_input_pos == c)) { - ++m_input_pos; - ++m_col; - retval = true; - } - - return retval; - } - - /** - * Reads (and potentially captures) a char from input if it matches the parameter - */ - bool Char(char t_c, bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Char_(t_c); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Char_(t_c)) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Char_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - return false; - } - } - } - - /** - * Reads a string from input if it matches the parameter, without skipping initial whitespace - */ - bool Keyword_(const char *t_s) { - bool retval = false; - size_t len = strlen(t_s); - - if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { - std::string::const_iterator tmp = m_input_pos; - for (size_t i = 0; i < len; ++i) { - if (*tmp != t_s[i]) { - return false; - } - ++tmp; - } - retval = true; - m_input_pos = tmp; - m_col += static_cast(len); - } - - return retval; - } - - /** - * Reads (and potentially captures) a string from input if it matches the parameter - */ - bool Keyword(const char *t_s, bool t_capture = false) { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - bool retval = Keyword_(t_s); - // ignore substring matches - if ( retval && has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { - m_input_pos = start; - m_col = prev_col; - m_line = prev_line; - retval = false; - } - - if ( t_capture && retval ) { + if (!t_capture) { + return Char_(t_c); + } else { + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + if (Char_(t_c)) { std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Str_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + return true; + } else { + return false; } - return retval; } + } - /** - * Reads a symbol group from input if it matches the parameter, without skipping initial whitespace - */ - bool Symbol_(const char *t_s) { - bool retval = false; - size_t len = strlen(t_s); + /// Reads a string from input if it matches the parameter, without skipping initial whitespace + bool Keyword_(const char *t_s) { + const auto len = strlen(t_s); - if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { - std::string::const_iterator tmp = m_input_pos; - for (size_t i = 0; i < len; ++i) { - if (*tmp != t_s[i]) { - return false; - } - ++tmp; - } - retval = true; - m_input_pos = tmp; - m_col += static_cast(len); - } - - return retval; - } - - /** - * Reads (and potentially captures) a symbol group from input if it matches the parameter - */ - bool Symbol(const char *t_s, bool t_capture = false, bool t_disallow_prevention=false) { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - bool retval = Symbol_(t_s); - // ignore substring matches - if (retval && has_more_input() && (t_disallow_prevention == false) && char_in_alphabet(*m_input_pos,detail::symbol_alphabet)) { - m_input_pos = start; - m_col = prev_col; - m_line = prev_line; - retval = false; - } - - if ( t_capture && retval ) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Str_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - - return retval; - } - - /** - * Reads an end-of-line group from input, without skipping initial whitespace - */ - bool Eol_() { - bool retval = false; - - if (has_more_input() && (Symbol_("\r\n") || Char_('\n'))) { - retval = true; - ++m_line; - m_col = 1; - } - else if (has_more_input() && Char_(';')) { - retval = true; - } - - return retval; - } - - /** - * Reads (and potentially captures) an end-of-line group from input - */ - bool Eol(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Eol_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Eol_()) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Eol_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { + if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { + auto tmp = m_input_pos; + for (size_t i = 0; i < len; ++i) { + if (*tmp != t_s[i]) { return false; } + ++tmp; } + m_input_pos = tmp; + m_col += static_cast(len); + return true; } - /** - * Reads a comma-separated list of values from input - */ - bool Arg_List() { + return false; + } - SkipWS(true); - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Equation()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Equation()) { - throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - - SkipWS(true); - - return retval; + /// Reads (and potentially captures) a string from input if it matches the parameter + bool Keyword(const char *t_s, bool t_capture = false) { + SkipWS(); + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + bool retval = Keyword_(t_s); + // ignore substring matches + if ( retval && has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { + m_input_pos = start; + m_col = prev_col; + m_line = prev_line; + retval = false; } - /** - * Reads possible special container values, including ranges and map_pairs - */ - bool Container_Arg_List() { - bool retval = false; - SkipWS(true); + if ( t_capture && retval ) { + std::string match(start, m_input_pos); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + } + return retval; + } - size_t prev_stack_top = m_match_stack.size(); + /// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace + bool Symbol_(const char *t_s) { + const auto len = strlen(t_s); - if (Value_Range()) { - retval = true; - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - else if (Map_Pair()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Map_Pair()) { - throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); + if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { + auto tmp = m_input_pos; + for (size_t i = 0; i < len; ++i) { + if (*tmp != t_s[i]) { + return false; } - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + ++tmp; } - else if (Operator()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Operator()) { - throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - - SkipWS(true); - - return retval; - + m_input_pos = tmp; + m_col += static_cast(len); + return true; } - /** - * Reads a lambda (anonymous function) from input - */ - bool Lambda() { - bool retval = false; + return false; + } - size_t prev_stack_top = m_match_stack.size(); + /// Reads (and potentially captures) a symbol group from input if it matches the parameter + bool Symbol(const char *t_s, const bool t_capture = false, const bool t_disallow_prevention=false) { + SkipWS(); + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + bool retval = Symbol_(t_s); - if (Keyword("fun")) { - retval = true; + // ignore substring matches + if (retval && has_more_input() && (t_disallow_prevention == false) && char_in_alphabet(*m_input_pos,detail::symbol_alphabet)) { + m_input_pos = start; + m_col = prev_col; + m_line = prev_line; + retval = false; + } - if (Char('(')) { - Arg_List(); - if (!Char(')')) { - throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); + if ( t_capture && retval ) { + std::string match(start, m_input_pos); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + } + + return retval; + } + + /// Reads an end-of-line group from input, without skipping initial whitespace + bool Eol_() { + bool retval = false; + + if (has_more_input() && (Symbol_("\r\n") || Char_('\n'))) { + retval = true; + ++m_line; + m_col = 1; + } else if (has_more_input() && Char_(';')) { + retval = true; + } + + return retval; + } + + /// Reads (and potentially captures) an end-of-line group from input + bool Eol(const bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Eol_(); + } else { + const auto start = m_input_pos; + const auto prev_col = m_col; + const auto prev_line = m_line; + if (Eol_()) { + std::string match(start, m_input_pos); + m_match_stack.push_back(std::make_shared(std::move(match), m_filename, prev_line, prev_col, m_line, m_col)); + return true; + } else { + return false; + } + } + } + + /// Reads a comma-separated list of values from input + bool Arg_List() { + SkipWS(true); + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Equation()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Equation()) { + throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); } - } + } while (Char(',')); + } + build_match(std::make_shared(), prev_stack_top); + } - while (Eol()) {} + SkipWS(true); - if (!Block()) { + return retval; + } + + /// Reads possible special container values, including ranges and map_pairs + bool Container_Arg_List() { + bool retval = false; + SkipWS(true); + + const auto prev_stack_top = m_match_stack.size(); + + if (Value_Range()) { + retval = true; + build_match(std::make_shared(), prev_stack_top); + } else if (Map_Pair()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Map_Pair()) { + throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + } + } while (Char(',')); + } + build_match(std::make_shared(), prev_stack_top); + } else if (Operator()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Operator()) { + throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + } + } while (Char(',')); + } + build_match(std::make_shared(), prev_stack_top); + } + + SkipWS(true); + + return retval; + } + + /// Reads a lambda (anonymous function) from input + bool Lambda() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("fun")) { + retval = true; + + if (Char('(')) { + Arg_List(); + if (!Char(')')) { throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); } - - build_match(AST_NodePtr(new eval::Lambda_AST_Node()), prev_stack_top); } - return retval; + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); } - /** - * Reads a function definition from input - */ - bool Def(bool t_class_context = false) { - bool retval = false; - bool is_annotated = false; - AST_NodePtr annotation; + return retval; + } - if (Annotation()) { - while (Eol_()) {} - annotation = m_match_stack.back(); - m_match_stack.pop_back(); - is_annotated = true; + /// Reads a function definition from input + bool Def(const bool t_class_context = false) { + bool retval = false; + AST_NodePtr annotation; + + if (Annotation()) { + while (Eol_()) {} + annotation = m_match_stack.back(); + m_match_stack.pop_back(); + } + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("def")) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Missing function name in definition", File_Position(m_line, m_col), *m_filename); } - size_t prev_stack_top = m_match_stack.size(); + bool is_method = false; - if (Keyword("def")) { - retval = true; + if (Symbol("::", false)) { + //We're now a method + is_method = true; if (!Id(true)) { - throw exception::eval_error("Missing function name in definition", File_Position(m_line, m_col), *m_filename); - } - - bool is_method = false; - - if (Symbol("::", false)) { - //We're now a method - is_method = true; - - if (!Id(true)) { - throw exception::eval_error("Missing method name in definition", File_Position(m_line, m_col), *m_filename); - } - } - - if (Char('(')) { - Arg_List(); - if (!Char(')')) { - throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); - } - } - - while (Eol()) {} - - if (Char(':')) { - if (!Operator()) { - throw exception::eval_error("Missing guard expression for function", File_Position(m_line, m_col), *m_filename); - } - } - - while (Eol()) {} - if (!Block()) { - throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); - } - - if (is_method || t_class_context) { - build_match(AST_NodePtr(new eval::Method_AST_Node()), prev_stack_top); - } - else { - build_match(AST_NodePtr(new eval::Def_AST_Node()), prev_stack_top); - } - - if (is_annotated) { - m_match_stack.back()->annotation = annotation; + throw exception::eval_error("Missing method name in definition", File_Position(m_line, m_col), *m_filename); } } - return retval; + if (Char('(')) { + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); + } + } + + while (Eol()) {} + + if (Char(':')) { + if (!Operator()) { + throw exception::eval_error("Missing guard expression for function", File_Position(m_line, m_col), *m_filename); + } + } + + while (Eol()) {} + if (!Block()) { + throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); + } + + if (is_method || t_class_context) { + build_match(std::make_shared(), prev_stack_top); + } else { + build_match(std::make_shared(), prev_stack_top); + } + + if (annotation) { + m_match_stack.back()->annotation = std::move(annotation); + } } - /** - * Reads a function definition from input - */ - bool Try() { - bool retval = false; + return retval; + } - size_t prev_stack_top = m_match_stack.size(); + /// Reads a function definition from input + bool Try() { + bool retval = false; - if (Keyword("try")) { - retval = true; + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("try")) { + retval = true; + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'try' block", File_Position(m_line, m_col), *m_filename); + } + + bool has_matches = true; + while (has_matches) { + while (Eol()) {} + has_matches = false; + if (Keyword("catch", false)) { + const auto catch_stack_top = m_match_stack.size(); + if (Char('(')) { + if (!(Id(true) && Char(')'))) { + throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); + } + if (Char(':')) { + if (!Operator()) { + throw exception::eval_error("Missing guard expression for catch", File_Position(m_line, m_col), *m_filename); + } + } + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); + } + build_match(std::make_shared(), catch_stack_top); + has_matches = true; + } + } + while (Eol()) {} + if (Keyword("finally", false)) { + const auto finally_stack_top = m_match_stack.size(); while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'try' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); } + build_match(std::make_shared(), finally_stack_top); + } - bool has_matches = true; - while (has_matches) { - while (Eol()) {} - has_matches = false; - if (Keyword("catch", false)) { - size_t catch_stack_top = m_match_stack.size(); - if (Char('(')) { - if (!(Id(true) && Char(')'))) { - throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); - } - if (Char(':')) { - if (!Operator()) { - throw exception::eval_error("Missing guard expression for catch", File_Position(m_line, m_col), *m_filename); - } - } + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads an if/else if/else block from input + bool If() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("if")) { + retval = true; + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'if' block", File_Position(m_line, m_col), *m_filename); + } + + bool has_matches = true; + while (has_matches) { + while (Eol()) {} + has_matches = false; + if (Keyword("else", true)) { + if (Keyword("if")) { + const AST_NodePtr back(m_match_stack.back()); + m_match_stack.back() = std::make_shared("else if"); + m_match_stack.back()->start = back->start; + m_match_stack.back()->end = back->end; + m_match_stack.back()->children = back->children; + m_match_stack.back()->annotation = back->annotation; + if (!Char('(')) { + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); } while (Eol()) {} if (!Block()) { - throw exception::eval_error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'else if' block", File_Position(m_line, m_col), *m_filename); + } + has_matches = true; + } else { + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'else' block", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new eval::Catch_AST_Node()), catch_stack_top); has_matches = true; } } - while (Eol()) {} - if (Keyword("finally", false)) { - size_t finally_stack_top = m_match_stack.size(); - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); - } - build_match(AST_NodePtr(new eval::Finally_AST_Node()), finally_stack_top); - } - - build_match(AST_NodePtr(new eval::Try_AST_Node()), prev_stack_top); } - return retval; + build_match(std::make_shared(), prev_stack_top); } - /** - * Reads an if/else if/else block from input - */ - bool If() { - bool retval = false; + return retval; + } - size_t prev_stack_top = m_match_stack.size(); + /// Reads a class block from input + bool Class() { + bool retval = false; - if (Keyword("if")) { - retval = true; + size_t prev_stack_top = m_match_stack.size(); - if (!Char('(')) { - throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); - } + if (Keyword("class")) { + retval = true; - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'if' block", File_Position(m_line, m_col), *m_filename); - } - - bool has_matches = true; - while (has_matches) { - while (Eol()) {} - has_matches = false; - if (Keyword("else", true)) { - if (Keyword("if")) { - AST_NodePtr back(m_match_stack.back()); - m_match_stack.back() = AST_NodePtr(new eval::If_AST_Node("else if")); - m_match_stack.back()->start = back->start; - m_match_stack.back()->end = back->end; - m_match_stack.back()->children = back->children; - m_match_stack.back()->annotation = back->annotation; - if (!Char('(')) { - throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'else if' block", File_Position(m_line, m_col), *m_filename); - } - has_matches = true; - } - else { - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'else' block", File_Position(m_line, m_col), *m_filename); - } - has_matches = true; - } - } - } - - build_match(AST_NodePtr(new eval::If_AST_Node()), prev_stack_top); + if (!Id(true)) { + throw exception::eval_error("Missing class name in definition", File_Position(m_line, m_col), *m_filename); } - return retval; - } - /** - * Reads a class block from input - */ - bool Class() { - bool retval = false; + while (Eol()) {} - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("class")) { - retval = true; - - if (!Id(true)) { - throw exception::eval_error("Missing class name in definition", File_Position(m_line, m_col), *m_filename); - } - - - while (Eol()) {} - - if (!Class_Block()) { - throw exception::eval_error("Incomplete 'class' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Class_AST_Node()), prev_stack_top); + if (!Class_Block()) { + throw exception::eval_error("Incomplete 'class' block", File_Position(m_line, m_col), *m_filename); } - return retval; + build_match(std::make_shared(), prev_stack_top); } + return retval; + } - /** - * Reads a while block from input - */ - bool While() { - bool retval = false; - size_t prev_stack_top = m_match_stack.size(); + /// Reads a while block from input + bool While() { + bool retval = false; - if (Keyword("while")) { - retval = true; + const auto prev_stack_top = m_match_stack.size(); - if (!Char('(')) { - throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); - } + if (Keyword("while")) { + retval = true; - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'while' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::While_AST_Node()), prev_stack_top); + if (!Char('(')) { + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); } - return retval; + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'while' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); } + return retval; + } - /** - * Reads the C-style for conditions from input - */ - bool For_Guards() { - if (!(Equation() && Eol())) + + /// Reads the C-style for conditions from input + bool For_Guards() { + if (!(Equation() && Eol())) + { + if (!Eol()) { - if (!Eol()) - { - throw exception::eval_error("'for' loop initial statment missing", File_Position(m_line, m_col), *m_filename); - } else { - AST_NodePtr t(new eval::Noop_AST_Node()); - m_match_stack.push_back(t); - } - } - - if (!(Equation() && Eol())) - { - if (!Eol()) - { - throw exception::eval_error("'for' loop condition missing", File_Position(m_line, m_col), *m_filename); - } else { - AST_NodePtr t(new eval::Noop_AST_Node()); - m_match_stack.push_back(t); - } - } - - if (!Equation()) - { - AST_NodePtr t(new eval::Noop_AST_Node()); - m_match_stack.push_back(t); - } - - return true; - } - - /** - * Reads a for block from input - */ - bool For() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("for")) { - retval = true; - - if (!Char('(')) { - throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(For_Guards() && Char(')'))) { - throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'for' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::For_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a case block from input - */ - bool Case() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("case")) { - retval = true; - - if (!Char('(')) { - throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'case' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Case_AST_Node()), prev_stack_top); - } - else if (Keyword("default")) { - while (Eol()) {} - - if (!Block()) { - throw exception::eval_error("Incomplete 'default' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Default_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a switch statement from input - */ - bool Switch() { - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("switch")) { - - if (!Char('(')) { - throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (Char('{')) { - while (Eol()) {} - - while (Case()) { - while (Eol()) { } // eat - } - - while (Eol()) { } // eat - - if (!Char('}')) { - throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); - } - } - else { - throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Switch_AST_Node()), prev_stack_top); - return true; - + throw exception::eval_error("'for' loop initial statment missing", File_Position(m_line, m_col), *m_filename); } else { - return false; + m_match_stack.push_back(std::make_shared()); } - } - /** - * Reads a curly-brace C-style class block from input - */ - bool Class_Block() { - bool retval = false; + if (!(Equation() && Eol())) + { + if (!Eol()) + { + throw exception::eval_error("'for' loop condition missing", File_Position(m_line, m_col), *m_filename); + } else { + m_match_stack.push_back(std::make_shared()); + } + } - size_t prev_stack_top = m_match_stack.size(); + if (!Equation()) + { + m_match_stack.push_back(std::make_shared()); + } + + return true; + } + + /** + * Reads a for block from input + */ + bool For() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("for")) { + retval = true; + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(For_Guards() && Char(')'))) { + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'for' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads a case block from input + bool Case() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("case")) { + retval = true; + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'case' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Keyword("default")) { + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'default' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + + /// Reads a switch statement from input + bool Switch() { + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("switch")) { + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} if (Char('{')) { - retval = true; + while (Eol()) {} - Class_Statements(); - if (!Char('}')) { - throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename); + while (Case()) { + while (Eol()) { } // eat } - build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top); - } + while (Eol()) { } // eat - return retval; - } - - /** - * Reads a curly-brace C-style block from input - */ - bool Block() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Char('{')) { - retval = true; - - Statements(); if (!Char('}')) { throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); } - - build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a return statement from input - */ - bool Return() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("return")) { - retval = true; - - Operator(); - build_match(AST_NodePtr(new eval::Return_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a break statement from input - */ - bool Break() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("break")) { - retval = true; - - build_match(AST_NodePtr(new eval::Break_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a continue statement from input - */ - bool Continue() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("continue")) { - retval = true; - - build_match(AST_NodePtr(new eval::Continue_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a dot expression(member access), then proceeds to check if it's a function or array call - */ - bool Dot_Fun_Array() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - if (Lambda() || Num(true) || Quoted_String(true) || Single_Quoted_String(true) || - Paren_Expression() || Inline_Container() || Id(true)) { - retval = true; - bool has_more = true; - - while (has_more) { - has_more = false; - - if (Char('(')) { - has_more = true; - - Arg_List(); - if (!Char(')')) { - throw exception::eval_error("Incomplete function call", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), prev_stack_top); - /// \todo Work around for method calls until we have a better solution - if (!m_match_stack.back()->children.empty()) { - if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) { - AST_NodePtr dot_access = m_match_stack.back()->children[0]; - AST_NodePtr func_call = m_match_stack.back(); - m_match_stack.pop_back(); - func_call->children.erase(func_call->children.begin()); - func_call->children.insert(func_call->children.begin(), dot_access->children.back()); - dot_access->children.pop_back(); - dot_access->children.push_back(func_call); - m_match_stack.push_back(dot_access); - } - } - } - else if (Char('[')) { - has_more = true; - - if (!(Operator() && Char(']'))) { - throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Array_Call_AST_Node()), prev_stack_top); - } - else if (Symbol(".", true)) { - has_more = true; - if (!(Id(true))) { - throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Dot_Access_AST_Node()), prev_stack_top); - } - } - } - - return retval; - } - - /** - * Reads a variable declaration from input - */ - bool Var_Decl(bool t_class_context = false) { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) { - retval = true; - - if (!Id(true)) { - throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top); - } else if (Keyword("auto") || Keyword("var")) { - retval = true; - - if (!(Reference() || Id(true))) { - throw exception::eval_error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Var_Decl_AST_Node()), prev_stack_top); - } else if (Keyword("attr")) { - retval = true; - - if (!Id(true)) { - throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - if (!Symbol("::", false)) { - throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - if (!Id(true)) { - throw exception::eval_error("Missing attribute name in definition", File_Position(m_line, m_col), *m_filename); - } - - - build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads an expression surrounded by parentheses from input - */ - bool Paren_Expression() { - bool retval = false; - - if (Char('(')) { - retval = true; - if (!Operator()) { - throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename); - } - if (!Char(')')) { - throw exception::eval_error("Missing closing parenthesis ')'", File_Position(m_line, m_col), *m_filename); - } - } - return retval; - } - - /** - * Reads, and identifies, a short-form container initialization from input - */ - bool Inline_Container() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Char('[')) { - retval = true; - Container_Arg_List(); - - if (!Char(']')) { - throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_line, m_col), *m_filename); - } - if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { - if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { - build_match(AST_NodePtr(new eval::Inline_Range_AST_Node()), prev_stack_top); - } - else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { - build_match(AST_NodePtr(new eval::Inline_Map_AST_Node()), prev_stack_top); - } - else { - build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); - } - } - else { - build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); - } - } - - return retval; - } - - bool Reference() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Symbol("&", false)) { - retval = true; - - if (!Id(true)) { - throw exception::eval_error("Incomplete '&' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr( - new eval::Reference_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a unary prefixed expression from input - */ - bool Prefix() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Symbol("++", true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Symbol("--", true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('-', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('+', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('!', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('~', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('&', true)) { - retval = true; - - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Parses any of a group of 'value' style ast_node groups from input - */ - bool Value() { - if (Var_Decl() || Dot_Fun_Array() || Prefix()) { - return true; } else { - return false; + throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); } - } - bool Operator_Helper(size_t t_precedence) { - for (auto & elem : m_operator_matches[t_precedence]) { - if (Symbol(elem.c_str(), true)) { - return true; - } - } + build_match(std::make_shared(), prev_stack_top); + return true; + + } else { return false; } - bool Operator(size_t t_precedence = 0) { - bool retval = false; - AST_NodePtr oper; - size_t prev_stack_top = m_match_stack.size(); + } - if (t_precedence < m_operators.size()) { - if (Operator(t_precedence+1)) { - retval = true; - if (Operator_Helper(t_precedence)) { - do { - while (Eol()) {} - if (!Operator(t_precedence+1)) { - throw exception::eval_error("Incomplete " - + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", - File_Position(m_line, m_col), *m_filename); - } - switch (m_operators[t_precedence]) { - case(AST_Node_Type::Comparison) : - build_match(AST_NodePtr(new eval::Comparison_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Ternary_Cond) : - m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, - m_match_stack.begin() + m_match_stack.size() - 1); - if (Symbol(":")) { - if (!Operator(t_precedence+1)) { - throw exception::eval_error("Incomplete " - + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", - File_Position(m_line, m_col), *m_filename); - } - build_match(AST_NodePtr(new eval::Ternary_Cond_AST_Node()), prev_stack_top); - } - else { + /// Reads a curly-brace C-style class block from input + bool Class_Block() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Char('{')) { + retval = true; + + Class_Statements(); + if (!Char('}')) { + throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads a curly-brace C-style block from input + bool Block() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Char('{')) { + retval = true; + + Statements(); + if (!Char('}')) { + throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads a return statement from input + bool Return() { + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("return")) { + Operator(); + build_match(std::make_shared(), prev_stack_top); + return true; + } else { + return false; + } + } + + /// Reads a break statement from input + bool Break() { + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("break")) { + build_match(std::make_shared(), prev_stack_top); + return true; + } else { + return false; + } + } + + /// Reads a continue statement from input + bool Continue() { + const auto prev_stack_top = m_match_stack.size(); + + if (Keyword("continue")) { + build_match(std::make_shared(), prev_stack_top); + return true; + } else { + return false; + } + } + + /// Reads a dot expression(member access), then proceeds to check if it's a function or array call + bool Dot_Fun_Array() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + if (Lambda() || Num(true) || Quoted_String(true) || Single_Quoted_String(true) || + Paren_Expression() || Inline_Container() || Id(true)) + { + retval = true; + bool has_more = true; + + while (has_more) { + has_more = false; + + if (Char('(')) { + has_more = true; + + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete function call", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + /// \todo Work around for method calls until we have a better solution + if (!m_match_stack.back()->children.empty()) { + if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) { + AST_NodePtr dot_access = m_match_stack.back()->children[0]; + AST_NodePtr func_call = m_match_stack.back(); + m_match_stack.pop_back(); + func_call->children.erase(func_call->children.begin()); + func_call->children.insert(func_call->children.begin(), dot_access->children.back()); + dot_access->children.pop_back(); + dot_access->children.push_back(std::move(func_call)); + m_match_stack.push_back(std::move(dot_access)); + } + } + } else if (Char('[')) { + has_more = true; + + if (!(Operator() && Char(']'))) { + throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else if (Symbol(".", true)) { + has_more = true; + if (!(Id(true))) { + throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + } + } + + return retval; + } + + /// Reads a variable declaration from input + bool Var_Decl(const bool t_class_context = false) { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Keyword("auto") || Keyword("var")) { + retval = true; + + if (!(Reference() || Id(true))) { + throw exception::eval_error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Keyword("attr")) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + if (!Symbol("::", false)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + if (!Id(true)) { + throw exception::eval_error("Missing attribute name in definition", File_Position(m_line, m_col), *m_filename); + } + + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Reads an expression surrounded by parentheses from input + bool Paren_Expression() { + if (Char('(')) { + if (!Operator()) { + throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename); + } + if (!Char(')')) { + throw exception::eval_error("Missing closing parenthesis ')'", File_Position(m_line, m_col), *m_filename); + } + return true; + } else { + return false; + } + } + + /// Reads, and identifies, a short-form container initialization from input + bool Inline_Container() { + const auto prev_stack_top = m_match_stack.size(); + + if (Char('[')) { + Container_Arg_List(); + + if (!Char(']')) { + throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_line, m_col), *m_filename); + } + if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { + if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { + build_match(std::make_shared(), prev_stack_top); + } + else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { + build_match(std::make_shared(), prev_stack_top); + } + else { + build_match(std::make_shared(), prev_stack_top); + } + } + else { + build_match(std::make_shared(), prev_stack_top); + } + + return true; + } else { + return false; + } + } + + /// Parses a variable specified with a & aka reference + bool Reference() { + const auto prev_stack_top = m_match_stack.size(); + + if (Symbol("&", false)) { + if (!Id(true)) { + throw exception::eval_error("Incomplete '&' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + return true; + } else { + return false; + } + } + + /// Reads a unary prefixed expression from input + bool Prefix() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Symbol("++", true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Symbol("--", true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Char('-', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } else if (Char('+', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else if (Char('!', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else if (Char('~', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else if (Char('&', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + + return retval; + } + + /// Parses any of a group of 'value' style ast_node groups from input + bool Value() { + if (Var_Decl() || Dot_Fun_Array() || Prefix()) { + return true; + } else { + return false; + } + } + + bool Operator_Helper(const size_t t_precedence) { + for (auto & elem : m_operator_matches[t_precedence]) { + if (Symbol(elem.c_str(), true)) { + return true; + } + } + return false; + } + + bool Operator(const size_t t_precedence = 0) { + bool retval = false; + AST_NodePtr oper; + const auto prev_stack_top = m_match_stack.size(); + + if (t_precedence < m_operators.size()) { + if (Operator(t_precedence+1)) { + retval = true; + if (Operator_Helper(t_precedence)) { + do { + while (Eol()) {} + if (!Operator(t_precedence+1)) { + throw exception::eval_error("Incomplete " + + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", + File_Position(m_line, m_col), *m_filename); + } + + switch (m_operators[t_precedence]) { + case(AST_Node_Type::Comparison) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Ternary_Cond) : + m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, + m_match_stack.begin() + m_match_stack.size() - 1); + if (Symbol(":")) { + if (!Operator(t_precedence+1)) { throw exception::eval_error("Incomplete " + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", File_Position(m_line, m_col), *m_filename); } - break; - case(AST_Node_Type::Addition) : - oper = m_match_stack.at(m_match_stack.size()-2); - m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, - m_match_stack.begin() + m_match_stack.size() - 1); - if (oper->text == "+") { - build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); - } - else if (oper->text == "-") { - build_match(AST_NodePtr(new eval::Subtraction_AST_Node()), prev_stack_top); - } - break; - case(AST_Node_Type::Multiplication) : - oper = m_match_stack.at(m_match_stack.size()-2); - m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, - m_match_stack.begin() + m_match_stack.size() - 1); - if (oper->text == "*") { - build_match(AST_NodePtr(new eval::Multiplication_AST_Node()), prev_stack_top); - } - else if (oper->text == "/") { - build_match(AST_NodePtr(new eval::Division_AST_Node()), prev_stack_top); - } - else if (oper->text == "%") { - build_match(AST_NodePtr(new eval::Modulus_AST_Node()), prev_stack_top); - } - break; - case(AST_Node_Type::Shift) : - build_match(AST_NodePtr(new eval::Shift_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Equality) : - build_match(AST_NodePtr(new eval::Equality_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_And) : - build_match(AST_NodePtr(new eval::Bitwise_And_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_Xor) : - build_match(AST_NodePtr(new eval::Bitwise_Xor_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_Or) : - build_match(AST_NodePtr(new eval::Bitwise_Or_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Logical_And) : - build_match(AST_NodePtr(new eval::Logical_And_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Logical_Or) : - build_match(AST_NodePtr(new eval::Logical_Or_AST_Node()), prev_stack_top); - break; - default: - throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); - } - } while (Operator_Helper(t_precedence)); - } + build_match(std::make_shared(), prev_stack_top); + } + else { + throw exception::eval_error("Incomplete " + + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", + File_Position(m_line, m_col), *m_filename); + } + break; + case(AST_Node_Type::Addition) : + oper = m_match_stack.at(m_match_stack.size()-2); + m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, + m_match_stack.begin() + m_match_stack.size() - 1); + if (oper->text == "+") { + build_match(std::make_shared(), prev_stack_top); + } + else if (oper->text == "-") { + build_match(std::make_shared(), prev_stack_top); + } + break; + case(AST_Node_Type::Multiplication) : + oper = m_match_stack.at(m_match_stack.size()-2); + m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, + m_match_stack.begin() + m_match_stack.size() - 1); + if (oper->text == "*") { + build_match(std::make_shared(), prev_stack_top); + } + else if (oper->text == "/") { + build_match(std::make_shared(), prev_stack_top); + } + else if (oper->text == "%") { + build_match(std::make_shared(), prev_stack_top); + } + break; + case(AST_Node_Type::Shift) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Equality) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_And) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_Xor) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_Or) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Logical_And) : + build_match(std::make_shared(), prev_stack_top); + break; + case(AST_Node_Type::Logical_Or) : + build_match(std::make_shared(), prev_stack_top); + break; + default: + throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); + } + } while (Operator_Helper(t_precedence)); } } - else { - return Value(); - } - - return retval; + } + else { + return Value(); } - /** - * Reads a pair of values used to create a map initialization from input - */ - bool Map_Pair() { - bool retval = false; + return retval; + } - size_t prev_stack_top = m_match_stack.size(); - std::string::const_iterator prev_pos = m_input_pos; - int prev_col = m_col; + /// Reads a pair of values used to create a map initialization from input + bool Map_Pair() { + bool retval = false; - if (Operator()) { - if (Symbol(":")) { - retval = true; - if (!Operator()) { - throw exception::eval_error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); - } + const auto prev_stack_top = m_match_stack.size(); + const auto prev_pos = m_input_pos; + const auto prev_col = m_col; - build_match(AST_NodePtr(new eval::Map_Pair_AST_Node()), prev_stack_top); - } - else { - m_input_pos = prev_pos; - m_col = prev_col; - while (prev_stack_top != m_match_stack.size()) { - m_match_stack.pop_back(); - } - } - } - - return retval; - } - - /** - * Reads a pair of values used to create a range initialization from input - */ - bool Value_Range() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - std::string::const_iterator prev_pos = m_input_pos; - int prev_col = m_col; - - if (Operator()) { - if (Symbol("..")) { - retval = true; - if (!Operator()) { - throw exception::eval_error("Incomplete value range", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Value_Range_AST_Node()), prev_stack_top); - } - else { - m_input_pos = prev_pos; - m_col = prev_col; - while (prev_stack_top != m_match_stack.size()) { - m_match_stack.pop_back(); - } - } - } - - return retval; - } - - /** - * Parses a string of binary equation operators - */ - bool Equation() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Operator()) { + if (Operator()) { + if (Symbol(":")) { retval = true; - if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) || - Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true) || - Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) || - Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { - SkipWS(true); - if (!Equation()) { - throw exception::eval_error("Incomplete equation", File_Position(m_line, m_col), *m_filename); - } + if (!Operator()) { + throw exception::eval_error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); + } - build_match(AST_NodePtr(new eval::Equation_AST_Node()), prev_stack_top); - } - } - - return retval; - } - - /** - * Parses statements allowed inside of a class block - */ - bool Class_Statements() { - bool retval = false; - - bool has_more = true; - bool saw_eol = true; - - while (has_more) { - int prev_line = m_line; - int prev_col = m_col; - if (Def(true)) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } else if (Var_Decl(true)) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } else if (Eol()) { - has_more = true; - retval = true; - saw_eol = true; - } else { - has_more = false; - } - } - - return retval; - } - - /** - * Top level parser, starts parsing of all known parses - */ - bool Statements() { - bool retval = false; - - bool has_more = true; - bool saw_eol = true; - - while (has_more) { - int prev_line = m_line; - int prev_col = m_col; - if (Def()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Try()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (If()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (While()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Class()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (For()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Switch()) { - if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Return()) { - if (!saw_eol) { - throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Break()) { - if (!saw_eol) { - throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Continue()) { - if (!saw_eol) { - throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Block()) { - has_more = true; - retval = true; - saw_eol = true; - } - else if (Equation()) { - if (!saw_eol) { - throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Eol()) { - has_more = true; - retval = true; - saw_eol = true; - } - else { - has_more = false; - } - } - - return retval; - } - - /** - * Parses the given input string, tagging parsed ast_nodes with the given m_filename. - */ - bool parse(const std::string &t_input, const std::string &t_fname) { - m_input_pos = t_input.begin(); - m_input_end = t_input.end(); - m_line = 1; - m_col = 1; - m_filename = std::shared_ptr(new std::string(t_fname)); - - if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { - while ((m_input_pos != m_input_end) && (!Eol())) { - ++m_input_pos; - } - /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) - } - - if (Statements()) { - if (m_input_pos != m_input_end) { - throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); - } - else { - build_match(AST_NodePtr(new eval::File_AST_Node()), 0); - return true; - } + build_match(std::make_shared(), prev_stack_top); } else { - return false; + m_input_pos = prev_pos; + m_col = prev_col; + while (prev_stack_top != m_match_stack.size()) { + m_match_stack.pop_back(); + } } } - }; + + return retval; + } + + /// Reads a pair of values used to create a range initialization from input + bool Value_Range() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + const auto prev_pos = m_input_pos; + const auto prev_col = m_col; + + if (Operator()) { + if (Symbol("..")) { + retval = true; + if (!Operator()) { + throw exception::eval_error("Incomplete value range", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + else { + m_input_pos = prev_pos; + m_col = prev_col; + while (prev_stack_top != m_match_stack.size()) { + m_match_stack.pop_back(); + } + } + } + + return retval; + } + + /// Parses a string of binary equation operators + bool Equation() { + bool retval = false; + + const auto prev_stack_top = m_match_stack.size(); + + if (Operator()) { + retval = true; + if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) || + Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true) || + Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) || + Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { + SkipWS(true); + if (!Equation()) { + throw exception::eval_error("Incomplete equation", File_Position(m_line, m_col), *m_filename); + } + + build_match(std::make_shared(), prev_stack_top); + } + } + + return retval; + } + + /// Parses statements allowed inside of a class block + bool Class_Statements() { + bool retval = false; + + bool has_more = true; + bool saw_eol = true; + + while (has_more) { + const auto prev_line = m_line; + const auto prev_col = m_col; + if (Def(true)) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } else if (Var_Decl(true)) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } else if (Eol()) { + has_more = true; + retval = true; + saw_eol = true; + } else { + has_more = false; + } + } + + return retval; + } + + /// Top level parser, starts parsing of all known parses + bool Statements() { + bool retval = false; + + bool has_more = true; + bool saw_eol = true; + + while (has_more) { + int prev_line = m_line; + int prev_col = m_col; + if (Def()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Try()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (If()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (While()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Class()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (For()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Switch()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Return()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Break()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Continue()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Block()) { + has_more = true; + retval = true; + saw_eol = true; + } + else if (Equation()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Eol()) { + has_more = true; + retval = true; + saw_eol = true; + } + else { + has_more = false; + } + } + + return retval; + } + + /// Parses the given input string, tagging parsed ast_nodes with the given m_filename. + bool parse(const std::string &t_input, std::string t_fname) { + m_input_pos = t_input.begin(); + m_input_end = t_input.end(); + m_line = 1; + m_col = 1; + m_filename = std::make_shared(std::move(t_fname)); + + if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { + while ((m_input_pos != m_input_end) && (!Eol())) { + ++m_input_pos; + } + /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) + } + + if (Statements()) { + if (m_input_pos != m_input_end) { + throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); + } else { + build_match(std::make_shared(), 0); + return true; + } + } else { + return false; + } + } + }; } } #endif /* CHAISCRIPT_PARSER_HPP_ */ + diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 3efb525..07fdff4 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -21,6 +21,29 @@ namespace chaiscript namespace utility { + /// Single step command for registering a class with ChaiScript + /// + /// \param[in,out] t_module Model to add class to + /// \param[in] t_class_name Name of the class being registered + /// \param[in] t_constructors Vector of constructors to add + /// \param[in] t_funcs Vector of methods to add + /// + /// \example Adding a basic class to ChaiScript in one step + /// + /// \code + /// chaiscript::utility::add_class(*m, + /// "test", + /// { constructor(), + /// constructor() }, + /// { {fun(&test::function), "function"}, + /// {fun(&test::function2), "function2"}, + /// {fun(&test::function3), "function3"}, + /// {fun(static_cast(&test::functionoverload)), "functionoverload" }, + /// {fun(static_cast(&test::functionoverload)), "functionoverload" }, + /// {fun(static_cast(&test::operator=)), "=" } + /// } + /// ); + /// template void add_class(ModuleType &t_module, const std::string &t_class_name, @@ -34,13 +57,11 @@ namespace chaiscript t_module.add(ctor, t_class_name); } - for(auto fun: t_funcs) + for(const auto &fun: t_funcs) { t_module.add(fun.first, fun.second); } - } - } }