Everywhere: Pass step1 tests by supporting more Tokens in the Reader
This commit is contained in:
+2
-4
@@ -10,16 +10,14 @@
|
||||
|
||||
namespace blaze {
|
||||
|
||||
List::~List()
|
||||
Collection::~Collection()
|
||||
{
|
||||
for (auto node : m_nodes) {
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void List::addNode(ASTNode* node)
|
||||
void Collection::addNode(ASTNode* node)
|
||||
{
|
||||
m_nodes.push_back(node);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
template<typename T>
|
||||
bool fastIs() const = delete;
|
||||
|
||||
virtual bool isCollection() const { return false; }
|
||||
virtual bool isVector() const { return false; }
|
||||
virtual bool isHashMap() const { return false; }
|
||||
virtual bool isList() const { return false; }
|
||||
@@ -30,56 +31,68 @@ public:
|
||||
virtual bool isNumber() const { return false; }
|
||||
virtual bool isSpecialSymbol() const { return false; }
|
||||
virtual bool isSymbol() const { return false; }
|
||||
|
||||
protected:
|
||||
ASTNode() {}
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// []
|
||||
class Vector final : public ASTNode {
|
||||
class Collection : public ASTNode {
|
||||
public:
|
||||
Vector();
|
||||
virtual ~Vector();
|
||||
virtual ~Collection() override;
|
||||
|
||||
virtual bool isVector() const override { return true; }
|
||||
|
||||
private:
|
||||
std::vector<ASTNode*> m_nodes;
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// {}
|
||||
class HashMap final : public ASTNode {
|
||||
public:
|
||||
HashMap();
|
||||
virtual ~HashMap();
|
||||
|
||||
virtual bool isHashMap() const override { return true; }
|
||||
|
||||
private:
|
||||
std::vector<ASTNode*> m_nodes;
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// ()
|
||||
class List final : public ASTNode {
|
||||
public:
|
||||
List() = default;
|
||||
virtual ~List() override;
|
||||
|
||||
virtual bool isList() const override { return true; }
|
||||
virtual bool isCollection() const override { return true; }
|
||||
|
||||
void addNode(ASTNode* node);
|
||||
|
||||
const std::vector<ASTNode*>& nodes() const { return m_nodes; }
|
||||
|
||||
protected:
|
||||
Collection() {}
|
||||
|
||||
private:
|
||||
std::vector<ASTNode*> m_nodes;
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// []
|
||||
class Vector final : public Collection {
|
||||
public:
|
||||
Vector() = default;
|
||||
virtual ~Vector() = default;
|
||||
|
||||
virtual bool isCollection() const override { return false; }
|
||||
virtual bool isVector() const override { return true; }
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// {}
|
||||
class HashMap final : public Collection {
|
||||
public:
|
||||
HashMap() = default;
|
||||
virtual ~HashMap() = default;
|
||||
|
||||
virtual bool isCollection() const override { return false; }
|
||||
virtual bool isHashMap() const override { return true; }
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// ()
|
||||
class List final : public Collection {
|
||||
public:
|
||||
List() = default;
|
||||
virtual ~List() = default;
|
||||
|
||||
virtual bool isCollection() const override { return false; }
|
||||
virtual bool isList() const override { return true; }
|
||||
};
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
// "string"
|
||||
class String final : public ASTNode {
|
||||
public:
|
||||
@@ -143,6 +156,9 @@ private:
|
||||
// -----------------------------------------
|
||||
|
||||
// clang-format off
|
||||
template<>
|
||||
inline bool ASTNode::fastIs<Collection>() const { return isCollection(); }
|
||||
|
||||
template<>
|
||||
inline bool ASTNode::fastIs<Vector>() const { return isVector(); }
|
||||
|
||||
|
||||
+2
-2
@@ -39,10 +39,10 @@ void Lexer::tokenize()
|
||||
consumeSpliceUnquoteOrUnquote();
|
||||
break;
|
||||
case '[':
|
||||
m_tokens.push_back({ Token::Type::ParenOpen, m_line, m_column, "[" });
|
||||
m_tokens.push_back({ Token::Type::BracketOpen, m_line, m_column, "[" });
|
||||
break;
|
||||
case ']':
|
||||
m_tokens.push_back({ Token::Type::ParenClose, m_line, m_column, "]" });
|
||||
m_tokens.push_back({ Token::Type::BracketClose, m_line, m_column, "]" });
|
||||
break;
|
||||
case '{':
|
||||
m_tokens.push_back({ Token::Type::BraceOpen, m_line, m_column, "{" });
|
||||
|
||||
+25
-1
@@ -48,7 +48,31 @@ void Printer::dumpImpl(ASTNode* node)
|
||||
}
|
||||
};
|
||||
|
||||
if (is<List>(node)) {
|
||||
if (is<Vector>(node)) {
|
||||
printSpacing();
|
||||
print("[");
|
||||
m_firstNode = false;
|
||||
m_previousNodeIsList = true;
|
||||
Vector* vector = static_cast<Vector*>(node);
|
||||
for (size_t i = 0; i < vector->nodes().size(); ++i) {
|
||||
dumpImpl(vector->nodes()[i]);
|
||||
m_previousNodeIsList = false;
|
||||
}
|
||||
print("]");
|
||||
}
|
||||
else if (is<HashMap>(node)) {
|
||||
printSpacing();
|
||||
print("{{");
|
||||
m_firstNode = false;
|
||||
m_previousNodeIsList = true;
|
||||
HashMap* hash_map = static_cast<HashMap*>(node);
|
||||
for (size_t i = 0; i < hash_map->nodes().size(); ++i) {
|
||||
dumpImpl(hash_map->nodes()[i]);
|
||||
m_previousNodeIsList = false;
|
||||
}
|
||||
print("}}");
|
||||
}
|
||||
else if (is<List>(node)) {
|
||||
printSpacing();
|
||||
print("(");
|
||||
m_firstNode = false;
|
||||
|
||||
+104
@@ -59,6 +59,8 @@ void Reader::read()
|
||||
case Token::Type::Value:
|
||||
Error::the().addError("more than one sexp in input");
|
||||
break;
|
||||
case Token::Type::Comment:
|
||||
break;
|
||||
default:
|
||||
Error::the().addError("unknown error");
|
||||
break;
|
||||
@@ -76,6 +78,22 @@ ASTNode* Reader::readImpl()
|
||||
case Token::Type::Special: // ~@
|
||||
return readSpliceUnquote();
|
||||
break;
|
||||
case Token::Type::BracketOpen: // [
|
||||
return readVector();
|
||||
break;
|
||||
case Token::Type::BracketClose: // ]
|
||||
m_invalid_syntax = true;
|
||||
m_error_character = ']';
|
||||
return nullptr;
|
||||
break;
|
||||
case Token::Type::BraceOpen: // {
|
||||
return readHashMap();
|
||||
break;
|
||||
case Token::Type::BraceClose: // }
|
||||
m_invalid_syntax = true;
|
||||
m_error_character = '}';
|
||||
return nullptr;
|
||||
break;
|
||||
case Token::Type::ParenOpen: // (
|
||||
return readList();
|
||||
break;
|
||||
@@ -93,9 +111,19 @@ ASTNode* Reader::readImpl()
|
||||
case Token::Type::Tilde: // ~
|
||||
return readUnquote();
|
||||
break;
|
||||
case Token::Type::Caret: // ^
|
||||
return readWithMeta();
|
||||
break;
|
||||
case Token::Type::At: // @
|
||||
return readDeref();
|
||||
break;
|
||||
case Token::Type::String:
|
||||
return readString();
|
||||
break;
|
||||
case Token::Type::Comment: // ;
|
||||
ignore();
|
||||
return nullptr;
|
||||
break;
|
||||
case Token::Type::Value:
|
||||
return readValue();
|
||||
break;
|
||||
@@ -124,6 +152,40 @@ ASTNode* Reader::readSpliceUnquote()
|
||||
return list;
|
||||
}
|
||||
|
||||
ASTNode* Reader::readVector()
|
||||
{
|
||||
ignore(); // [
|
||||
|
||||
Vector* vector = new Vector();
|
||||
while (!isEOF() && peek().type != Token::Type::BracketClose) {
|
||||
vector->addNode(readImpl());
|
||||
}
|
||||
|
||||
if (!consumeSpecific(Token { .type = Token::Type::BracketClose })) { // ]
|
||||
m_error_character = ']';
|
||||
m_is_unbalanced = true;
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
ASTNode* Reader::readHashMap()
|
||||
{
|
||||
ignore(); // {
|
||||
|
||||
HashMap* vector = new HashMap();
|
||||
while (!isEOF() && peek().type != Token::Type::BraceClose) {
|
||||
vector->addNode(readImpl());
|
||||
}
|
||||
|
||||
if (!consumeSpecific(Token { .type = Token::Type::BraceClose })) { // }
|
||||
m_error_character = '}';
|
||||
m_is_unbalanced = true;
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
ASTNode* Reader::readList()
|
||||
{
|
||||
ignore(); // (
|
||||
@@ -189,6 +251,43 @@ ASTNode* Reader::readUnquote()
|
||||
return list;
|
||||
}
|
||||
|
||||
ASTNode* Reader::readWithMeta()
|
||||
{
|
||||
ignore(); // ^
|
||||
|
||||
ignore(); // first token
|
||||
if (isEOF()) { // second token
|
||||
Error::the().addError("expected form, got EOF");
|
||||
return nullptr;
|
||||
}
|
||||
retreat();
|
||||
|
||||
List* list = new List();
|
||||
list->addNode(new Symbol("with-meta"));
|
||||
ASTNode* first = readImpl();
|
||||
ASTNode* second = readImpl();
|
||||
list->addNode(second);
|
||||
list->addNode(first);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
ASTNode* Reader::readDeref()
|
||||
{
|
||||
ignore(); // @
|
||||
|
||||
if (isEOF()) {
|
||||
Error::the().addError("expected form, got EOF");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
List* list = new List();
|
||||
list->addNode(new Symbol("deref"));
|
||||
list->addNode(readImpl());
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
ASTNode* Reader::readString()
|
||||
{
|
||||
std::string symbol = consume().symbol;
|
||||
@@ -248,6 +347,11 @@ void Reader::ignore()
|
||||
m_index++;
|
||||
}
|
||||
|
||||
void Reader::retreat()
|
||||
{
|
||||
m_index--;
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void Reader::dump()
|
||||
|
||||
+11
-6
@@ -32,14 +32,19 @@ private:
|
||||
Token consume();
|
||||
bool consumeSpecific(Token token);
|
||||
void ignore();
|
||||
void retreat();
|
||||
|
||||
ASTNode* readImpl();
|
||||
ASTNode* readSpliceUnquote();
|
||||
ASTNode* readList();
|
||||
ASTNode* readQuote();
|
||||
ASTNode* readQuasiQuote();
|
||||
ASTNode* readUnquote();
|
||||
ASTNode* readString();
|
||||
ASTNode* readSpliceUnquote(); // ~@
|
||||
ASTNode* readVector(); // []
|
||||
ASTNode* readHashMap(); // {}
|
||||
ASTNode* readList(); // ()
|
||||
ASTNode* readQuote(); // '
|
||||
ASTNode* readQuasiQuote(); // `
|
||||
ASTNode* readUnquote(); // ~
|
||||
ASTNode* readWithMeta(); // ^
|
||||
ASTNode* readDeref(); // @
|
||||
ASTNode* readString(); // "foobar"
|
||||
ASTNode* readValue();
|
||||
|
||||
void dumpImpl(ASTNode* node);
|
||||
|
||||
Reference in New Issue
Block a user