initial commit
This commit is contained in:
190
src/parser/parser.cpp
Normal file
190
src/parser/parser.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#include "parser.hpp"
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
|
||||
using TT = Solstice::TokenType;
|
||||
|
||||
namespace Solstice {
|
||||
|
||||
std::unordered_map<TokenType, NodeType> tokToNodeType = {
|
||||
{TT::Math_Add, NodeType::Add},
|
||||
{TT::Math_Subtract, NodeType::Subtract},
|
||||
{TT::Math_Multiply, NodeType::Multiply},
|
||||
{TT::Math_Divide, NodeType::Divide},
|
||||
{TT::Comparison_Equal, NodeType::Equal},
|
||||
{TT::Comparison_NotEqual, NodeType::NotEqual},
|
||||
{TT::Comparison_GreaterThan, NodeType::GreaterThan},
|
||||
{TT::Comparison_LesserThan, NodeType::LesserThan},
|
||||
};
|
||||
|
||||
std::optional<Token> Parser::peek(int64_t ahead) {
|
||||
if (current + ahead >= input.size() || current + ahead < 0) {
|
||||
return {};
|
||||
}
|
||||
return input[current + ahead];
|
||||
}
|
||||
|
||||
std::optional<Token> Parser::consume() {
|
||||
if (current >= input.size()) {
|
||||
return {};
|
||||
}
|
||||
return input[current++];
|
||||
}
|
||||
|
||||
std::optional<Node> Parser::getPreviousNode(Node& parent) {
|
||||
if (parent.children.empty()) {
|
||||
return {};
|
||||
}
|
||||
Node node = parent.children[parent.children.size() - 1];
|
||||
parent.children.pop_back();
|
||||
return node;
|
||||
}
|
||||
|
||||
Node Parser::parseExpr(TT type) {
|
||||
auto left = getPreviousNode(output);
|
||||
if (!left.has_value()) {
|
||||
throw std::runtime_error("Expecting expression on left of '+'");
|
||||
}
|
||||
consume(); // be rid of the +
|
||||
Precedence precedence = getTokenPrecedence(Token(type));
|
||||
auto right = parseOneNode(precedence);
|
||||
if (!right.has_value()) {
|
||||
throw std::runtime_error("Expecting expression on right of '+'");
|
||||
}
|
||||
|
||||
NodeType nodeType;
|
||||
if (tokToNodeType.find(type) == tokToNodeType.end()) {
|
||||
throw std::runtime_error("FIXME couldn't map token type to node type");
|
||||
} else {
|
||||
nodeType = tokToNodeType[type];
|
||||
}
|
||||
|
||||
return Node(nodeType, {*left, *right});
|
||||
}
|
||||
|
||||
Node Parser::parseLiteral() {
|
||||
auto current = peek(-1);
|
||||
if (!current.has_value()) {
|
||||
throw std::runtime_error("FIXME couldn't get current token");
|
||||
}
|
||||
auto literal = current->getLiteral();
|
||||
if (!literal.has_value()) {
|
||||
throw std::runtime_error("FIXME token with type literal does not hold a literal");
|
||||
}
|
||||
|
||||
return Node(*literal);
|
||||
}
|
||||
|
||||
Node Parser::parseIdentifier() {
|
||||
auto current = peek(-1);
|
||||
if (!current.has_value()) {
|
||||
throw std::runtime_error("FIXME couldn't get current token");
|
||||
}
|
||||
auto id = current->getIdentifier();
|
||||
if (!id.has_value()) {
|
||||
throw std::runtime_error("FIXME token with type identifier does not hold an identifier");
|
||||
}
|
||||
|
||||
return Node(*id);
|
||||
}
|
||||
|
||||
Precedence Parser::getTokenPrecedence(const Token& token) {
|
||||
static size_t braceCount = 0;
|
||||
static size_t bracketCount = 0;
|
||||
static size_t spikyBracketCount = 0;
|
||||
switch (token.type) {
|
||||
case TT::OpenCurly: {
|
||||
braceCount++;
|
||||
return Precedence::Other;
|
||||
}
|
||||
case TT::CloseCurly: {
|
||||
braceCount--;
|
||||
return Precedence::Other;
|
||||
}
|
||||
case TT::OpenSpiky: {
|
||||
spikyBracketCount++;
|
||||
return Precedence::Other;
|
||||
}
|
||||
case TT::CloseSpiky: {
|
||||
spikyBracketCount--;
|
||||
return Precedence::Other;
|
||||
}
|
||||
case TT::OpenParen: {
|
||||
bracketCount++;
|
||||
return Precedence::Other;
|
||||
}
|
||||
case TT::CloseParen: {
|
||||
bracketCount--;
|
||||
return Precedence::Other;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
if (braceCount > 0) {
|
||||
return Precedence::Other;
|
||||
}
|
||||
if (bracketCount > 0) {
|
||||
return Precedence::Other;
|
||||
}
|
||||
if (spikyBracketCount > 0) {
|
||||
return Precedence::Other;
|
||||
}
|
||||
switch (token.type) {
|
||||
case TT::None:
|
||||
case TT::Kw_Type:
|
||||
case TT::Hash_CImport:
|
||||
case TT::Hash_Effect:
|
||||
case TT::Action_Function:
|
||||
return Precedence::Other;
|
||||
case TT::Math_Add:
|
||||
case TT::Math_Subtract:
|
||||
return Precedence::Add;
|
||||
case TT::Math_Multiply:
|
||||
case TT::Math_Divide:
|
||||
return Precedence::Multiply;
|
||||
case TT::Assign_Bind:
|
||||
case TT::Assign_Set:
|
||||
case TT::Assign_Type:
|
||||
return Precedence::Set;
|
||||
case TT::NewLine:
|
||||
return Precedence::NewLine;
|
||||
case TT::Identifier:
|
||||
return Precedence::Identifier;
|
||||
case TT::Literal:
|
||||
return Precedence::Identifier;
|
||||
default:
|
||||
return Precedence::Other;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Node> Parser::parseOneNode(Precedence precedence) {
|
||||
auto next = peek();
|
||||
if (!next.has_value()) {
|
||||
return {};
|
||||
}
|
||||
if (getTokenPrecedence(*next) >= precedence) {
|
||||
return {};
|
||||
}
|
||||
consume();
|
||||
switch (next->type) {
|
||||
case TT::None: break;
|
||||
case TT::Identifier:
|
||||
return parseIdentifier();
|
||||
case TT::Literal:
|
||||
return parseLiteral();
|
||||
case TT::Math_Add:
|
||||
case TT::Math_Subtract:
|
||||
case TT::Math_Multiply:
|
||||
case TT::Math_Divide:
|
||||
return parseExpr(next->type);
|
||||
}
|
||||
throw std::runtime_error("FIXME: unimplemented parsing case");
|
||||
}
|
||||
|
||||
const Node& Parser::parse() {
|
||||
while (auto node = parseOneNode(Precedence::Root)) {
|
||||
output.children.push_back(*node);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
95
src/parser/parser.hpp
Normal file
95
src/parser/parser.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
#include "../lexer/lexer.hpp"
|
||||
|
||||
namespace Solstice {
|
||||
|
||||
enum class NodeType {
|
||||
Root, Literal, Identifier,
|
||||
FunctionBind, Bind, Set,
|
||||
Lambda, FunctionCall,
|
||||
Add, Subtract, Multiply, Divide,
|
||||
Equal, NotEqual, GreaterThan, LesserThan
|
||||
};
|
||||
|
||||
enum class Precedence {
|
||||
NewLine,
|
||||
Identifier,
|
||||
If,
|
||||
While,
|
||||
Compare,
|
||||
Set,
|
||||
FunctionCall,
|
||||
Add,
|
||||
Multiply,
|
||||
Other,
|
||||
Root
|
||||
};
|
||||
|
||||
extern std::unordered_map<TokenType, NodeType> tokToNodeType;
|
||||
|
||||
class Node {
|
||||
public:
|
||||
NodeType type = NodeType::Root;
|
||||
std::vector<Node> children;
|
||||
std::variant<Literal, std::string> data;
|
||||
|
||||
Node() = delete;
|
||||
Node(NodeType type) : type(type) {}
|
||||
Node(NodeType type, const std::vector<Node>& children) : type(type), children(children) {}
|
||||
Node(const Literal& literal) : type(NodeType::Literal), data(literal) {}
|
||||
Node(const std::string& id) : type(NodeType::Identifier), data(id) {}
|
||||
};
|
||||
|
||||
class Parser {
|
||||
|
||||
std::vector<Token> input;
|
||||
Node output{NodeType::Root};
|
||||
|
||||
size_t current = 0;
|
||||
|
||||
std::optional<Token> peek(int64_t ahead = 0);
|
||||
std::optional<Token> consume();
|
||||
|
||||
std::optional<Node> getPreviousNode(Node& parent);
|
||||
|
||||
Node parseKwType();
|
||||
|
||||
Node parseHashCimport();
|
||||
Node parseHashEffect();
|
||||
|
||||
Node parseAssignBind();
|
||||
Node parseAssignSet();
|
||||
Node parseAssignType();
|
||||
|
||||
Node parseActionFunction();
|
||||
|
||||
Node parseExpr(TokenType type);
|
||||
|
||||
Node parseOpenCurly();
|
||||
Node parseOpenParen();
|
||||
Node parseOpenSpiky();
|
||||
Node parseCloseCurly();
|
||||
Node parseCloseParen();
|
||||
Node parseCloseSpiky();
|
||||
Node parseNewLine();
|
||||
|
||||
Node parseLiteral();
|
||||
Node parseIdentifier();
|
||||
|
||||
static Precedence getTokenPrecedence(const Token& token);
|
||||
|
||||
// Returns false when finished
|
||||
std::optional<Node> parseOneNode(Precedence precedence = Precedence::Other);
|
||||
|
||||
public:
|
||||
Parser() = delete;
|
||||
Parser(const std::vector<Token>& input) : input(input) {}
|
||||
|
||||
const Node& parse();
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user