Everywhere: Add Error class for generic error reporting
The Lexer can now also report errors.
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
+5
-3
@@ -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 });
|
||||||
|
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
+22
-5
@@ -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
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
+8
-34
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user