Files
newsolstice/src/parser/parser.cpp
2026-07-31 15:58:09 +10:00

191 lines
5.8 KiB
C++

#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;
}
}