Improved error reporting in the expression parser
Fixes 15A80F68-F233-49D9-AF0C-9908BB6903BA
This commit is contained in:
parent
3e1ec40551
commit
a3482606dc
4 changed files with 45 additions and 23 deletions
|
|
@ -79,9 +79,7 @@ expr_t::parser_t::parse_value_term(std::istream& in,
|
||||||
case token_t::LPAREN:
|
case token_t::LPAREN:
|
||||||
node = parse_value_expr(in, tflags.plus_flags(PARSE_PARTIAL)
|
node = parse_value_expr(in, tflags.plus_flags(PARSE_PARTIAL)
|
||||||
.minus_flags(PARSE_SINGLE));
|
.minus_flags(PARSE_SINGLE));
|
||||||
tok = next_token(in, tflags);
|
tok = next_token(in, tflags, ')');
|
||||||
if (tok.kind != token_t::RPAREN)
|
|
||||||
tok.expected(')');
|
|
||||||
|
|
||||||
if (node->kind == op_t::O_CONS) {
|
if (node->kind == op_t::O_CONS) {
|
||||||
ptr_op_t prev(node);
|
ptr_op_t prev(node);
|
||||||
|
|
@ -383,10 +381,7 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
|
||||||
throw_(parse_error,
|
throw_(parse_error,
|
||||||
_("%1 operator not followed by argument") << tok.symbol);
|
_("%1 operator not followed by argument") << tok.symbol);
|
||||||
|
|
||||||
token_t& next_tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
|
next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT), ':');
|
||||||
if (next_tok.kind != token_t::COLON)
|
|
||||||
next_tok.expected(':');
|
|
||||||
|
|
||||||
prev = node->right();
|
prev = node->right();
|
||||||
ptr_op_t subnode = new op_t(op_t::O_COLON);
|
ptr_op_t subnode = new op_t(op_t::O_COLON);
|
||||||
subnode->set_left(prev);
|
subnode->set_left(prev);
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,12 @@ class expr_t::parser_t : public noncopyable
|
||||||
mutable token_t lookahead;
|
mutable token_t lookahead;
|
||||||
mutable bool use_lookahead;
|
mutable bool use_lookahead;
|
||||||
|
|
||||||
token_t& next_token(std::istream& in, const parse_flags_t& tflags) const {
|
token_t& next_token(std::istream& in, const parse_flags_t& tflags,
|
||||||
|
const char expecting = '\0') const {
|
||||||
if (use_lookahead)
|
if (use_lookahead)
|
||||||
use_lookahead = false;
|
use_lookahead = false;
|
||||||
else
|
else
|
||||||
lookahead.next(in, tflags);
|
lookahead.next(in, tflags, expecting);
|
||||||
return lookahead;
|
return lookahead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
47
src/token.cc
47
src/token.cc
|
|
@ -138,7 +138,8 @@ void expr_t::token_t::parse_ident(std::istream& in)
|
||||||
value.set_string(buf);
|
value.set_string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags)
|
void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
|
||||||
|
const char expecting)
|
||||||
{
|
{
|
||||||
if (in.eof()) {
|
if (in.eof()) {
|
||||||
kind = TOK_EOF;
|
kind = TOK_EOF;
|
||||||
|
|
@ -423,6 +424,13 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags)
|
||||||
expected('\0', c);
|
expected('\0', c);
|
||||||
|
|
||||||
parse_ident(in);
|
parse_ident(in);
|
||||||
|
|
||||||
|
if (value.as_string().length() == 0) {
|
||||||
|
kind = ERROR;
|
||||||
|
symbol[0] = c;
|
||||||
|
symbol[1] = '\0';
|
||||||
|
unexpected(expecting);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
kind = VALUE;
|
kind = VALUE;
|
||||||
value = temp;
|
value = temp;
|
||||||
|
|
@ -447,21 +455,38 @@ void expr_t::token_t::rewind(std::istream& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void expr_t::token_t::unexpected()
|
void expr_t::token_t::unexpected(const char wanted)
|
||||||
{
|
{
|
||||||
kind_t prev_kind = kind;
|
kind_t prev_kind = kind;
|
||||||
|
|
||||||
kind = ERROR;
|
kind = ERROR;
|
||||||
|
|
||||||
switch (prev_kind) {
|
if (wanted == '\0') {
|
||||||
case TOK_EOF:
|
switch (prev_kind) {
|
||||||
throw_(parse_error, _("Unexpected end of expression"));
|
case TOK_EOF:
|
||||||
case IDENT:
|
throw_(parse_error, _("Unexpected end of expression"));
|
||||||
throw_(parse_error, _("Unexpected symbol '%1'") << value);
|
case IDENT:
|
||||||
case VALUE:
|
throw_(parse_error, _("Unexpected symbol '%1'") << value);
|
||||||
throw_(parse_error, _("Unexpected value '%1'") << value);
|
case VALUE:
|
||||||
default:
|
throw_(parse_error, _("Unexpected value '%1'") << value);
|
||||||
throw_(parse_error, _("Unexpected token '%1'") << symbol);
|
default:
|
||||||
|
throw_(parse_error, _("Unexpected expression token '%1'") << symbol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (prev_kind) {
|
||||||
|
case TOK_EOF:
|
||||||
|
throw_(parse_error,
|
||||||
|
_("Unexpected end of expression (wanted '%1')" << wanted));
|
||||||
|
case IDENT:
|
||||||
|
throw_(parse_error,
|
||||||
|
_("Unexpected symbol '%1' (wanted '%2')") << value << wanted);
|
||||||
|
case VALUE:
|
||||||
|
throw_(parse_error,
|
||||||
|
_("Unexpected value '%1' (wanted '%2')") << value << wanted);
|
||||||
|
default:
|
||||||
|
throw_(parse_error, _("Unexpected expression token '%1' (wanted '%2')")
|
||||||
|
<< symbol << wanted);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,10 +124,11 @@ struct expr_t::token_t : public noncopyable
|
||||||
|
|
||||||
int parse_reserved_word(std::istream& in);
|
int parse_reserved_word(std::istream& in);
|
||||||
void parse_ident(std::istream& in);
|
void parse_ident(std::istream& in);
|
||||||
void next(std::istream& in, const parse_flags_t& flags);
|
void next(std::istream& in, const parse_flags_t& flags,
|
||||||
|
const char expecting = '\0');
|
||||||
void rewind(std::istream& in);
|
void rewind(std::istream& in);
|
||||||
void unexpected();
|
void unexpected(const char wanted = '\0');
|
||||||
void expected(char wanted, char c = '\0');
|
void expected(const char wanted, char c = '\0');
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue