Unexpected empty source error improved
This commit is contained in:
parent
183907a0ed
commit
cb5eedb2a5
@ -41,6 +41,47 @@ using i64 = std::int64_t;
|
|||||||
using usize = std::size_t;
|
using usize = std::size_t;
|
||||||
using isize = std::ptrdiff_t;
|
using isize = std::ptrdiff_t;
|
||||||
|
|
||||||
|
/// \brief Location describes code position in `file line column` format.
|
||||||
|
/// It's used both to represent position in source files provided
|
||||||
|
// to interpreter and internal interpreter usage.
|
||||||
|
struct Location
|
||||||
|
{
|
||||||
|
std::string_view filename = "<unnamed>"; ///< File that location is pointing to
|
||||||
|
usize line = 1; ///< Line number (1 based) that location is pointing to
|
||||||
|
usize column = 1; ///< Column number (1 based) that location is pointing to
|
||||||
|
|
||||||
|
/// Advances line and column numbers based on provided rune
|
||||||
|
///
|
||||||
|
/// If rune is newline, then column is reset to 1, and line number is incremented.
|
||||||
|
/// Otherwise column number is incremented.
|
||||||
|
///
|
||||||
|
/// @param rune Rune from which column and line numbers advancements are made.
|
||||||
|
Location& advance(u32 rune);
|
||||||
|
|
||||||
|
bool operator==(Location const& rhs) const = default;
|
||||||
|
|
||||||
|
//! Creates location at default filename with specified line and column number
|
||||||
|
static Location at(usize line, usize column);
|
||||||
|
|
||||||
|
// Used to describe location of function call in interpreter (internal use only)
|
||||||
|
#if defined(__cpp_lib_source_location)
|
||||||
|
static Location caller(std::source_location loc = std::source_location::current());
|
||||||
|
#elif (__has_builtin(__builtin_FILE) and __has_builtin(__builtin_LINE))
|
||||||
|
static Location caller(char const* file = __builtin_FILE(), usize line = __builtin_LINE());
|
||||||
|
#else
|
||||||
|
#error Cannot implement Location::caller function
|
||||||
|
/// Returns location of call in interpreter source code.
|
||||||
|
///
|
||||||
|
/// Example of reporting where `foo()` was beeing called:
|
||||||
|
/// @code
|
||||||
|
/// void foo(Location loc = Location::caller()) { std::cout << loc << '\n'; }
|
||||||
|
/// @endcode
|
||||||
|
static Location caller();
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, Location const& location);
|
||||||
|
|
||||||
/// Error handling related functions and definitions
|
/// Error handling related functions and definitions
|
||||||
namespace errors
|
namespace errors
|
||||||
{
|
{
|
||||||
@ -53,6 +94,8 @@ namespace errors
|
|||||||
/// When parser was expecting code but encountered end of file
|
/// When parser was expecting code but encountered end of file
|
||||||
struct Unexpected_Empty_Source
|
struct Unexpected_Empty_Source
|
||||||
{
|
{
|
||||||
|
enum { Block_Without_Closing_Bracket } reason;
|
||||||
|
std::optional<Location> start;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// When user passed numeric literal too big for numeric type
|
/// When user passed numeric literal too big for numeric type
|
||||||
@ -183,47 +226,6 @@ namespace pretty
|
|||||||
template<typename ...Lambdas>
|
template<typename ...Lambdas>
|
||||||
struct Overloaded : Lambdas... { using Lambdas::operator()...; };
|
struct Overloaded : Lambdas... { using Lambdas::operator()...; };
|
||||||
|
|
||||||
/// \brief Location describes code position in `file line column` format.
|
|
||||||
/// It's used both to represent position in source files provided
|
|
||||||
// to interpreter and internal interpreter usage.
|
|
||||||
struct Location
|
|
||||||
{
|
|
||||||
std::string_view filename = "<unnamed>"; ///< File that location is pointing to
|
|
||||||
usize line = 1; ///< Line number (1 based) that location is pointing to
|
|
||||||
usize column = 1; ///< Column number (1 based) that location is pointing to
|
|
||||||
|
|
||||||
/// Advances line and column numbers based on provided rune
|
|
||||||
///
|
|
||||||
/// If rune is newline, then column is reset to 1, and line number is incremented.
|
|
||||||
/// Otherwise column number is incremented.
|
|
||||||
///
|
|
||||||
/// @param rune Rune from which column and line numbers advancements are made.
|
|
||||||
Location& advance(u32 rune);
|
|
||||||
|
|
||||||
bool operator==(Location const& rhs) const = default;
|
|
||||||
|
|
||||||
//! Creates location at default filename with specified line and column number
|
|
||||||
static Location at(usize line, usize column);
|
|
||||||
|
|
||||||
// Used to describe location of function call in interpreter (internal use only)
|
|
||||||
#if defined(__cpp_lib_source_location)
|
|
||||||
static Location caller(std::source_location loc = std::source_location::current());
|
|
||||||
#elif (__has_builtin(__builtin_FILE) and __has_builtin(__builtin_LINE))
|
|
||||||
static Location caller(char const* file = __builtin_FILE(), usize line = __builtin_LINE());
|
|
||||||
#else
|
|
||||||
#error Cannot implement Location::caller function
|
|
||||||
/// Returns location of call in interpreter source code.
|
|
||||||
///
|
|
||||||
/// Example of reporting where `foo()` was beeing called:
|
|
||||||
/// @code
|
|
||||||
/// void foo(Location loc = Location::caller()) { std::cout << loc << '\n'; }
|
|
||||||
/// @endcode
|
|
||||||
static Location caller();
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, Location const& location);
|
|
||||||
|
|
||||||
/// Guards that program exits if condition does not hold
|
/// Guards that program exits if condition does not hold
|
||||||
void assert(bool condition, std::string message, Location loc = Location::caller());
|
void assert(bool condition, std::string message, Location loc = Location::caller());
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ 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;
|
auto const loc = err.location;
|
||||||
auto const print_error_line = [&] {
|
auto const print_error_line = [&] (std::optional<Location> loc) {
|
||||||
if (loc) {
|
if (loc) {
|
||||||
Lines::the.print(os, std::string(loc->filename), loc->line, loc->line);
|
Lines::the.print(os, std::string(loc->filename), loc->line, loc->line);
|
||||||
os << '\n';
|
os << '\n';
|
||||||
@ -167,7 +167,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
os << "I cannot '" << err.name << "' due to lack of MIDI " << (err.is_input ? "input" : "output") << "connection\n";
|
os << "I cannot '" << err.name << "' due to lack of MIDI " << (err.is_input ? "input" : "output") << "connection\n";
|
||||||
os << "\n";
|
os << "\n";
|
||||||
|
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
os << "You can connect to given MIDI device by specifing port when running musique command like:\n";
|
os << "You can connect to given MIDI device by specifing port when running musique command like:\n";
|
||||||
os << (err.is_input ? " --input" : " --output") << " PORT\n";
|
os << (err.is_input ? " --input" : " --output") << " PORT\n";
|
||||||
@ -178,7 +178,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
os << "I can't find it in surrounding scope or in one of parent's scopes\n";
|
os << "I can't find it in surrounding scope or in one of parent's scopes\n";
|
||||||
os << "\n";
|
os << "\n";
|
||||||
|
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
os << "Variables can only be references in scope (block) where they been created\n";
|
os << "Variables can only be references in scope (block) where they been created\n";
|
||||||
os << "or from parent blocks to variable block\n";
|
os << "or from parent blocks to variable block\n";
|
||||||
@ -189,7 +189,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
os << " Character printed: '" << utf8::Print{err.invalid_character} << "'\n";
|
os << " Character printed: '" << utf8::Print{err.invalid_character} << "'\n";
|
||||||
os << "\n";
|
os << "\n";
|
||||||
|
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
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";
|
||||||
},
|
},
|
||||||
@ -199,7 +199,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
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.\n\n";
|
os << "I tried to parse numeric literal, but I failed.\n\n";
|
||||||
|
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
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 << "Declared number is outside of valid range of numbers that can be represented.\n";
|
||||||
@ -212,7 +212,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
os << " Token type: " << ut.type << '\n';
|
os << " Token type: " << ut.type << '\n';
|
||||||
os << " Token source: " << ut.source << "\n\n";
|
os << " Token source: " << ut.source << "\n\n";
|
||||||
|
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
os << pretty::begin_comment << "This error is considered an internal one. It should not be displayed to the end user.\n";
|
os << pretty::begin_comment << "This error is considered an internal one. It should not be displayed to the end user.\n";
|
||||||
os << "\n";
|
os << "\n";
|
||||||
@ -223,7 +223,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
[&](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\n";
|
os << "I failed to parse following code, due to missing semicolon before it!\n\n";
|
||||||
|
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
if (err.what == "var") {
|
if (err.what == "var") {
|
||||||
os << "If you want to create variable inside expression try wrapping them inside parentheses like this:\n";
|
os << "If you want to create variable inside expression try wrapping them inside parentheses like this:\n";
|
||||||
@ -234,7 +234,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
[&](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\n";
|
os << "I expected an identifier in " << err.context << ", but found" << (err.type_name.empty() ? "" : " ") << err.type_name << " value = '" << err.source << "'\n\n";
|
||||||
|
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
if (err.type_name == "chord") {
|
if (err.type_name == "chord") {
|
||||||
os << "Try renaming to different name or appending with something that is not part of chord literal like 'x'\n";
|
os << "Try renaming to different name or appending with something that is not part of chord literal like 'x'\n";
|
||||||
@ -252,7 +252,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
{
|
{
|
||||||
os << "I tried to call function '" << err.name << "' but you gave me wrong types for it!\n";
|
os << "I tried to call function '" << err.name << "' but you gave me wrong types for it!\n";
|
||||||
|
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
os << "Make sure that all values matches one of supported signatures listed below!\n";
|
os << "Make sure that all values matches one of supported signatures listed below!\n";
|
||||||
os << '\n';
|
os << '\n';
|
||||||
@ -267,7 +267,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
os << "I tried and failed to evaluate operator '" << err.name << "' due to values with wrong types provided\n";
|
os << "I tried and failed to evaluate operator '" << err.name << "' due to values with wrong types provided\n";
|
||||||
os << "Make sure that both values matches one of supported signatures listed below!\n";
|
os << "Make sure that both values matches one of supported signatures listed below!\n";
|
||||||
os << '\n';
|
os << '\n';
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
|
|
||||||
if (err.name == "+") { os << "Addition only supports:\n"; }
|
if (err.name == "+") { os << "Addition only supports:\n"; }
|
||||||
@ -285,7 +285,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
os << "Value of type " << err.type << " cannot be called.\n";
|
os << "Value of type " << err.type << " cannot be called.\n";
|
||||||
os << "\n";
|
os << "\n";
|
||||||
|
|
||||||
print_error_line();
|
print_error_line(loc);
|
||||||
|
|
||||||
os << "Only values of this types can be called:\n";
|
os << "Only values of this types can be called:\n";
|
||||||
os << " - musical values like c, c47, (c&g) can be called to provide octave and duration\n";
|
os << " - musical values like c, c47, (c&g) can be called to provide octave and duration\n";
|
||||||
@ -299,9 +299,21 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
|
|||||||
os << "when correct code for such expression would be [4;3]\n";
|
os << "when correct code for such expression would be [4;3]\n";
|
||||||
os << pretty::end;
|
os << pretty::end;
|
||||||
},
|
},
|
||||||
|
[&](errors::Unexpected_Empty_Source const& err) {
|
||||||
|
switch (err.reason) {
|
||||||
|
break; case errors::Unexpected_Empty_Source::Block_Without_Closing_Bracket:
|
||||||
|
os << "Reached end of input when waiting for closing of a block ']'\n";
|
||||||
|
os << "Expected block end after:\n\n";
|
||||||
|
print_error_line(loc);
|
||||||
|
|
||||||
|
if (err.start) {
|
||||||
|
os << "Which was introduced by block starting here:\n\n";
|
||||||
|
print_error_line(err.start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
[&](errors::Undefined_Operator const&) { unimplemented(); },
|
[&](errors::Undefined_Operator const&) { unimplemented(); },
|
||||||
[&](errors::Unexpected_Keyword const&) { unimplemented(); },
|
[&](errors::Unexpected_Keyword const&) { unimplemented(); },
|
||||||
[&](errors::Unexpected_Empty_Source const&) { unimplemented(); }
|
|
||||||
}, err.details);
|
}, err.details);
|
||||||
|
|
||||||
return os;
|
return os;
|
||||||
|
@ -272,8 +272,11 @@ Result<Ast> Parser::parse_atomic_expression()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Error {
|
return Error {
|
||||||
.details = errors::Unexpected_Empty_Source {},
|
.details = errors::Unexpected_Empty_Source {
|
||||||
.location = {}
|
.reason = errors::Unexpected_Empty_Source::Block_Without_Closing_Bracket,
|
||||||
|
.start = opening.location
|
||||||
|
},
|
||||||
|
.location = tokens.back().location
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
consume();
|
consume();
|
||||||
|
Loading…
Reference in New Issue
Block a user