From 34afdd9642055c3e63c78bf5a18801d06659c837 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 1 Aug 2026 20:43:16 +1000 Subject: [PATCH] Function parsing! --- src/main.cpp | 17 +++++++- src/parser/parser.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++- src/parser/parser.hpp | 1 + 3 files changed, 112 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fcb57e7..42a27ad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,22 @@ #include "lexer/lexer.hpp" #include "parser/parser.hpp" #include +#include +#include +#include -int main() { - Solstice::Lexer lexer{"(2 + 2) / 5\n(1, 2, 3)"}; +int main(int argc, char** argv) { + + if (argc <= 1) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + std::ifstream file{argv[1]}; + std::stringstream ss; + ss << file.rdbuf(); + + Solstice::Lexer lexer{ss.str()}; auto lexed = lexer.lex(); Solstice::Parser parser{lexed}; diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index 79b8376..59310d3 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -44,6 +44,8 @@ namespace Solstice { return "Expression"; case NodeType::Tuple: return "Tuple"; + case NodeType::CodeBlock: + return "CodeBlock"; case NodeType::FunctionBind: return "FunctionBind"; case NodeType::Bind: @@ -70,8 +72,8 @@ namespace Solstice { return "GreaterThan"; case NodeType::LesserThan: return "LesserThan"; - } + throw std::runtime_error("FIXME Unhandled case in nodeTypeToString"); } std::ostream& operator<<(std::ostream& stream, const Node& node) { @@ -130,6 +132,37 @@ namespace Solstice { return node; } + Node Parser::parseActionFunction() { + Node node{NodeType::FunctionBind}; + + auto previous = getPreviousNode(*context); + if (!previous.has_value()) { + throw std::runtime_error("expecting function arguments before '->'"); + } + + // the previous node is either a tuple or expression (for lambda) or a function call (for named function) + if (previous->type == NodeType::FunctionCall) { + node.type = NodeType::FunctionBind; + node.children.push_back(previous->children[0]); // name + node.children.push_back(previous->children[1]); // args + } else if (previous->type == NodeType::Tuple || previous->type == NodeType::Expression) { + node.type = NodeType::Lambda; + previous->type = NodeType::Tuple; // for consistency's sake + node.children.push_back(*previous); + } else { + throw std::runtime_error("expecting function arguments before '->'"); + } + + // process the body for the function + auto body = parseOneNode(Precedence::Root); + if (!body.has_value()) { + throw std::runtime_error("expecting function body after '->'"); + } + node.children.push_back(*body); + + return node; + } + Node Parser::parseExpr(TT type) { auto left = getPreviousNode(*context); if (!left.has_value()) { @@ -215,6 +248,52 @@ namespace Solstice { return node; } + Node Parser::parseOpenCurly() { + Node node{NodeType::CodeBlock}; + + for (;;) { + while (peek().has_value() && peek()->type == TT::NewLine) { + consume(); + } + auto next = peek(); + if (!next.has_value()) { + throw std::runtime_error("unclosed curly bracket"); + } + if (next->type == TT::CloseCurly) { + consume(); + break; + } + + Node elem{NodeType::Root}; + Node* prevContext = context; + context = &elem; + + for (;;) { + auto t = peek(); + if (!t.has_value() || t->type == TT::CloseCurly) { + break; + } + auto n = parseOneNode(Precedence::NewLine); + if (!n.has_value()) break; + elem.children.push_back(*n); + } + + context = prevContext; + + if (elem.children.empty()) { + throw std::runtime_error("expecting expression in code block"); + } + node.children.push_back(elem.children.back()); + + auto sep = peek(); + if (!sep.has_value()) { + throw std::runtime_error("unclosed parens"); + } + } + + return node; + } + Node Parser::parseLiteral() { auto current = peek(-1); if (!current.has_value()) { @@ -238,6 +317,17 @@ namespace Solstice { throw std::runtime_error("FIXME token with type identifier does not hold an identifier"); } + // Check if it's a function call + auto next = peek(); + if (next.has_value() && next->type == TT::OpenParen) { + consume(); + Node argsNode = parseOpenParen(); + argsNode.type = NodeType::Tuple; + + Node callNode = {NodeType::FunctionCall, {*id, argsNode}}; + return callNode; + } + return Node(*id); } @@ -269,6 +359,7 @@ namespace Solstice { return Precedence::Compare; } + throw std::runtime_error("FIXME unhandled node precedence case"); } Precedence Parser::getTokenPrecedence(const Token& token) { @@ -322,6 +413,10 @@ namespace Solstice { return parseExpr(next->type); case TT::OpenParen: return parseOpenParen(); + case TT::Action_Function: + return parseActionFunction(); + case TT::OpenCurly: + return parseOpenCurly(); case TT::NewLine: // ignore new line diff --git a/src/parser/parser.hpp b/src/parser/parser.hpp index d392041..50e0071 100644 --- a/src/parser/parser.hpp +++ b/src/parser/parser.hpp @@ -10,6 +10,7 @@ namespace Solstice { enum class NodeType { Root, Literal, Identifier, Expression, Tuple, + CodeBlock, FunctionBind, Bind, Set, Lambda, FunctionCall, Add, Subtract, Multiply, Divide,