Relevant code printing when error reporting

This commit is contained in:
Robert Bendun 2022-06-09 01:48:02 +02:00
parent d16f6de53c
commit b7d879bf70
5 changed files with 86 additions and 16 deletions

View File

@ -14,6 +14,7 @@ Obj= \
errors.o \ errors.o \
interpreter.o \ interpreter.o \
lexer.o \ lexer.o \
lines.o \
location.o \ location.o \
number.o \ number.o \
parser.o \ parser.o \

View File

@ -125,36 +125,47 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
error_heading(os, err.location, Error_Level::Error, short_description); error_heading(os, err.location, Error_Level::Error, short_description);
auto const loc = err.location;
visit(Overloaded { visit(Overloaded {
[&os](errors::Unrecognized_Character const& err) { [&](errors::Unrecognized_Character const& err) {
os << "I encountered character in the source code that was not supposed to be here.\n"; os << "I encountered character in the source code that was not supposed to be here.\n";
os << " Character Unicode code: U+" << std::hex << err.invalid_character << '\n'; os << " Character Unicode code: U+" << std::hex << err.invalid_character << '\n';
os << " Character printed: '" << utf8::Print{err.invalid_character} << "'\n"; os << " Character printed: '" << utf8::Print{err.invalid_character} << "'\n";
os << "\n"; os << "\n";
Lines::the.print(os, std::string(loc->filename), loc->line, loc->line);
os << "Musique only accepts characters that are unicode letters or ascii numbers and punctuation\n"; os << "Musique only accepts characters that are unicode letters or ascii numbers and punctuation\n";
}, },
[&os](errors::Failed_Numeric_Parsing const& err) { [&](errors::Failed_Numeric_Parsing const& err) {
constexpr auto Max = std::numeric_limits<decltype(Number::num)>::max(); constexpr auto Max = std::numeric_limits<decltype(Number::num)>::max();
constexpr auto Min = std::numeric_limits<decltype(Number::num)>::min(); constexpr auto Min = std::numeric_limits<decltype(Number::num)>::min();
os << "I tried to parse numeric literal, but I failed."; os << "I tried to parse numeric literal, but I failed.\n\n";
Lines::the.print(os, std::string(loc->filename), loc->line, loc->line);
if (err.reason == std::errc::result_out_of_range) { if (err.reason == std::errc::result_out_of_range) {
os << " Declared number is outside of valid range of numbers that can be represented.\n"; os << "\nDeclared number is outside of valid range of numbers that can be represented.\n";
os << " Only numbers in range [" << Min << ", " << Max << "] are supported\n"; os << "Only numbers in range [" << Min << ", " << Max << "] are supported\n";
} }
}, },
[&os](errors::internal::Unexpected_Token const& ut) { [&](errors::internal::Unexpected_Token const& ut) {
os << "I encountered unexpected token during " << ut.when << '\n'; os << "I encountered unexpected token during " << ut.when << '\n';
os << " Token type: " << ut.type << '\n'; os << " Token type: " << ut.type << '\n';
os << " Token source: " << ut.source << '\n'; os << " Token source: " << ut.source << "\n\n";
Lines::the.print(os, std::string(loc->filename), loc->line, loc->line);
os << pretty::begin_comment << "\nThis error is considered an internal one. It should not be displayed to the end user.\n" << pretty::end; os << pretty::begin_comment << "\nThis error is considered an internal one. It should not be displayed to the end user.\n" << pretty::end;
encourage_contact(os); encourage_contact(os);
}, },
[&os](errors::Expected_Expression_Separator_Before const& err) { [&](errors::Expected_Expression_Separator_Before const& err) {
os << "I failed to parse following code, due to missing semicolon before it!\n"; os << "I failed to parse following code, due to missing semicolon before it!\n\n";
Lines::the.print(os, std::string(loc->filename), loc->line, loc->line);
if (err.what == "var") { if (err.what == "var") {
os << "\nIf you want to create variable inside expression try wrapping them inside parentheses like this:\n"; os << "\nIf you want to create variable inside expression try wrapping them inside parentheses like this:\n";
@ -162,9 +173,10 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
} }
}, },
[&os](errors::Literal_As_Identifier const& err) { [&](errors::Literal_As_Identifier const& err) {
os << "I expected an identifier in " << err.context << ", but found" << (err.type_name.empty() ? "" : " ") << err.type_name << " value = '" << err.source << "'\n"; os << "I expected an identifier in " << err.context << ", but found" << (err.type_name.empty() ? "" : " ") << err.type_name << " value = '" << err.source << "'\n\n";
Lines::the.print(os, std::string(loc->filename), loc->line, loc->line);
if (err.type_name == "chord") { if (err.type_name == "chord") {
os << "\nTry renaming to different name or appending with something that is not part of chord literal like 'x'\n"; os << "\nTry renaming to different name or appending with something that is not part of chord literal like 'x'\n";
@ -176,10 +188,10 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
} }
}, },
[&os](errors::Not_Callable const&) { unimplemented(); }, [&](errors::Not_Callable const&) { unimplemented(); },
[&os](errors::Undefined_Operator const&) { unimplemented(); }, [&](errors::Undefined_Operator const&) { unimplemented(); },
[&os](errors::Unexpected_Keyword const&) { unimplemented(); }, [&](errors::Unexpected_Keyword const&) { unimplemented(); },
[&os](errors::Unexpected_Empty_Source const&) { unimplemented(); } [&](errors::Unexpected_Empty_Source const&) { unimplemented(); }
}, err.details); }, err.details);
return os; return os;

36
src/lines.cc Normal file
View File

@ -0,0 +1,36 @@
#include <musique.hh>
#include <iomanip>
Lines Lines::the;
void Lines::add_file(std::string filename, std::string_view source)
{
auto file = lines.insert({ filename, {} });
auto &lines_in_file = file.first->second;
while (not source.empty()) {
auto end = source.find('\n');
if (end == std::string_view::npos) {
lines_in_file.push_back({ source.data(), end });
break;
} else {
lines_in_file.push_back({ source.data(), end });
source.remove_prefix(end+1);
}
}
}
void Lines::add_line(std::string const& filename, std::string_view source)
{
lines[filename].push_back(source);
}
void Lines::print(std::ostream &os, std::string const& filename, unsigned first_line, unsigned last_line) const
{
auto const& file = lines.at(filename);
for (auto i = first_line; i <= last_line; ++i) {
os << std::setw(3) << std::right << i << " | " << file[i-1] << '\n';
}
os << std::flush;
}

View File

@ -166,11 +166,13 @@ static Result<void> Main(std::span<char const*> args)
for (auto const& [is_file, argument] : runnables) { for (auto const& [is_file, argument] : runnables) {
if (!is_file) { if (!is_file) {
Lines::the.add_line("<arguments>", argument);
Try(runner.run(argument, "<arguments>")); Try(runner.run(argument, "<arguments>"));
continue; continue;
} }
auto const path = argument; auto path = argument;
if (path == "-") { if (path == "-") {
path = "<stdin>";
eternal_sources.emplace_back(std::istreambuf_iterator<char>(std::cin), std::istreambuf_iterator<char>()); eternal_sources.emplace_back(std::istreambuf_iterator<char>(std::cin), std::istreambuf_iterator<char>());
} else { } else {
if (not fs::exists(path)) { if (not fs::exists(path)) {
@ -181,6 +183,7 @@ static Result<void> Main(std::span<char const*> args)
eternal_sources.emplace_back(std::istreambuf_iterator<char>(source_file), std::istreambuf_iterator<char>()); eternal_sources.emplace_back(std::istreambuf_iterator<char>(source_file), std::istreambuf_iterator<char>());
} }
Lines::the.add_file(std::string(path), eternal_sources.back());
Try(runner.run(eternal_sources.back(), path)); Try(runner.run(eternal_sources.back(), path));
} }
@ -216,6 +219,7 @@ static Result<void> Main(std::span<char const*> args)
continue; continue;
} }
Lines::the.add_line("<repl>", raw);
auto result = runner.run(raw, "<repl>", true); auto result = runner.run(raw, "<repl>", true);
if (not result.has_value()) { if (not result.has_value()) {
std::cout << std::flush; std::cout << std::flush;

View File

@ -392,6 +392,23 @@ std::ostream& operator<<(std::ostream& os, Token const& tok);
/// Token type debug printing /// Token type debug printing
std::ostream& operator<<(std::ostream& os, Token::Type type); std::ostream& operator<<(std::ostream& os, Token::Type type);
struct Lines
{
static Lines the;
/// Region of lines in files
std::unordered_map<std::string, std::vector<std::string_view>> lines;
/// Add lines from file
void add_file(std::string filename, std::string_view source);
/// Add single line into file (REPL usage)
void add_line(std::string const& filename, std::string_view source);
/// Print selected region
void print(std::ostream& os, std::string const& file, unsigned first_line, unsigned last_line) const;
};
/// Explicit marker of the end of file /// Explicit marker of the end of file
struct End_Of_File {}; struct End_Of_File {};