Browse Source

Everywhere: Add Error class for generic error reporting

The Lexer can now also report errors.
master
Riyyi 2 years ago
parent
commit
9816bb3de2
  1. 7
      src/ast.cpp
  2. 19
      src/ast.h
  3. 45
      src/error.h
  4. 8
      src/lexer.cpp
  5. 1
      src/lexer.h
  6. 27
      src/printer.cpp
  7. 1
      src/printer.h
  8. 42
      src/reader.cpp
  9. 12
      src/step1_read_print.cpp

7
src/ast.cpp

@ -10,13 +10,6 @@
namespace blaze { namespace blaze {
Error::Error(const std::string& error)
: m_error(error)
{
}
// -----------------------------------------
List::~List() List::~List()
{ {
for (auto node : m_nodes) { for (auto node : m_nodes) {

19
src/ast.h

@ -23,7 +23,6 @@ public:
template<typename T> template<typename T>
bool fastIs() const = delete; bool fastIs() const = delete;
virtual bool isError() const { return false; }
virtual bool isVector() const { return false; } virtual bool isVector() const { return false; }
virtual bool isHashMap() const { return false; } virtual bool isHashMap() const { return false; }
virtual bool isList() 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 { class Vector final : public ASTNode {
public: public:
@ -159,9 +143,6 @@ private:
// ----------------------------------------- // -----------------------------------------
// clang-format off // clang-format off
template<>
inline bool ASTNode::fastIs<Error>() const { return isError(); }
template<> template<>
inline bool ASTNode::fastIs<Vector>() const { return isVector(); } inline bool ASTNode::fastIs<Vector>() const { return isVector(); }

45
src/error.h

@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <vector>
#include "ruc/singleton.h"
#include "lexer.h"
namespace blaze {
class Error final : public ruc::Singleton<Error> {
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<Token> m_token_errors;
std::vector<std::string> m_other_errors;
};
} // namespace blaze

8
src/lexer.cpp

@ -11,6 +11,7 @@
#include "ruc/format/print.h" #include "ruc/format/print.h"
#include "ruc/genericlexer.h" #include "ruc/genericlexer.h"
#include "error.h"
#include "lexer.h" #include "lexer.h"
namespace blaze { namespace blaze {
@ -28,7 +29,7 @@ Lexer::~Lexer()
void Lexer::tokenize() void Lexer::tokenize()
{ {
if (m_tokens.size() != 0) { if (Error::the().hasAnyError() || m_tokens.size() > 0) {
return; return;
} }
@ -152,8 +153,9 @@ bool Lexer::consumeString()
if (character == '"') { if (character == '"') {
text += character; text += character;
} }
else {
print("lex text '{}'\n", text); Error::the().addError({ Token::Type::Error, m_line, column, "expected '\"', got EOF" });
}
m_tokens.push_back({ Token::Type::String, m_line, column, text }); m_tokens.push_back({ Token::Type::String, m_line, column, text });

1
src/lexer.h

@ -34,6 +34,7 @@ struct Token {
String, // "foobar" String, // "foobar"
Comment, // ; Comment, // ;
Value, // symbols, numbers, "true", "false", and "nil" Value, // symbols, numbers, "true", "false", and "nil"
Error,
}; };
Type type { Type::None }; Type type { Type::None };

27
src/printer.cpp

@ -4,8 +4,10 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include "lexer.h"
#include "ruc/format/print.h" #include "ruc/format/print.h"
#include "error.h"
#include "printer.h" #include "printer.h"
#include "types.h" #include "types.h"
@ -25,6 +27,11 @@ Printer::~Printer()
void Printer::dump() void Printer::dump()
{ {
if (Error::the().hasAnyError()) {
dumpError();
return;
}
if (m_node == nullptr) { if (m_node == nullptr) {
return; return;
} }
@ -41,11 +48,7 @@ void Printer::dumpImpl(ASTNode* node)
} }
}; };
if (is<List>(node)) {
if (is<Error>(node)) {
print("*** blaze error *** {}", static_cast<Error*>(node)->error());
}
else if (is<List>(node)) {
printSpacing(); printSpacing();
print("("); print("(");
m_firstNode = false; 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 } // namespace blaze

1
src/printer.h

@ -20,6 +20,7 @@ public:
private: private:
void dumpImpl(ASTNode* node); void dumpImpl(ASTNode* node);
void dumpError();
bool m_firstNode { true }; bool m_firstNode { true };
bool m_previousNodeIsList { false }; bool m_previousNodeIsList { false };

42
src/reader.cpp

@ -9,6 +9,7 @@
#include <cstdlib> // std::strtoll #include <cstdlib> // std::strtoll
#include <utility> // std::move #include <utility> // std::move
#include "error.h"
#include "ruc/format/color.h" #include "ruc/format/color.h"
#include "ruc/meta/assert.h" #include "ruc/meta/assert.h"
@ -31,7 +32,7 @@ Reader::~Reader()
void Reader::read() void Reader::read()
{ {
if (m_node) { if (Error::the().hasAnyError() || m_node) {
return; return;
} }
@ -40,26 +41,26 @@ void Reader::read()
// Error checking // Error checking
if (m_invalid_syntax) { 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; return;
} }
if (m_is_unbalanced) { 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; return;
} }
if (!isEOF()) { if (!isEOF()) {
Token::Type type = peek().type; Token::Type type = peek().type;
switch (type) { switch (type) {
case Token::Type::ParenOpen: // ( case Token::Type::ParenOpen: // (
case Token::Type::ParenClose: // ) case Token::Type::ParenClose: // )
case Token::Type::String: case Token::Type::String:
case Token::Type::Value: case Token::Type::Value:
m_node = new Error("More than one sexp in input"); Error::the().addError("more than one sexp in input");
break; break;
default: default:
m_node = new Error("Unknown error"); Error::the().addError("unknown error");
break; break;
}; };
} }
@ -110,39 +111,12 @@ ASTNode* Reader::readList()
return list; 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() ASTNode* Reader::readString()
{ {
std::string symbol = consume().symbol; std::string symbol = consume().symbol;
// Unbalanced string // Unbalanced string
if (!isValidString(symbol)) { if (symbol.size() < 2 || symbol.front() != '"' || symbol.back() != '"') {
m_error_character = '"'; m_error_character = '"';
m_is_unbalanced = true; m_is_unbalanced = true;
} }

12
src/step1_read_print.cpp

@ -4,6 +4,7 @@
#include <string> // std::getline #include <string> // std::getline
#include <string_view> #include <string_view>
#include "error.h"
#include "ruc/format/color.h" #include "ruc/format/color.h"
#include "ast.h" #include "ast.h"
@ -14,9 +15,9 @@
#define PRETTY_PRINT 0 #define PRETTY_PRINT 0
#if 1 #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.tokenize();
// lexer.dump(); // lexer.dump();
blaze::Reader reader(std::move(lexer.tokens())); blaze::Reader reader(std::move(lexer.tokens()));
@ -37,9 +38,12 @@ auto print(blaze::ASTNode* node) -> void
printer.dump(); 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 static auto cleanup(int signal) -> void

Loading…
Cancel
Save