diff --git a/Makefile b/Makefile index fd98db9..ab5b3c4 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ Obj= \ location.o \ number.o \ parser.o \ + pretty.o \ unicode.o \ unicode_tables.o \ value.o diff --git a/src/errors.cc b/src/errors.cc index e3dd40f..f04b275 100644 --- a/src/errors.cc +++ b/src/errors.cc @@ -37,30 +37,37 @@ static std::ostream& error_heading( Error_Level lvl, std::string_view short_description) { + std::stringstream ss; + switch (lvl) { case Error_Level::Error: - os << "ERROR " << short_description << ' '; + ss << pretty::begin_error << "ERROR " << pretty::end << short_description; break; // This branch should be reached if we have Error_Level::Bug // or definetely where error level is outside of enum Error_Level default: - os << "IMPLEMENTATION BUG " << short_description << ' '; + ss << pretty::begin_error << "IMPLEMENTATION BUG " << pretty::end << short_description; } if (location) { - os << " at " << *location; + ss << " at " << pretty::begin_path << *location << pretty::end; } + auto heading = std::move(ss).str(); + os << heading << '\n'; + + auto const line_length = heading.size(); + std::fill_n(std::ostreambuf_iterator(os), line_length, '-'); return os << '\n'; } static void encourage_contact(std::ostream &os) { - os << + os << pretty::begin_comment << "\n" "Interpreter got in state that was not expected by it's developers.\n" "Contact them providing code that coused it and error message above to resolve this trouble\n" - << std::flush; + << pretty::end << std::flush; } void assert(bool condition, std::string message, Location loc) @@ -69,7 +76,7 @@ void assert(bool condition, std::string message, Location loc) error_heading(std::cerr, loc, Error_Level::Bug, "Assertion in interpreter"); if (not message.empty()) - std::cerr << "with message: " << message << std::endl; + std::cerr << message << std::endl; encourage_contact(std::cerr); @@ -91,7 +98,6 @@ void assert(bool condition, std::string message, Location loc) [[noreturn]] void unreachable(Location loc) { - error_heading(std::cerr, loc, Error_Level::Bug, "Reached unreachable state"); encourage_contact(std::cerr); std::exit(1); @@ -117,7 +123,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err) visit(Overloaded { [&os](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: " << 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 << "\n"; os << "Musique only accepts characters that are unicode letters or ascii numbers and punctuation\n"; @@ -138,7 +144,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err) os << " Token type: " << ut.type << '\n'; os << " Token source: " << ut.source << '\n'; - os << "\nThis error is considered an internal one. It should not be displayed to the end user.\n"; + 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); }, diff --git a/src/main.cc b/src/main.cc index 3f13698..c809950 100644 --- a/src/main.cc +++ b/src/main.cc @@ -111,6 +111,10 @@ std::vector eternal_sources; /// Fancy main that supports Result forwarding on error (Try macro) static Result Main(std::span args) { + if (isatty(STDOUT_FILENO) && getenv("NO_COLOR") == nullptr) { + pretty::terminal_mode(); + } + /// Describes all arguments that will be run struct Run { @@ -211,7 +215,11 @@ static Result Main(std::span args) continue; } - Try(runner.run(raw, "")); + auto result = runner.run(raw, ""); + if (not result.has_value()) { + std::cout << std::flush; + std::cerr << result.error() << std::flush; + } // We don't free input line since there could be values that still relay on it } } diff --git a/src/musique.hh b/src/musique.hh index a789fbf..09bfb7d 100644 --- a/src/musique.hh +++ b/src/musique.hh @@ -122,6 +122,18 @@ namespace errors >; } +/// All code related to pretty printing +namespace pretty +{ + std::ostream& begin_error(std::ostream&); + std::ostream& begin_path(std::ostream&); + std::ostream& begin_comment(std::ostream&); + std::ostream& end(std::ostream&); + + void terminal_mode(); + void no_color_mode(); +} + template struct Overloaded : Lambdas... { using Lambdas::operator()...; };