diff --git a/src/ast.cpp b/src/ast.cpp index 04ff2d3..5b14c23 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -10,13 +10,6 @@ namespace blaze { -Error::Error(const std::string& error) - : m_error(error) -{ -} - -// ----------------------------------------- - List::~List() { for (auto node : m_nodes) { diff --git a/src/ast.h b/src/ast.h index b891c3e..5c411c7 100644 --- a/src/ast.h +++ b/src/ast.h @@ -23,7 +23,6 @@ public: template bool fastIs() const = delete; - virtual bool isError() const { return false; } virtual bool isVector() const { return false; } virtual bool isHashMap() const { return false; } virtual bool isList() const { return false; } @@ -35,21 +34,6 @@ public: // ----------------------------------------- -class Error final : public ASTNode { -public: - Error(const std::string& error); - virtual ~Error() = default; - - virtual bool isError() const override { return true; } - - const std::string& error() const { return m_error; } - -private: - std::string m_error; -}; - -// ----------------------------------------- - // [] class Vector final : public ASTNode { public: @@ -159,9 +143,6 @@ private: // ----------------------------------------- // clang-format off -template<> -inline bool ASTNode::fastIs() const { return isError(); } - template<> inline bool ASTNode::fastIs() const { return isVector(); } diff --git a/src/error.h b/src/error.h new file mode 100644 index 0000000..90eea3c --- /dev/null +++ b/src/error.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#include "ruc/singleton.h" + +#include "lexer.h" + +namespace blaze { + +class Error final : public ruc::Singleton { +public: + Error(s) {} + virtual ~Error() = default; + + void clearErrors() + { + m_token_errors.clear(); + m_other_errors.clear(); + } + void addError(Token error) { m_token_errors.push_back(error); } + void addError(const std::string& error) { m_other_errors.push_back(error); } + + bool hasTokenError() { return m_token_errors.size() > 0; } + bool hasOtherError() { return m_other_errors.size() > 0; } + bool hasAnyError() { return hasTokenError() || hasOtherError(); } + + void setInput(std::string_view input) { m_input = input; } + + Token tokenError() const { return m_token_errors[0]; } + const std::string& otherError() const { return m_other_errors[0]; } + +private: + std::string_view m_input; + std::vector m_token_errors; + std::vector m_other_errors; +}; + +} // namespace blaze diff --git a/src/lexer.cpp b/src/lexer.cpp index e123864..f423764 100644 --- a/src/lexer.cpp +++ b/src/lexer.cpp @@ -11,6 +11,7 @@ #include "ruc/format/print.h" #include "ruc/genericlexer.h" +#include "error.h" #include "lexer.h" namespace blaze { @@ -28,7 +29,7 @@ Lexer::~Lexer() void Lexer::tokenize() { - if (m_tokens.size() != 0) { + if (Error::the().hasAnyError() || m_tokens.size() > 0) { return; } @@ -152,8 +153,9 @@ bool Lexer::consumeString() if (character == '"') { text += character; } - - print("lex text '{}'\n", text); + else { + Error::the().addError({ Token::Type::Error, m_line, column, "expected '\"', got EOF" }); + } m_tokens.push_back({ Token::Type::String, m_line, column, text }); diff --git a/src/lexer.h b/src/lexer.h index 96f05af..2906ddd 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -34,6 +34,7 @@ struct Token { String, // "foobar" Comment, // ; Value, // symbols, numbers, "true", "false", and "nil" + Error, }; Type type { Type::None }; diff --git a/src/printer.cpp b/src/printer.cpp index bda16ff..1b4688b 100644 --- a/src/printer.cpp +++ b/src/printer.cpp @@ -4,8 +4,10 @@ * SPDX-License-Identifier: MIT */ +#include "lexer.h" #include "ruc/format/print.h" +#include "error.h" #include "printer.h" #include "types.h" @@ -25,6 +27,11 @@ Printer::~Printer() void Printer::dump() { + if (Error::the().hasAnyError()) { + dumpError(); + return; + } + if (m_node == nullptr) { return; } @@ -41,11 +48,7 @@ void Printer::dumpImpl(ASTNode* node) } }; - - if (is(node)) { - print("*** blaze error *** {}", static_cast(node)->error()); - } - else if (is(node)) { + if (is(node)) { printSpacing(); print("("); m_firstNode = false; @@ -71,4 +74,18 @@ void Printer::dumpImpl(ASTNode* node) } } +void Printer::dumpError() +{ + print("Error: "); + if (Error::the().hasTokenError()) { + Token error = Error::the().tokenError(); + print("{}", error.symbol); + } + else if (Error::the().hasOtherError()) { + std::string error = Error::the().otherError(); + print("{}", error); + } + print("\n"); +} + } // namespace blaze diff --git a/src/printer.h b/src/printer.h index 7039907..0b16ce6 100644 --- a/src/printer.h +++ b/src/printer.h @@ -20,6 +20,7 @@ public: private: void dumpImpl(ASTNode* node); + void dumpError(); bool m_firstNode { true }; bool m_previousNodeIsList { false }; diff --git a/src/reader.cpp b/src/reader.cpp index 9083822..0ba5f9c 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -9,6 +9,7 @@ #include // std::strtoll #include // std::move +#include "error.h" #include "ruc/format/color.h" #include "ruc/meta/assert.h" @@ -31,7 +32,7 @@ Reader::~Reader() void Reader::read() { - if (m_node) { + if (Error::the().hasAnyError() || m_node) { return; } @@ -40,26 +41,26 @@ void Reader::read() // Error checking if (m_invalid_syntax) { - m_node = new Error("Invalid read syntax: '" + std::string(1, m_error_character) + "'"); + Error::the().addError("invalid read syntax: '" + std::string(1, m_error_character) + "'"); return; } if (m_is_unbalanced) { - m_node = new Error("Expected '" + std::string(1, m_error_character) + "', got EOF"); + Error::the().addError("expected '" + std::string(1, m_error_character) + "', got EOF"); return; } if (!isEOF()) { Token::Type type = peek().type; switch (type) { - case Token::Type::ParenOpen: // ( + case Token::Type::ParenOpen: // ( case Token::Type::ParenClose: // ) case Token::Type::String: case Token::Type::Value: - m_node = new Error("More than one sexp in input"); + Error::the().addError("more than one sexp in input"); break; default: - m_node = new Error("Unknown error"); + Error::the().addError("unknown error"); break; }; } @@ -110,39 +111,12 @@ ASTNode* Reader::readList() return list; } -static bool isValidString(const std::string& str) -{ - if (str.size() < 2 || str.front() != '"' || str.back() != '"') { - return false; - } - if (str.size() == 2) { - return true; - } - - bool escaped = false; - for (auto it = str.begin() + 1; it != str.end() - 1; ++it) { - if (*it == '\\' && !escaped) { - escaped = true; - continue; - } - - // The last character needs to be an escaped '\' or not a '\' - if (it == str.end() - 2 && (escaped || *it != '\\')) { - return true; - } - - escaped = false; - } - - return false; -} - ASTNode* Reader::readString() { std::string symbol = consume().symbol; // Unbalanced string - if (!isValidString(symbol)) { + if (symbol.size() < 2 || symbol.front() != '"' || symbol.back() != '"') { m_error_character = '"'; m_is_unbalanced = true; } diff --git a/src/step1_read_print.cpp b/src/step1_read_print.cpp index 3efd03c..9544026 100644 --- a/src/step1_read_print.cpp +++ b/src/step1_read_print.cpp @@ -4,6 +4,7 @@ #include // std::getline #include +#include "error.h" #include "ruc/format/color.h" #include "ast.h" @@ -14,9 +15,9 @@ #define PRETTY_PRINT 0 #if 1 -auto read(std::string_view data) -> blaze::ASTNode* +auto read(std::string_view input) -> blaze::ASTNode* { - blaze::Lexer lexer(data); + blaze::Lexer lexer(input); lexer.tokenize(); // lexer.dump(); blaze::Reader reader(std::move(lexer.tokens())); @@ -37,9 +38,12 @@ auto print(blaze::ASTNode* node) -> void printer.dump(); } -auto rep(std::string_view data) -> void +auto rep(std::string_view input) -> void { - print(eval(read(data))); + blaze::Error::the().clearErrors(); + blaze::Error::the().setInput(input); + + print(eval(read(input))); } static auto cleanup(int signal) -> void