Correctly report the line context when there is a valexpr parsing error.

This commit is contained in:
John Wiegley 2009-01-22 21:16:43 -04:00
parent d9e97cfede
commit 812d38c176
4 changed files with 75 additions and 37 deletions

View file

@ -63,15 +63,29 @@ inline string file_context(const path& file, std::size_t line) {
return buf.str();
}
inline string line_context(const string& line, istream_pos_type pos) {
inline string line_context(const string& line,
istream_pos_type pos = istream_pos_type(0),
istream_pos_type end_pos = istream_pos_type(0))
{
std::ostringstream buf;
buf << " " << line << " ";
istream_pos_type idx = (pos == istream_pos_type(0) ?
istream_pos_type(line.length()) : pos);
idx -= 1;
for (istream_pos_type i = 0; i < idx; i += 1)
buf << " ";
buf << "^" << std::endl;
buf << " " << line << "\n";
if (pos != istream_pos_type(0)) {
buf << " ";
if (end_pos == istream_pos_type(0)) {
for (istream_pos_type i = 0; i < pos; i += 1)
buf << " ";
buf << "^\n";
} else {
for (istream_pos_type i = 0; i < end_pos; i += 1) {
if (i >= pos)
buf << "^";
else
buf << " ";
}
buf << '\n';
}
}
return buf.str();
}

View file

@ -399,11 +399,21 @@ expr_t::parser_t::parse(std::istream& in, const flags_t flags,
return top_node;
}
catch (const std::exception& err) {
add_error_context("While parsing value expression:");
if (original_string) {
istream_pos_type pos = in.tellg();
pos -= 1;
add_error_context(line_context(*original_string, pos));
add_error_context("While parsing value expression:");
istream_pos_type end_pos = in.tellg();
istream_pos_type pos = end_pos;
pos -= lookahead.length;
DEBUG("parser.error", "original_string = '" << *original_string << "'");
DEBUG("parser.error", " pos = " << pos);
DEBUG("parser.error", " end_pos = " << end_pos);
DEBUG("parser.error", " token kind = " << int(lookahead.kind));
DEBUG("parser.error", " token length = " << lookahead.length);
add_error_context(line_context(*original_string, pos, end_pos));
}
throw;
}

View file

@ -347,24 +347,32 @@ void expr_t::token_t::next(std::istream& in, const uint_least8_t pflags)
if (pflags & EXPR_PARSE_NO_REDUCE)
parse_flags |= AMOUNT_PARSE_NO_REDUCE;
amount_t temp;
if (! temp.parse(in, parse_flags | AMOUNT_PARSE_SOFT_FAIL)) {
// If the amount had no commodity, it must be an unambiguous
// variable reference
try {
amount_t temp;
if (! temp.parse(in, parse_flags | AMOUNT_PARSE_SOFT_FAIL)) {
// If the amount had no commodity, it must be an unambiguous
// variable reference
in.clear();
in.seekg(pos, std::ios::beg);
if (in.fail())
throw_(parse_error, "Failed to reset input stream");
in.clear();
in.seekg(pos, std::ios::beg);
if (in.fail())
throw_(parse_error, "Failed to reset input stream");
c = in.peek();
if (std::isdigit(c) || c == '.')
expected('\0', c);
c = in.peek();
if (std::isdigit(c) || c == '.')
expected('\0', c);
parse_ident(in);
} else {
kind = VALUE;
value = temp;
parse_ident(in);
} else {
kind = VALUE;
value = temp;
length = in.tellg() - pos;
}
}
catch (const std::exception& err) {
kind = ERROR;
length = in.tellg() - pos;
throw;
}
break;
}
@ -381,7 +389,11 @@ void expr_t::token_t::rewind(std::istream& in)
void expr_t::token_t::unexpected()
{
switch (kind) {
kind_t prev_kind = kind;
kind = ERROR;
switch (prev_kind) {
case TOK_EOF:
throw_(parse_error, "Unexpected end of expression");
case IDENT:
@ -395,17 +407,19 @@ void expr_t::token_t::unexpected()
void expr_t::token_t::expected(char wanted, char c)
{
if (c == '\0') {
if (wanted)
throw_(parse_error, "Missing '" << wanted << "'");
else
kind = ERROR;
if (c == '\0' || c == -1) {
if (wanted == '\0' || wanted == -1)
throw_(parse_error, "Unexpected end");
else
throw_(parse_error, "Missing '" << wanted << "'");
} else {
if (wanted)
if (wanted == '\0' || wanted == -1)
throw_(parse_error, "Invalid char '" << c << "'");
else
throw_(parse_error, "Invalid char '" << c
<< "' (wanted '" << wanted << "')");
else
throw_(parse_error, "Invalid char '" << c << "'");
}
}

View file

@ -39,6 +39,7 @@ namespace ledger {
struct expr_t::token_t : public noncopyable
{
enum kind_t {
ERROR, // an error occurred while tokenizing
VALUE, // any kind of literal value
IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
MASK, // /regexp/
@ -109,8 +110,7 @@ struct expr_t::token_t : public noncopyable
void next(std::istream& in, const uint_least8_t flags);
void rewind(std::istream& in);
void unexpected();
static void expected(char wanted, char c = '\0');
void expected(char wanted, char c = '\0');
};
} // namespace ledger