diff --git a/src/parser.cpp b/src/parser.cpp index bf2a896..eee0556 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,4 +1,3 @@ -// src/parser.cpp #include "parser.hpp" #include "ast.hpp" @@ -20,139 +19,103 @@ const std::unordered_map>& Parser::definition } const Token& Parser::peek() const { - if (position >= tokens.size()) - throw std::runtime_error("parser: unexpected end of file"); - return tokens[position]; + if (position >= tokens.size()) + throw std::runtime_error("parser: unexpected end of file"); + return tokens[position]; } const Token& Parser::get() { - if (position >= tokens.size()) - throw std::runtime_error("parser: unexpected end of file"); - return tokens[position++]; + if (position >= tokens.size()) + throw std::runtime_error("parser: unexpected end of file"); + return tokens[position++]; } bool Parser::accept(TokenType t) { - if (position < tokens.size() && tokens[position].type == t) { - ++position; - return true; - } - return false; + if (position < tokens.size() && tokens[position].type == t) { + ++position; + return true; + } + return false; } void Parser::expect(TokenType t) { - if (!accept(t)) { - std::cout << display_tokentype(t) << std::endl; - throw std::runtime_error("parser: unexpected token at position " - + std::to_string(peek().start)); - } + if (!accept(t)) { + std::cout << display_tokentype(t) << std::endl; + throw std::runtime_error("parser: unexpected token at position " + std::to_string(peek().start)); + } } -// Try to parse a definition of the form: -// '=' ';' -// Returns true if a definition was parsed and stored in defs. +// parse expressions like "main = \ x . x;" bool Parser::tryParseDefinition() { - if (peek().type == TokenType::VARIABLE - && position+1 < tokens.size() - && tokens[position+1].type == TokenType::EQUALS) - { - std::string name = get().lexeme; // consume VARIABLE - expect(TokenType::EQUALS); // consume '=' + if (peek().type == TokenType::VARIABLE && position+1 < tokens.size() && tokens[position+1].type == TokenType::EQUALS) { + std::string name = get().lexeme; + expect(TokenType::EQUALS); - // parse the right-hand term - std::unique_ptr value = parseTerm(); + std::unique_ptr value = parseApplication(); - // require a semicolon (EOL token) - expect(TokenType::EOL); + expect(TokenType::EOL); - // store in definitions map - defs.emplace(std::move(name), std::move(value)); - return true; - } - return false; + defs.emplace(std::move(name), std::move(value)); + return true; + } + return false; } -// ::= '\' + '.' -// | -// | '(' ')' +// parse simple expressions like "\ x . x" or "x" or stuff in parenthesis std::unique_ptr Parser::parseSimple() { - // abstraction with one-or-more parameters - if (accept(TokenType::LAMBDA)) { - std::vector params; - while (peek().type == TokenType::VARIABLE) { - params.push_back(get().lexeme); + if (accept(TokenType::LAMBDA)) { + std::vector params; + while (peek().type == TokenType::VARIABLE) { + params.push_back(get().lexeme); + } + expect(TokenType::DOT); + + std::unique_ptr body = parseApplication(); + for (auto it = params.rbegin(); it != params.rend(); ++it) { + body = std::make_unique(*it, std::move(body)); + } + return body; } - expect(TokenType::DOT); - std::unique_ptr body = parseTerm(); - // right-nest them: \p1.\p2.…body - for (auto it = params.rbegin(); it != params.rend(); ++it) { - body = std::make_unique(*it, std::move(body)); + if (peek().type == TokenType::VARIABLE) { + const auto &tok = get(); + return std::make_unique(tok.lexeme); } - return body; - } - // variable - if (peek().type == TokenType::VARIABLE) { - const auto &tok = get(); - return std::make_unique(tok.lexeme); - } + if (accept(TokenType::LPAREN)) { + std::unique_ptr e = parseApplication(); + expect(TokenType::RPAREN); + return e; + } - // parenthesized term - if (accept(TokenType::LPAREN)) { - std::unique_ptr e = parseTerm(); - expect(TokenType::RPAREN); - return e; - } - - throw std::runtime_error("parser: expected \\, variable, or '(' at position " - + std::to_string(peek().start)); + throw std::runtime_error("parser: expected \\, variable, or '(' at position " + std::to_string(peek().start)); } -// ::= { } +// parse function applications std::unique_ptr Parser::parseApplication() { - std::unique_ptr expr = parseSimple(); - while (true) { - TokenType t = peek().type; - if (t == TokenType::VARIABLE || - t == TokenType::LAMBDA || - t == TokenType::LPAREN) - { - std::unique_ptr rhs = parseSimple(); - expr = std::make_unique(std::move(expr), std::move(rhs)); - } else { - break; + std::unique_ptr expr = parseSimple(); + while (true) { + TokenType t = peek().type; + if (t == TokenType::VARIABLE || t == TokenType::LAMBDA || t == TokenType::LPAREN) { + std::unique_ptr rhs = parseSimple(); + expr = std::make_unique(std::move(expr), std::move(rhs)); + } + else break; } - } - return expr; + return expr; } -// ::= -std::unique_ptr Parser::parseTerm() { - return parseApplication(); -} - -// parse exactly one term and expect EOC -std::unique_ptr Parser::parse() { - std::unique_ptr root = parseTerm(); - expect(TokenType::EOC); - return root; -} - -// ::= { | EOL } EOC +// uuum... i think the name says it? std::vector> Parser::parseProgram() { - std::vector> results; + std::vector> results; - while (peek().type != TokenType::EOC) { - // first try a definition - if (tryParseDefinition()) - continue; + while (peek().type != TokenType::EOC) { + if (tryParseDefinition()) continue; - // otherwise a bare term ending in EOL - results.push_back(parseTerm()); - expect(TokenType::EOL); - } + results.push_back(parseApplication()); + expect(TokenType::EOL); + } - expect(TokenType::EOC); - return results; + expect(TokenType::EOC); + return results; } - diff --git a/src/print.cpp b/src/print.cpp index 3c2d863..a43a43a 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -3,6 +3,8 @@ #include #include +// thank you chatgpt lol + // Forward‐declare static void _print(const Expr* e, std::ostream& out); @@ -51,6 +53,6 @@ static void _print(const Expr* e, std::ostream& out) { } // fallback - out << ""; + out << "print: unknown expression"; }