diff options
-rw-r--r-- | src/error.h | 30 | ||||
-rw-r--r-- | src/parser.cc | 18 | ||||
-rw-r--r-- | src/token.cc | 66 | ||||
-rw-r--r-- | src/token.h | 4 |
4 files changed, 78 insertions, 40 deletions
diff --git a/src/error.h b/src/error.h index 1ef6ff3c..6730ce17 100644 --- a/src/error.h +++ b/src/error.h @@ -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(); } diff --git a/src/parser.cc b/src/parser.cc index 82bc771d..4881f7bc 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -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; } diff --git a/src/token.cc b/src/token.cc index 51eb4623..6c28e7d6 100644 --- a/src/token.cc +++ b/src/token.cc @@ -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 - - 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); - - parse_ident(in); - } else { - kind = VALUE; - value = temp; + 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"); + + c = in.peek(); + if (std::isdigit(c) || c == '.') + expected('\0', c); + + 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 << "'"); } } diff --git a/src/token.h b/src/token.h index 5502ad94..904a2e52 100644 --- a/src/token.h +++ b/src/token.h @@ -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 |