summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2011-11-10 00:48:19 -0600
committerJohn Wiegley <johnw@newartisans.com>2011-11-10 00:48:19 -0600
commit37e9ec8030a2634cbe9b2727f4d5530a582292c7 (patch)
tree7fb3a1ece2c97c6b034a56b7e47b5754c0150e9b
parentd493f79651d124481aa49bd0eeea1fdea11e477b (diff)
downloadfork-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.h6
-rw-r--r--src/parser.cc4
-rw-r--r--src/parser.h8
-rw-r--r--src/report.h2
-rw-r--r--src/token.cc104
-rw-r--r--src/token.h9
6 files changed, 115 insertions, 18 deletions
diff --git a/src/expr.h b/src/expr.h
index a3ae5669..c4cd5dc5 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -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