Relevant code printing when error reporting
This commit is contained in:
parent
d16f6de53c
commit
b7d879bf70
1
Makefile
1
Makefile
@ -14,6 +14,7 @@ Obj= \
|
||||
errors.o \
|
||||
interpreter.o \
|
||||
lexer.o \
|
||||
lines.o \
|
||||
location.o \
|
||||
number.o \
|
||||
parser.o \
|
||||
|
@ -125,36 +125,47 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
||||
|
||||
error_heading(os, err.location, Error_Level::Error, short_description);
|
||||
|
||||
auto const loc = err.location;
|
||||
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 << " Character Unicode code: U+" << std::hex << err.invalid_character << '\n';
|
||||
os << " Character printed: '" << utf8::Print{err.invalid_character} << "'\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](errors::Failed_Numeric_Parsing const& err) {
|
||||
[&](errors::Failed_Numeric_Parsing const& err) {
|
||||
constexpr auto Max = std::numeric_limits<decltype(Number::num)>::max();
|
||||
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) {
|
||||
os << " Declared number is outside of valid range of numbers that can be represented.\n";
|
||||
os << " Only numbers in range [" << Min << ", " << Max << "] are supported\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](errors::internal::Unexpected_Token const& ut) {
|
||||
[&](errors::internal::Unexpected_Token const& ut) {
|
||||
os << "I encountered unexpected token during " << ut.when << '\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;
|
||||
encourage_contact(os);
|
||||
},
|
||||
|
||||
[&os](errors::Expected_Expression_Separator_Before const& err) {
|
||||
os << "I failed to parse following code, due to missing semicolon before it!\n";
|
||||
[&](errors::Expected_Expression_Separator_Before const& err) {
|
||||
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") {
|
||||
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) {
|
||||
os << "I expected an identifier in " << err.context << ", but found" << (err.type_name.empty() ? "" : " ") << err.type_name << " value = '" << err.source << "'\n";
|
||||
[&](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\n";
|
||||
|
||||
Lines::the.print(os, std::string(loc->filename), loc->line, loc->line);
|
||||
|
||||
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";
|
||||
@ -176,10 +188,10 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
||||
}
|
||||
},
|
||||
|
||||
[&os](errors::Not_Callable const&) { unimplemented(); },
|
||||
[&os](errors::Undefined_Operator const&) { unimplemented(); },
|
||||
[&os](errors::Unexpected_Keyword const&) { unimplemented(); },
|
||||
[&os](errors::Unexpected_Empty_Source const&) { unimplemented(); }
|
||||
[&](errors::Not_Callable const&) { unimplemented(); },
|
||||
[&](errors::Undefined_Operator const&) { unimplemented(); },
|
||||
[&](errors::Unexpected_Keyword const&) { unimplemented(); },
|
||||
[&](errors::Unexpected_Empty_Source const&) { unimplemented(); }
|
||||
}, err.details);
|
||||
|
||||
return os;
|
||||
|
36
src/lines.cc
Normal file
36
src/lines.cc
Normal 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;
|
||||
}
|
@ -166,11 +166,13 @@ static Result<void> Main(std::span<char const*> args)
|
||||
|
||||
for (auto const& [is_file, argument] : runnables) {
|
||||
if (!is_file) {
|
||||
Lines::the.add_line("<arguments>", argument);
|
||||
Try(runner.run(argument, "<arguments>"));
|
||||
continue;
|
||||
}
|
||||
auto const path = argument;
|
||||
auto path = argument;
|
||||
if (path == "-") {
|
||||
path = "<stdin>";
|
||||
eternal_sources.emplace_back(std::istreambuf_iterator<char>(std::cin), std::istreambuf_iterator<char>());
|
||||
} else {
|
||||
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>());
|
||||
}
|
||||
|
||||
Lines::the.add_file(std::string(path), eternal_sources.back());
|
||||
Try(runner.run(eternal_sources.back(), path));
|
||||
}
|
||||
|
||||
@ -216,6 +219,7 @@ static Result<void> Main(std::span<char const*> args)
|
||||
continue;
|
||||
}
|
||||
|
||||
Lines::the.add_line("<repl>", raw);
|
||||
auto result = runner.run(raw, "<repl>", true);
|
||||
if (not result.has_value()) {
|
||||
std::cout << std::flush;
|
||||
|
@ -392,6 +392,23 @@ std::ostream& operator<<(std::ostream& os, Token const& tok);
|
||||
/// Token type debug printing
|
||||
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
|
||||
struct End_Of_File {};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user