diff options
author | John Wiegley <johnw@newartisans.com> | 2011-11-10 00:48:19 -0600 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2011-11-10 00:48:19 -0600 |
commit | 37e9ec8030a2634cbe9b2727f4d5530a582292c7 (patch) | |
tree | 7fb3a1ece2c97c6b034a56b7e47b5754c0150e9b | |
parent | d493f79651d124481aa49bd0eeea1fdea11e477b (diff) | |
download | fork-ledger-37e9ec8030a2634cbe9b2727f4d5530a582292c7.tar.gz fork-ledger-37e9ec8030a2634cbe9b2727f4d5530a582292c7.tar.bz2 fork-ledger-37e9ec8030a2634cbe9b2727f4d5530a582292c7.zip |
Report an error in the case of '(1' (missing rparen)
Fixes #557
-rw-r--r-- | src/expr.h | 6 | ||||
-rw-r--r-- | src/parser.cc | 4 | ||||
-rw-r--r-- | src/parser.h | 8 | ||||
-rw-r--r-- | src/report.h | 2 | ||||
-rw-r--r-- | src/token.cc | 104 | ||||
-rw-r--r-- | src/token.h | 9 |
6 files changed, 115 insertions, 18 deletions
@@ -49,15 +49,15 @@ namespace ledger { class expr_t : public expr_base_t<value_t> { - struct token_t; - class parser_t; - + class parser_t; typedef expr_base_t<value_t> base_type; public: + struct token_t; class op_t; typedef intrusive_ptr<op_t> ptr_op_t; typedef intrusive_ptr<const op_t> const_ptr_op_t; + protected: ptr_op_t ptr; diff --git a/src/parser.cc b/src/parser.cc index f0085295..a18fa552 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -74,7 +74,7 @@ expr_t::parser_t::parse_value_term(std::istream& in, case token_t::LPAREN: node = parse_value_expr(in, tflags.plus_flags(PARSE_PARTIAL) .minus_flags(PARSE_SINGLE)); - tok = next_token(in, tflags, ')'); + tok = next_token(in, tflags, token_t::RPAREN); break; default: @@ -367,7 +367,7 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in, throw_(parse_error, _("%1 operator not followed by argument") << tok.symbol); - next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT), ':'); + next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT), token_t::COLON); prev = node->right(); ptr_op_t subnode = new op_t(op_t::O_COLON); subnode->set_left(prev); diff --git a/src/parser.h b/src/parser.h index 9a65765d..09e12d95 100644 --- a/src/parser.h +++ b/src/parser.h @@ -53,11 +53,15 @@ class expr_t::parser_t : public noncopyable mutable bool use_lookahead; token_t& next_token(std::istream& in, const parse_flags_t& tflags, - const char expecting = '\0') const { + const optional<token_t::kind_t>& expecting = none) const { if (use_lookahead) use_lookahead = false; else - lookahead.next(in, tflags, expecting); + lookahead.next(in, tflags); + + if (expecting && lookahead.kind != *expecting) + lookahead.expected(*expecting); + return lookahead; } diff --git a/src/report.h b/src/report.h index 58c12f24..5b403205 100644 --- a/src/report.h +++ b/src/report.h @@ -770,7 +770,7 @@ public: parent->HANDLER(total_) .set_expr(string("--percent"), "((is_account&parent&parent.total)?" - " percent(scrub(total), scrub(parent.total)):0"); + " percent(scrub(total), scrub(parent.total)):0)"); }); OPTION__ diff --git a/src/token.cc b/src/token.cc index 735f5825..fc7f73ee 100644 --- a/src/token.cc +++ b/src/token.cc @@ -137,8 +137,7 @@ void expr_t::token_t::parse_ident(std::istream& in) value.set_string(buf); } -void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags, - const char expecting) +void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags) { if (in.eof()) { kind = TOK_EOF; @@ -436,7 +435,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags, kind = ERROR; symbol[0] = c; symbol[1] = '\0'; - unexpected(expecting); + throw_(parse_error, _("Failed to parse identifier")); } } else { if (! in.good()) { @@ -505,10 +504,8 @@ void expr_t::token_t::unexpected(const char wanted) } } -void expr_t::token_t::expected(char wanted, char c) +void expr_t::token_t::expected(const char wanted, char c) { - kind = ERROR; - if (c == '\0' || c == -1) { if (wanted == '\0' || wanted == -1) throw_(parse_error, _("Unexpected end")); @@ -518,8 +515,101 @@ void expr_t::token_t::expected(char wanted, char c) if (wanted == '\0' || wanted == -1) throw_(parse_error, _("Invalid char '%1'") << c); else - throw_(parse_error, _("Invalid char '%1' (wanted '%2')") << c << wanted); + throw_(parse_error, + _("Invalid char '%1' (wanted '%2')") << c << wanted); + } +} + +void expr_t::token_t::expected(const kind_t wanted) +{ + try { + if (wanted == '\0' || wanted == -1) + throw_(parse_error, _("Invalid token '%1'") << *this); + else + throw_(parse_error, + _("Invalid token '%1' (wanted '%2')") << *this << wanted); + } + catch (...) { + kind = ERROR; + throw; } } +std::ostream& operator<<(std::ostream& out, const expr_t::token_t::kind_t& kind) +{ + switch (kind) { + case expr_t::token_t::ERROR: out << "<error token>"; break; + case expr_t::token_t::VALUE: out << "<value>"; break; + case expr_t::token_t::IDENT: out << "<identifier>"; break; + case expr_t::token_t::MASK: out << "<regex mask>"; break; + + case expr_t::token_t::LPAREN: out << "("; break; + case expr_t::token_t::RPAREN: out << ")"; break; + case expr_t::token_t::LBRACE: out << "{"; break; + case expr_t::token_t::RBRACE: out << "}"; break; + + case expr_t::token_t::EQUAL: out << "=="; break; + case expr_t::token_t::NEQUAL: out << "!="; break; + case expr_t::token_t::LESS: out << "<"; break; + case expr_t::token_t::LESSEQ: out << "<="; break; + case expr_t::token_t::GREATER: out << ">"; break; + case expr_t::token_t::GREATEREQ: out << ">="; break; + + case expr_t::token_t::ASSIGN: out << "="; break; + case expr_t::token_t::MATCH: out << "=~"; break; + case expr_t::token_t::NMATCH: out << "!~"; break; + case expr_t::token_t::MINUS: out << "-"; break; + case expr_t::token_t::PLUS: out << "+"; break; + case expr_t::token_t::STAR: out << "*"; break; + case expr_t::token_t::SLASH: out << "/"; break; + case expr_t::token_t::ARROW: out << "->"; break; + case expr_t::token_t::KW_DIV: out << "div"; break; + + case expr_t::token_t::EXCLAM: out << "!"; break; + case expr_t::token_t::KW_AND: out << "and"; break; + case expr_t::token_t::KW_OR: out << "or"; break; + case expr_t::token_t::KW_MOD: out << "mod"; break; + + case expr_t::token_t::KW_IF: out << "if"; break; + case expr_t::token_t::KW_ELSE: out << "else"; break; + + case expr_t::token_t::QUERY: out << "?"; break; + case expr_t::token_t::COLON: out << ":"; break; + + case expr_t::token_t::DOT: out << "."; break; + case expr_t::token_t::COMMA: out << ","; break; + case expr_t::token_t::SEMI: out << ";"; break; + + case expr_t::token_t::TOK_EOF: out << "<end of input>"; break; + case expr_t::token_t::UNKNOWN: out << "<unknown>"; break; + + default: + assert(false); + break; + } + + return out; +} + +std::ostream& operator<<(std::ostream& out, const expr_t::token_t& token) +{ + switch (token.kind) { + case expr_t::token_t::VALUE: + out << "<value '" << token.value << "'>"; + break; + case expr_t::token_t::IDENT: + out << "<ident '" << token.value << "'>"; + break; + case expr_t::token_t::MASK: + out << "<mask '" << token.value << "'>"; + break; + + default: + out << token.kind; + break; + } + + return out; +} + } // namespace ledger diff --git a/src/token.h b/src/token.h index 13a799cb..cbdf1258 100644 --- a/src/token.h +++ b/src/token.h @@ -123,13 +123,16 @@ struct expr_t::token_t : public noncopyable int parse_reserved_word(std::istream& in); void parse_ident(std::istream& in); - void next(std::istream& in, const parse_flags_t& flags, - const char expecting = '\0'); + void next(std::istream& in, const parse_flags_t& flags); void rewind(std::istream& in); void unexpected(const char wanted = '\0'); - void expected(const char wanted, char c = '\0'); + void expected(const char wanted, const char c = '\0'); + void expected(const kind_t wanted); }; +std::ostream& operator<<(std::ostream& out, const expr_t::token_t::kind_t& kind); +std::ostream& operator<<(std::ostream& out, const expr_t::token_t& token); + } // namespace ledger #endif // _TOKEN_H |