#include "parser.h" #include namespace camellya { Parser::Parser(std::vector tokens) : tokens_(std::move(tokens)) {} Program Parser::parse() { std::vector statements; while (!is_at_end()) { try { statements.push_back(declaration()); } catch (const ParseError& error) { synchronize(); } } return Program(std::move(statements)); } Token Parser::peek() const { return tokens_[current_]; } Token Parser::previous() const { return tokens_[current_ - 1]; } bool Parser::is_at_end() const { return peek().type == TokenType::END_OF_FILE; } Token Parser::advance() { if (!is_at_end()) current_++; return previous(); } bool Parser::check(TokenType type) const { if (is_at_end()) return false; return peek().type == type; } bool Parser::match(std::initializer_list types) { for (TokenType type : types) { if (check(type)) { advance(); return true; } } return false; } Token Parser::consume(TokenType type, const std::string& message) { if (check(type)) return advance(); throw error(peek(), message); } ParseError Parser::error(const Token& token, const std::string& message) { std::string error_msg = std::format("Line {}: Error at '{}': {}", token.line, token.lexeme, message); return ParseError(error_msg); } void Parser::synchronize() { advance(); while (!is_at_end()) { if (previous().type == TokenType::SEMICOLON) return; switch (peek().type) { case TokenType::CLASS: case TokenType::FUNC: case TokenType::VAR: case TokenType::FOR: case TokenType::IF: case TokenType::WHILE: case TokenType::RETURN: return; default: break; } advance(); } } StmtPtr Parser::declaration() { if (match({TokenType::CLASS})) { return class_declaration(); } if (match({TokenType::FUNC})) { return function_declaration(); } if (check(TokenType::NUMBER) || check(TokenType::STRING) || check(TokenType::BOOL) || check(TokenType::LIST) || check(TokenType::MAP) || check(TokenType::IDENTIFIER)) { // Type name followed by identifier Token lookahead = tokens_[current_]; if (current_ + 1 < tokens_.size() && tokens_[current_ + 1].type == TokenType::IDENTIFIER) { return var_declaration(); } } return statement(); } StmtPtr Parser::class_declaration() { Token name = consume(TokenType::IDENTIFIER, "Expected class name."); consume(TokenType::LEFT_BRACE, "Expected '{' before class body."); std::vector members; while (!check(TokenType::RIGHT_BRACE) && !is_at_end()) { // Parse field or method if (check(TokenType::FUNC)) { advance(); members.push_back(function_declaration()); } else { members.push_back(var_declaration()); consume(TokenType::SEMICOLON, "Expected ';' after field declaration."); } } consume(TokenType::RIGHT_BRACE, "Expected '}' after class body."); return std::make_unique(name.lexeme, std::move(members)); } StmtPtr Parser::function_declaration() { Token name = consume(TokenType::IDENTIFIER, "Expected function name."); consume(TokenType::LEFT_PAREN, "Expected '(' after function name."); std::vector> parameters; if (!check(TokenType::RIGHT_PAREN)) { do { Token type_token = advance(); std::string type_name = type_token.lexeme; Token param_name = consume(TokenType::IDENTIFIER, "Expected parameter name."); parameters.emplace_back(type_name, param_name.lexeme); } while (match({TokenType::COMMA})); } consume(TokenType::RIGHT_PAREN, "Expected ')' after parameters."); std::string return_type = "nil"; if (match({TokenType::ARROW})) { Token type_token = advance(); return_type = type_token.lexeme; } consume(TokenType::LEFT_BRACE, "Expected '{' before function body."); StmtPtr body = block_statement(); auto body_block = std::shared_ptr(static_cast(body.release())); return std::make_unique(name.lexeme, std::move(parameters), return_type, std::move(body_block)); } StmtPtr Parser::var_declaration() { Token type_token = advance(); std::string type_name = type_token.lexeme; Token name = consume(TokenType::IDENTIFIER, "Expected variable name."); ExprPtr initializer = nullptr; if (match({TokenType::EQUAL})) { initializer = expression(); } return std::make_unique(type_name, name.lexeme, std::move(initializer)); } StmtPtr Parser::statement() { if (match({TokenType::IF})) return if_statement(); if (match({TokenType::WHILE})) return while_statement(); if (match({TokenType::FOR})) return for_statement(); if (match({TokenType::RETURN})) return return_statement(); if (match({TokenType::LEFT_BRACE})) return block_statement(); return expression_statement(); } StmtPtr Parser::if_statement() { consume(TokenType::LEFT_PAREN, "Expected '(' after 'if'."); ExprPtr condition = expression(); consume(TokenType::RIGHT_PAREN, "Expected ')' after if condition."); StmtPtr then_branch = statement(); StmtPtr else_branch = nullptr; if (match({TokenType::ELSE})) { else_branch = statement(); } return std::make_unique(std::move(condition), std::move(then_branch), std::move(else_branch)); } StmtPtr Parser::while_statement() { consume(TokenType::LEFT_PAREN, "Expected '(' after 'while'."); ExprPtr condition = expression(); consume(TokenType::RIGHT_PAREN, "Expected ')' after while condition."); StmtPtr body = statement(); return std::make_unique(std::move(condition), std::move(body)); } StmtPtr Parser::for_statement() { consume(TokenType::LEFT_PAREN, "Expected '(' after 'for'."); StmtPtr initializer = nullptr; if (!match({TokenType::SEMICOLON})) { initializer = declaration(); consume(TokenType::SEMICOLON, "Expected ';' after for initializer."); } ExprPtr condition = nullptr; if (!check(TokenType::SEMICOLON)) { condition = expression(); } consume(TokenType::SEMICOLON, "Expected ';' after for condition."); ExprPtr increment = nullptr; if (!check(TokenType::RIGHT_PAREN)) { increment = expression(); } consume(TokenType::RIGHT_PAREN, "Expected ')' after for clauses."); StmtPtr body = statement(); return std::make_unique(std::move(initializer), std::move(condition), std::move(increment), std::move(body)); } StmtPtr Parser::return_statement() { ExprPtr value = nullptr; if (!check(TokenType::SEMICOLON)) { value = expression(); } consume(TokenType::SEMICOLON, "Expected ';' after return value."); return std::make_unique(std::move(value)); } StmtPtr Parser::block_statement() { std::vector statements; while (!check(TokenType::RIGHT_BRACE) && !is_at_end()) { auto stmt = declaration(); // If declaration returned a VarDecl (not a class/function/statement), consume semicolon if (dynamic_cast(stmt.get())) { consume(TokenType::SEMICOLON, "Expected ';' after variable declaration."); } statements.push_back(std::move(stmt)); } consume(TokenType::RIGHT_BRACE, "Expected '}' after block."); return std::make_unique(std::move(statements)); } StmtPtr Parser::expression_statement() { ExprPtr expr = expression(); consume(TokenType::SEMICOLON, "Expected ';' after expression."); return std::make_unique(std::move(expr)); } ExprPtr Parser::expression() { return assignment(); } ExprPtr Parser::assignment() { ExprPtr expr = logical_or(); if (match({TokenType::EQUAL})) { Token equals = previous(); ExprPtr value = assignment(); if (auto* var_expr = dynamic_cast(expr.get())) { return std::make_unique(var_expr->name, std::move(value)); } else if (auto* get_expr = dynamic_cast(expr.get())) { return std::make_unique(std::move(get_expr->object), get_expr->name, std::move(value)); } else if (auto* index_expr = dynamic_cast(expr.get())) { return std::make_unique(std::move(index_expr->object), std::move(index_expr->index), std::move(value)); } throw error(equals, "Invalid assignment target."); } return expr; } ExprPtr Parser::logical_or() { ExprPtr expr = logical_and(); while (match({TokenType::OR})) { Token op = previous(); ExprPtr right = logical_and(); expr = std::make_unique(std::move(expr), op.lexeme, std::move(right)); } return expr; } ExprPtr Parser::logical_and() { ExprPtr expr = equality(); while (match({TokenType::AND})) { Token op = previous(); ExprPtr right = equality(); expr = std::make_unique(std::move(expr), op.lexeme, std::move(right)); } return expr; } ExprPtr Parser::equality() { ExprPtr expr = comparison(); while (match({TokenType::EQUAL_EQUAL, TokenType::BANG_EQUAL})) { Token op = previous(); ExprPtr right = comparison(); expr = std::make_unique(std::move(expr), op.lexeme, std::move(right)); } return expr; } ExprPtr Parser::comparison() { ExprPtr expr = term(); while (match({TokenType::GREATER, TokenType::GREATER_EQUAL, TokenType::LESS, TokenType::LESS_EQUAL})) { Token op = previous(); ExprPtr right = term(); expr = std::make_unique(std::move(expr), op.lexeme, std::move(right)); } return expr; } ExprPtr Parser::term() { ExprPtr expr = factor(); while (match({TokenType::MINUS, TokenType::PLUS})) { Token op = previous(); ExprPtr right = factor(); expr = std::make_unique(std::move(expr), op.lexeme, std::move(right)); } return expr; } ExprPtr Parser::factor() { ExprPtr expr = unary(); while (match({TokenType::SLASH, TokenType::STAR, TokenType::PERCENT})) { Token op = previous(); ExprPtr right = unary(); expr = std::make_unique(std::move(expr), op.lexeme, std::move(right)); } return expr; } ExprPtr Parser::unary() { if (match({TokenType::BANG, TokenType::MINUS})) { Token op = previous(); ExprPtr right = unary(); return std::make_unique(op.lexeme, std::move(right)); } return call(); } ExprPtr Parser::call() { ExprPtr expr = primary(); while (true) { if (match({TokenType::LEFT_PAREN})) { expr = finish_call(std::move(expr)); } else if (match({TokenType::DOT})) { Token name = consume(TokenType::IDENTIFIER, "Expected property name after '.'."); expr = std::make_unique(std::move(expr), name.lexeme); } else if (match({TokenType::LEFT_BRACKET})) { ExprPtr index = expression(); consume(TokenType::RIGHT_BRACKET, "Expected ']' after index."); expr = std::make_unique(std::move(expr), std::move(index)); } else { break; } } return expr; } ExprPtr Parser::primary() { if (match({TokenType::TRUE})) { return std::make_unique(true); } if (match({TokenType::FALSE})) { return std::make_unique(false); } if (match({TokenType::NIL})) { return std::make_unique(); } if (match({TokenType::NUMBER_LITERAL})) { return std::make_unique(std::get(previous().literal)); } if (match({TokenType::STRING_LITERAL})) { return std::make_unique(std::get(previous().literal)); } if (match({TokenType::THIS})) { return std::make_unique("this"); } if (match({TokenType::IDENTIFIER})) { return std::make_unique(previous().lexeme); } if (match({TokenType::LEFT_PAREN})) { ExprPtr expr = expression(); consume(TokenType::RIGHT_PAREN, "Expected ')' after expression."); return expr; } if (match({TokenType::LEFT_BRACKET})) { std::vector elements; if (!check(TokenType::RIGHT_BRACKET)) { do { elements.push_back(expression()); } while (match({TokenType::COMMA})); } consume(TokenType::RIGHT_BRACKET, "Expected ']' after list elements."); return std::make_unique(std::move(elements)); } if (match({TokenType::LEFT_BRACE})) { std::vector> pairs; if (!check(TokenType::RIGHT_BRACE)) { do { ExprPtr key = expression(); consume(TokenType::COLON, "Expected ':' after map key."); ExprPtr value = expression(); pairs.emplace_back(std::move(key), std::move(value)); } while (match({TokenType::COMMA})); } consume(TokenType::RIGHT_BRACE, "Expected '}' after map pairs."); return std::make_unique(std::move(pairs)); } throw error(peek(), "Expected expression."); } ExprPtr Parser::finish_call(ExprPtr callee) { std::vector arguments; if (!check(TokenType::RIGHT_PAREN)) { do { arguments.push_back(expression()); } while (match({TokenType::COMMA})); } consume(TokenType::RIGHT_PAREN, "Expected ')' after arguments."); return std::make_unique(std::move(callee), std::move(arguments)); } } // namespace camellya