/
vit1251
/
cmm
Обзор
Документация
Войти
/
vit1251
/
cmm
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/parser.cpp
985 строк
42 KB
Vitold S
update
09 авг 2026, 02:25
09 авг 2026, 02:25
a36ae1e
Код
Авторство
О чём код?
#include "parser.h" #include <cstdio> #include <cstdlib> Parser::Parser(Lexer& lexer, ImportCallback on_import) : lexer_(lexer), on_import_(std::move(on_import)) {} bool Parser::check(TokenType type) const { return lexer_.current().type == type; } bool Parser::consume(TokenType type) { if (check(type)) { lexer_.advance(); return true; } return false; } Token Parser::peek(size_t n) { return lexer_.peek(n); } Token Parser::expect(TokenType type, const std::string& msg) { if (check(type)) { Token t = lexer_.current(); lexer_.advance(); return t; } std::string m = msg.empty() ? std::to_string(static_cast<int>(type)) : msg; fprintf(stderr, "%sexpected %s, got '%s'\n", error_prefix().c_str(), m.c_str(), lexer_.current().lexeme.c_str()); has_error_ = true; Token t; t.type = TokenType::ERROR; return t; } std::string Parser::error_prefix() const { auto& tok = lexer_.current(); return lexer_.filename() + ":" + std::to_string(tok.line) + ":" + std::to_string(tok.col) + ": "; } void Parser::error(const std::string& msg) { fprintf(stderr, "%s%s\n", error_prefix().c_str(), msg.c_str()); has_error_ = true; } // ---- Top-level ---- Program Parser::parse_program() { Program prog; prog_ = &prog; current_link_.clear(); while (!check(TokenType::EOF_) && !has_error_) { if (check(TokenType::CONST)) { parse_const_decl(prog); } else if (check(TokenType::ENUM)) { SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; lexer_.advance(); auto name_tok = expect(TokenType::IDENTIFIER, "enum name"); expect(TokenType::LBRACE, "'{'"); EnumDecl ed; ed.name = name_tok.lexeme; ed.loc = loc; while (!check(TokenType::RBRACE) && !check(TokenType::EOF_)) { auto field_tok = expect(TokenType::IDENTIFIER, "enum field"); expect(TokenType::EQ, "'='"); auto val = parse_expr(); // Desugar enum field to constant: EnumName_FieldName ConstantDecl cd; cd.name = ed.name + "_" + field_tok.lexeme; cd.type_name = "i32"; cd.loc = loc; if (val->kind == Expr::IntLiteral) { cd.int_value = val->int_value; } else if (val->kind == Expr::FloatLiteral) { cd.float_value = val->float_value; cd.is_float = true; } prog.constants.push_back(std::move(cd)); if (check(TokenType::COMMA)) lexer_.advance(); } expect(TokenType::RBRACE, "'}'"); prog.enums.push_back(std::move(ed)); } else if (check(TokenType::POUND)) { lexer_.advance(); // # expect(TokenType::LBRACKET, "'['"); auto attr_name = expect(TokenType::IDENTIFIER, "attribute name"); if (attr_name.lexeme == "no_mangle") { // #[no_mangle] expect(TokenType::RBRACKET, "']'"); // Set flag for the next fn declaration // Store a flag in a temporary that parse_fn_decl can check // Actually, the back() of prog.functions is set later // We'll set the flag from the outer code when check returns FN // For now, just set a flag that will be consumed current_no_mangle_ = true; } else if (attr_name.lexeme == "link") { // #[link(name = "...")] expect(TokenType::LPAREN, "'('"); expect(TokenType::IDENTIFIER, "'name'"); expect(TokenType::EQ, "'='"); auto name_tok = expect(TokenType::STRING, "library name"); expect(TokenType::RPAREN, "')'"); expect(TokenType::RBRACKET, "']'"); current_link_ = name_tok.lexeme; } else { expect(TokenType::RBRACKET, "']'"); error("unknown attribute '" + attr_name.lexeme + "'"); } } else if (check(TokenType::USE)) parse_use(prog); else if (check(TokenType::STRUCT)) parse_struct_decl(prog); else if (check(TokenType::IMPL)) parse_impl_block(prog); else if (check(TokenType::EXTERN)) { lexer_.advance(); std::string call_conv; if (check(TokenType::STRING)) { call_conv = lexer_.current().lexeme; lexer_.advance(); } if (check(TokenType::LBRACE)) { // extern "C" { ... } std::string link_lib = current_link_; current_link_.clear(); parse_extern_block(prog, link_lib, call_conv); } else { // extern "C" fn name(...) -> Type; bool is_pub = false; if (check(TokenType::PUB)) { is_pub = true; lexer_.advance(); } parse_fn_decl(prog, true, call_conv); if (is_pub && !prog.functions.empty()) prog.functions.back()->is_pub = true; current_link_.clear(); } } else if (check(TokenType::PUB)) { lexer_.advance(); if (check(TokenType::FN)) { parse_fn_decl(prog, false); if (!prog.functions.empty()) { prog.functions.back()->is_pub = true; if (current_no_mangle_) { prog.functions.back()->is_no_mangle = true; current_no_mangle_ = false; } } } else if (check(TokenType::STRUCT)) { parse_struct_decl(prog); if (!prog.structs.empty()) prog.structs.back().is_pub = true; } else if (check(TokenType::CONST)) { parse_const_decl(prog); if (!prog.constants.empty()) prog.constants.back().is_pub = true; } else { error("expected 'fn', 'struct' or 'const' after 'pub'"); } } else if (check(TokenType::FN)) { parse_fn_decl(prog, false); if (current_no_mangle_ && !prog.functions.empty()) { prog.functions.back()->is_no_mangle = true; current_no_mangle_ = false; } } else { error("unexpected token '" + lexer_.current().lexeme + "'"); lexer_.advance(); } } return prog; } void Parser::parse_extern_block(Program& prog, const std::string& link_lib, const std::string& call_conv) { expect(TokenType::LBRACE, "'{'"); while (!check(TokenType::RBRACE) && !check(TokenType::EOF_)) { if (check(TokenType::FN)) { // Parse like extern fn, but apply block-level attributes std::string saved_link = current_link_; current_link_ = link_lib; parse_fn_decl(prog, true, call_conv); current_link_ = saved_link; } else { error("expected fn in extern block"); lexer_.advance(); } } expect(TokenType::RBRACE, "'}'"); } void Parser::parse_const_decl(Program& prog) { SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; lexer_.advance(); auto name_tok = expect(TokenType::IDENTIFIER, "constant name"); expect(TokenType::COLON, "':'"); std::string type_name = parse_type_name(); expect(TokenType::EQ, "'='"); auto val = parse_expr(); expect(TokenType::SEMICOLON, "';'"); ConstantDecl cd; cd.name = name_tok.lexeme; cd.type_name = type_name; cd.loc = loc; if (val->kind == Expr::IntLiteral) { cd.int_value = val->int_value; } else if (val->kind == Expr::FloatLiteral) { cd.float_value = val->float_value; cd.is_float = true; } else if (val->kind == Expr::BoolLiteral) { cd.bool_value = val->bool_value; cd.is_bool = true; } prog.constants.push_back(std::move(cd)); } void Parser::parse_use(Program& prog) { SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; lexer_.advance(); std::string path; std::vector<UseItem> items; if (check(TokenType::STRING)) { // Old-style: import "libc"; / use "libc"; path = lexer_.current().lexeme; lexer_.advance(); } else if (check(TokenType::IDENTIFIER)) { // New-style: use libc; / use net::tcp; / use wav::{WavWriter, WavFmt}; path = lexer_.current().lexeme; lexer_.advance(); // Handle :: path separator: use net::tcp; → path = "net/tcp" // Also handle use libc::{write, strlen}; → path = "libc", then { items } while (check(TokenType::COLON2)) { lexer_.advance(); // If the next token after :: is {, then this is use libc::{...} syntax if (check(TokenType::LBRACE)) break; path += "/"; auto seg = expect(TokenType::IDENTIFIER, "module name"); path += seg.lexeme; } if (check(TokenType::LBRACE)) { // use wav::{WavWriter, WavFmt}; or use libc::{write, strlen}; or use libc::{*}; lexer_.advance(); if (check(TokenType::STAR)) { // use module::{*}; lexer_.advance(); Import imp; imp.path = path; imp.wildcard = true; imp.loc = loc; prog.imports.push_back(std::move(imp)); if (on_import_) on_import_(path, loc, prog); expect(TokenType::RBRACE, "'}'"); expect(TokenType::SEMICOLON, "';'"); return; } while (!check(TokenType::RBRACE) && !check(TokenType::EOF_)) { UseItem u; u.name = expect(TokenType::IDENTIFIER, "item name").lexeme; u.alias = ""; // default: same as name if (check(TokenType::AS)) { lexer_.advance(); u.alias = expect(TokenType::IDENTIFIER, "alias name").lexeme; } items.push_back(u); if (!check(TokenType::RBRACE)) expect(TokenType::COMMA, "',' or '}'"); } expect(TokenType::RBRACE, "'}'"); } } else { error("expected module path"); return; } expect(TokenType::SEMICOLON, "';'"); if (!has_error_) { Import imp; imp.path = path; imp.use_items = items; imp.loc = loc; prog.imports.push_back(std::move(imp)); if (on_import_) on_import_(path, loc, prog); } } void Parser::parse_struct_decl(Program& prog) { SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; lexer_.advance(); auto name = expect(TokenType::IDENTIFIER, "struct name"); StructDecl sd; sd.name = name.lexeme; sd.loc = loc; // Generic type params: <T, E> if (check(TokenType::LT)) { lexer_.advance(); auto tp = expect(TokenType::IDENTIFIER, "type parameter"); sd.type_params.push_back(tp.lexeme); while (check(TokenType::COMMA)) { lexer_.advance(); tp = expect(TokenType::IDENTIFIER, "type parameter"); sd.type_params.push_back(tp.lexeme); } expect(TokenType::GT, "'>'"); } expect(TokenType::LBRACE, "'{'"); while (!check(TokenType::RBRACE) && !check(TokenType::EOF_)) { auto fn = expect(TokenType::IDENTIFIER, "field name"); expect(TokenType::COLON, "':'"); StructField f; f.name = fn.lexeme; f.type_name = parse_type_name(); sd.fields.push_back(f); if (!check(TokenType::RBRACE)) expect(TokenType::COMMA, "',' or '}'"); } expect(TokenType::RBRACE, "'}'"); if (!has_error_) prog.structs.push_back(std::move(sd)); } void Parser::parse_impl_block(Program& prog) { lexer_.advance(); std::string type_name; std::vector<std::string> impl_type_params; // Generic params: impl<T, E> if (check(TokenType::LT)) { lexer_.advance(); auto tp = expect(TokenType::IDENTIFIER, "type parameter"); impl_type_params.push_back(tp.lexeme); while (check(TokenType::COMMA)) { lexer_.advance(); tp = expect(TokenType::IDENTIFIER, "type parameter"); impl_type_params.push_back(tp.lexeme); } expect(TokenType::GT, "'>'"); } // Type name (may include generic args like Result<T, E>) if (check(TokenType::STAR)) type_name = parse_type_name(); else { auto tok = expect(TokenType::IDENTIFIER, "type name"); type_name = tok.lexeme; } // If there are impl type params, the type name might have a '<' following // Actually parse_type_name already handles <T, E> after identifier // But we already consumed the identifier. Reconstruct: if (check(TokenType::LT)) { // The type name has generic args: Result<T, E> std::string generic_suffix = "<"; lexer_.advance(); generic_suffix += parse_type_name(); while (check(TokenType::COMMA)) { lexer_.advance(); generic_suffix += "," + parse_type_name(); } expect(TokenType::GT, "'>'"); generic_suffix += ">"; type_name += generic_suffix; } expect(TokenType::LBRACE, "'{'"); while (!check(TokenType::RBRACE) && !check(TokenType::EOF_)) { bool is_pub = false; if (check(TokenType::PUB)) { is_pub = true; lexer_.advance(); } if (check(TokenType::FN)) { // Save state, parse fn, then mangle its name parse_fn_decl(prog, false); if (!prog.functions.empty()) { auto& fn = prog.functions.back(); // Mangle type name for function name: replace <, >, , with _ std::string mangled_base; for (char c : type_name) { if (c == '<' || c == ',') mangled_base += '_'; else if (c == '>') continue; // skip else mangled_base += c; } fn->name = mangled_base + "_" + fn->name; fn->is_method = true; if (is_pub) fn->is_pub = true; // If method has just `self` without type, set it to *Ty if (!fn->params.empty() && fn->params[0].name == "self" && fn->params[0].type_name.empty()) { fn->params[0].type_name = "*" + type_name; } } } else if (is_pub) { error("expected 'fn' after 'pub'"); } else { error("expected fn in impl block"); lexer_.advance(); } } expect(TokenType::RBRACE, "'}'"); } void Parser::parse_fn_decl(Program& prog, bool is_extern, std::string call_conv) { SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; expect(TokenType::FN, "'fn'"); std::string fn_name; if (check(TokenType::IDENTIFIER) || check(TokenType::DROP)) { fn_name = lexer_.current().lexeme; lexer_.advance(); } else { expect(TokenType::IDENTIFIER, "function name"); } expect(TokenType::LPAREN, "'('"); std::vector<Param> params; bool var_arg = false; while (!check(TokenType::RPAREN) && !check(TokenType::EOF_)) { if (check(TokenType::ELLIPSIS)) { lexer_.advance(); var_arg = true; break; } Param p; if (check(TokenType::SELF)) { p.name = lexer_.current().lexeme; lexer_.advance(); if (check(TokenType::COLON)) { lexer_.advance(); p.type_name = parse_type_name(); } else p.type_name = ""; // filled later if in impl } else { auto tok = expect(TokenType::IDENTIFIER, "parameter name"); p.name = tok.lexeme; if (check(TokenType::COLON)) { lexer_.advance(); p.type_name = parse_type_name(); } else p.type_name = "i32"; } params.push_back(p); if (check(TokenType::COMMA)) lexer_.advance(); } expect(TokenType::RPAREN, "')'"); std::string ret_type = "void"; if (check(TokenType::ARROW)) { lexer_.advance(); ret_type = parse_type_name(); } auto fn = std::make_unique<FnDecl>(); fn->name = fn_name; fn->params = params; fn->ret_type_name = ret_type; fn->is_extern = is_extern; fn->is_var_arg = var_arg; fn->call_conv = call_conv; fn->lib_name = current_link_; fn->loc = loc; if (is_extern) expect(TokenType::SEMICOLON, "';'"); else fn->body = parse_block(); if (!has_error_) prog.functions.push_back(std::move(fn)); } // ---- Block ---- std::unique_ptr<Block> Parser::parse_block() { auto b = std::make_unique<Block>(); b->loc.file = lexer_.filename(); b->loc.line = lexer_.current().line; b->loc.col = lexer_.current().col; expect(TokenType::LBRACE, "'{'"); while (!check(TokenType::RBRACE) && !check(TokenType::EOF_)) { if (check(TokenType::LET) || check(TokenType::IF) || check(TokenType::FOR) || check(TokenType::DROP) || check(TokenType::DEFER) || check(TokenType::RETURN) || check(TokenType::LBRACE)) { b->stmts.push_back(parse_stmt()); } else if (check(TokenType::STRING)) { auto expr = parse_primary(); if (check(TokenType::SEMICOLON)) { lexer_.advance(); auto s = std::make_unique<Stmt>(); s->kind = Stmt::ExprStmt; s->expr = std::move(expr); b->stmts.push_back(std::move(s)); } else { b->result = std::move(expr); break; } } else if (check(TokenType::IDENTIFIER) && peek().type == TokenType::LBRACKET) { // Assignment to array subscript: ident[expr] = expr; Token saved = lexer_.current(); lexer_.advance(); lexer_.advance(); // skip [ auto index = parse_expr(); expect(TokenType::RBRACKET, "']'"); expect(TokenType::EQ, "'='"); auto val = parse_expr(); expect(TokenType::SEMICOLON, "';'"); auto s = std::make_unique<Stmt>(); s->kind = Stmt::ExprStmt; auto ident = std::make_unique<Expr>(); ident->kind = Expr::Identifier; ident->name = saved.lexeme; ident->loc.file = lexer_.filename(); ident->loc.line = saved.line; ident->loc.col = saved.col; auto subs = std::make_unique<Expr>(); subs->kind = Expr::ArraySubscript; subs->array = std::move(ident); subs->index = std::move(index); auto assign = std::make_unique<Expr>(); assign->kind = Expr::BinaryOp; assign->op = TokenType::EQ; assign->left = std::move(subs); assign->right = std::move(val); s->expr = std::move(assign); b->stmts.push_back(std::move(s)); } else if (check(TokenType::IDENTIFIER) && peek().type == TokenType::EQ) { // Assignment: ident = expr; Token saved = lexer_.current(); lexer_.advance(); lexer_.advance(); auto val = parse_expr(); expect(TokenType::SEMICOLON, "';'"); auto s = std::make_unique<Stmt>(); s->kind = Stmt::ExprStmt; auto ident = std::make_unique<Expr>(); ident->kind = Expr::Identifier; ident->name = saved.lexeme; ident->loc.file = lexer_.filename(); ident->loc.line = saved.line; ident->loc.col = saved.col; auto assign = std::make_unique<Expr>(); assign->kind = Expr::BinaryOp; assign->op = TokenType::EQ; assign->left = std::move(ident); assign->right = std::move(val); s->expr = std::move(assign); b->stmts.push_back(std::move(s)); } else { auto expr = parse_expr(); if (check(TokenType::SEMICOLON)) { lexer_.advance(); auto s = std::make_unique<Stmt>(); s->kind = Stmt::ExprStmt; s->expr = std::move(expr); b->stmts.push_back(std::move(s)); } else { b->result = std::move(expr); break; } } } expect(TokenType::RBRACE, "'}'"); return b; } // ---- Statements ---- std::unique_ptr<Stmt> Parser::parse_stmt() { if (check(TokenType::LET)) return parse_let_stmt(); if (check(TokenType::IF)) return parse_if_stmt(); if (check(TokenType::FOR)) return parse_for_stmt(); if (check(TokenType::RETURN)) { lexer_.advance(); auto s = std::make_unique<Stmt>(); s->kind = Stmt::Return; if (!check(TokenType::SEMICOLON)) s->ret_expr = parse_expr(); expect(TokenType::SEMICOLON, "';'"); return s; } if (check(TokenType::DEFER)) { lexer_.advance(); auto s = std::make_unique<Stmt>(); s->kind = Stmt::Defer; s->defer_expr = parse_expr(); expect(TokenType::SEMICOLON, "';'"); return s; } if (check(TokenType::DROP)) { lexer_.advance(); expect(TokenType::LPAREN, "'('"); auto arg = parse_expr(); expect(TokenType::RPAREN, "')'"); expect(TokenType::SEMICOLON, "';'"); // Desugar drop(x) → call drop on x as a method auto s = std::make_unique<Stmt>(); s->kind = Stmt::ExprStmt; auto call = std::make_unique<Expr>(); call->kind = Expr::MethodCall; // Convert x to MethodCall receiver: x.drop() call->name = "drop"; call->receiver = std::move(arg); s->expr = std::move(call); return s; } if (check(TokenType::LBRACE)) { auto s = std::make_unique<Stmt>(); s->kind = Stmt::BlockStmt; s->block = parse_block(); return s; } // Check for assignment: ident = expr; if (check(TokenType::IDENTIFIER)) { // Peek ahead — but we can't un-consume easily. // Parse as expression, then check if it's followed by = auto saved = lexer_.current(); lexer_.advance(); if (check(TokenType::EQ)) { lexer_.advance(); auto val = parse_expr(); expect(TokenType::SEMICOLON, "';'"); auto s = std::make_unique<Stmt>(); s->kind = Stmt::ExprStmt; // Desugar: ident = val → store val to ident's alloca auto* ident_expr = new Expr(); ident_expr->kind = Expr::Identifier; ident_expr->name = saved.lexeme; // Create a special assignment expression auto assign = std::make_unique<Expr>(); assign->kind = Expr::BinaryOp; assign->op = TokenType::EQ; // reuse EQ as assign assign->left = std::unique_ptr<Expr>(ident_expr); assign->right = std::move(val); s->expr = std::move(assign); return s; } // Not assignment: put token back? We can't. Re-parse as expression // Build identifier expression manually auto ident_expr = std::make_unique<Expr>(); ident_expr->kind = Expr::Identifier; ident_expr->name = saved.lexeme; // Continue parsing the rest of the expression // Call parse_xxx starting from postfix with the identifier as lhs auto expr = parse_postfix(std::move(ident_expr)); if (check(TokenType::SEMICOLON)) { lexer_.advance(); auto s = std::make_unique<Stmt>(); s->kind = Stmt::ExprStmt; s->expr = std::move(expr); return s; } // If we got here, it's the last expression in a block (implicit return) // But parse_stmt is only called from parse_block for statement-starting tokens // So this path shouldn't normally be hit auto s = std::make_unique<Stmt>(); s->kind = Stmt::ExprStmt; s->expr = std::move(expr); expect(TokenType::SEMICOLON, "';'"); return s; } auto s = std::make_unique<Stmt>(); s->kind = Stmt::ExprStmt; s->expr = parse_expr(); expect(TokenType::SEMICOLON, "';'"); return s; } std::unique_ptr<Stmt> Parser::parse_let_stmt() { SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; lexer_.advance(); auto name = expect(TokenType::IDENTIFIER, "variable name"); expect(TokenType::COLON, "':'"); std::string type_name = parse_type_name(); expect(TokenType::EQ, "'='"); auto init = parse_expr(); expect(TokenType::SEMICOLON, "';'"); auto s = std::make_unique<Stmt>(); s->kind = Stmt::Let; s->loc = loc; s->let_name = name.lexeme; s->let_type = type_name; s->let_init = std::move(init); return s; } std::unique_ptr<Stmt> Parser::parse_if_stmt() { SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; lexer_.advance(); auto cond = parse_expr(); auto then_b = parse_block(); std::unique_ptr<Block> else_b; if (check(TokenType::ELSE)) { lexer_.advance(); if (check(TokenType::IF)) { auto inner = parse_if_stmt(); else_b = std::make_unique<Block>(); else_b->stmts.push_back(std::move(inner)); } else else_b = parse_block(); } auto s = std::make_unique<Stmt>(); s->kind = Stmt::If; s->loc = loc; s->if_cond = std::move(cond); s->if_then = std::move(then_b); s->if_else = std::move(else_b); return s; } std::unique_ptr<Stmt> Parser::parse_for_stmt() { SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; lexer_.advance(); auto s = std::make_unique<Stmt>(); s->kind = Stmt::For; s->loc = loc; if (check(TokenType::LBRACE)) { s->for_kind = Stmt::Infinite; s->for_body = parse_block(); } else if (check(TokenType::IDENTIFIER) && peek().type == TokenType::IN) { Token saved = lexer_.current(); lexer_.advance(); // ident lexer_.advance(); // in s->for_kind = Stmt::Iter; s->for_var = saved.lexeme; s->for_iter = parse_expr(); } else if (check(TokenType::IDENTIFIER) && peek().type == TokenType::LBRACE) { // for ident { ... } — simple while loop; prevent parse_expr from eating { as struct literal auto tok = lexer_.current(); lexer_.advance(); auto e = std::make_unique<Expr>(); e->kind = Expr::Identifier; e->name = tok.lexeme; e->loc.file = lexer_.filename(); e->loc.line = tok.line; e->loc.col = tok.col; s->for_kind = Stmt::While; s->for_cond = std::move(e); } else { s->for_kind = Stmt::While; s->for_cond = parse_expr(); } s->for_body = parse_block(); return s; } // ---- Constants ---- const ConstantDecl* Parser::find_const(const std::string& name) const { if (!prog_) return nullptr; for (auto& c : prog_->constants) if (c.name == name) return &c; return nullptr; } // ---- Type name ---- std::string Parser::parse_type_name() { std::string name; while (check(TokenType::STAR)) { name += '*'; lexer_.advance(); } if (check(TokenType::TYPE_I8)) { name += "i8"; lexer_.advance(); } else if (check(TokenType::TYPE_I16)) { name += "i16"; lexer_.advance(); } else if (check(TokenType::TYPE_I32)) { name += "i32"; lexer_.advance(); } else if (check(TokenType::TYPE_I64)) { name += "i64"; lexer_.advance(); } else if (check(TokenType::TYPE_U8)) { name += "u8"; lexer_.advance(); } else if (check(TokenType::TYPE_U16)) { name += "u16"; lexer_.advance(); } else if (check(TokenType::TYPE_U32)) { name += "u32"; lexer_.advance(); } else if (check(TokenType::TYPE_U64)) { name += "u64"; lexer_.advance(); } else if (check(TokenType::TYPE_F32)) { name += "f32"; lexer_.advance(); } else if (check(TokenType::TYPE_F64)) { name += "f64"; lexer_.advance(); } else if (check(TokenType::TYPE_BOOL)) { name += "bool"; lexer_.advance(); } else if (check(TokenType::TYPE_VOID)) { name += "void"; lexer_.advance(); } else if (check(TokenType::IDENTIFIER)) { name += lexer_.current().lexeme; lexer_.advance(); if (check(TokenType::LT)) { lexer_.advance(); name += '<' + parse_type_name(); while (check(TokenType::COMMA)) { lexer_.advance(); name += ',' + parse_type_name(); } expect(TokenType::GT, "'>'"); name += '>'; } } else if (check(TokenType::LBRACKET)) { lexer_.advance(); auto count_tok = expect(TokenType::NUMBER, "array size"); expect(TokenType::RBRACKET, "']'"); std::string elem = parse_type_name(); name = "[" + count_tok.lexeme + "]" + elem; } else error("expected type"); return name; } // ---- Expression parsing ---- std::unique_ptr<Expr> Parser::parse_expr() { return parse_logical_or(); } std::unique_ptr<Expr> Parser::parse_logical_or() { auto left = parse_logical_and(); while (check(TokenType::OR) && !has_error_) { lexer_.advance(); auto right = parse_logical_and(); auto e = std::make_unique<Expr>(); e->kind = Expr::BinaryOp; e->op = TokenType::OR; e->left = std::move(left); e->right = std::move(right); left = std::move(e); } return left; } std::unique_ptr<Expr> Parser::parse_bitwise_or() { auto left = parse_comparison(); while (check(TokenType::PIPE) && !has_error_) { lexer_.advance(); auto right = parse_comparison(); auto e = std::make_unique<Expr>(); e->kind = Expr::BinaryOp; e->op = TokenType::PIPE; e->left = std::move(left); e->right = std::move(right); left = std::move(e); } return left; } std::unique_ptr<Expr> Parser::parse_logical_and() { auto left = parse_bitwise_or(); while (check(TokenType::AND) && !has_error_) { lexer_.advance(); auto right = parse_comparison(); auto e = std::make_unique<Expr>(); e->kind = Expr::BinaryOp; e->op = TokenType::AND; e->left = std::move(left); e->right = std::move(right); left = std::move(e); } return left; } std::unique_ptr<Expr> Parser::parse_comparison() { auto left = parse_as_cast(); TokenType comp_ops[] = {TokenType::EQEQ, TokenType::NEQ, TokenType::LT, TokenType::GT, TokenType::LE, TokenType::GE}; for (auto op : comp_ops) { if (check(op)) { lexer_.advance(); auto right = parse_as_cast(); auto e = std::make_unique<Expr>(); e->kind = Expr::BinaryOp; e->op = op; e->left = std::move(left); e->right = std::move(right); return e; } } return left; } std::unique_ptr<Expr> Parser::parse_as_cast() { auto left = parse_range(); if (check(TokenType::AS)) { SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; lexer_.advance(); auto e = std::make_unique<Expr>(); e->kind = Expr::AsCast; e->loc = loc; e->as_expr = std::move(left); e->as_type_name = parse_type_name(); return e; } return left; } std::unique_ptr<Expr> Parser::parse_range() { auto left = parse_prefix(); if (check(TokenType::RANGE)) { lexer_.advance(); auto right = parse_prefix(); auto e = std::make_unique<Expr>(); e->kind = Expr::RangeLiteral; e->range_start = std::move(left); e->range_end = std::move(right); return e; } return left; } std::unique_ptr<Expr> Parser::parse_prefix() { if (check(TokenType::NOT)) { lexer_.advance(); auto operand = parse_prefix(); auto e = std::make_unique<Expr>(); e->kind = Expr::UnaryOp; e->op = TokenType::NOT; e->left = std::move(operand); return e; } if (check(TokenType::AMPERSAND)) { lexer_.advance(); auto operand = parse_prefix(); auto e = std::make_unique<Expr>(); e->kind = Expr::AddressOf; e->left = std::move(operand); return e; } if (check(TokenType::MINUS)) { lexer_.advance(); auto operand = parse_prefix(); // Desugar -x to x.neg() auto e = std::make_unique<Expr>(); e->kind = Expr::MethodCall; e->name = "neg"; // Build receiver from the operand // For literal like -1, desugar to 1.neg() if (operand->kind == Expr::IntLiteral) { // For -42, just create negated integer literal instead of method call auto e2 = std::make_unique<Expr>(); e2->kind = Expr::IntLiteral; e2->int_value = -operand->int_value; return e2; } e->receiver = std::move(operand); return e; } return parse_subscript(nullptr); } std::unique_ptr<Expr> Parser::parse_subscript(std::unique_ptr<Expr> lhs) { if (!lhs) lhs = parse_postfix(nullptr); while (check(TokenType::LBRACKET) && !has_error_) { lexer_.advance(); auto idx = parse_expr(); expect(TokenType::RBRACKET, "']'"); auto e = std::make_unique<Expr>(); e->kind = Expr::ArraySubscript; e->array = std::move(lhs); e->index = std::move(idx); lhs = std::move(e); } return lhs; } std::unique_ptr<Expr> Parser::parse_postfix(std::unique_ptr<Expr> lhs) { if (!lhs) lhs = parse_primary(); while (check(TokenType::DOT) && !has_error_) { lexer_.advance(); auto field_tok = expect(TokenType::IDENTIFIER, "field/method name"); if (check(TokenType::LPAREN)) { // Method call: x.foo(args) lexer_.advance(); auto args = parse_args(); expect(TokenType::RPAREN, "')'"); auto e = std::make_unique<Expr>(); e->kind = Expr::MethodCall; e->name = field_tok.lexeme; e->args = std::move(args); e->receiver = std::move(lhs); lhs = std::move(e); } else { // Field access: x.field auto e = std::make_unique<Expr>(); e->kind = Expr::FieldAccess; e->field_name = field_tok.lexeme; e->object = std::move(lhs); lhs = std::move(e); } } return lhs; } std::unique_ptr<Expr> Parser::parse_primary() { if (check(TokenType::STRING)) { auto tok = lexer_.current(); lexer_.advance(); auto e = std::make_unique<Expr>(); e->kind = Expr::StringLiteral; e->string_value = tok.lexeme; e->loc.file = lexer_.filename(); e->loc.line = tok.line; e->loc.col = tok.col; return e; } if (check(TokenType::NUMBER)) { auto tok = lexer_.current(); lexer_.advance(); auto e = std::make_unique<Expr>(); e->kind = Expr::IntLiteral; e->int_value = tok.int_value; e->literal_type = tok.literal_type; e->loc.file = lexer_.filename(); e->loc.line = tok.line; e->loc.col = tok.col; return e; } if (check(TokenType::FLOAT)) { auto tok = lexer_.current(); lexer_.advance(); auto e = std::make_unique<Expr>(); e->kind = Expr::FloatLiteral; e->float_value = tok.float_value; e->literal_type = tok.literal_type; e->loc.file = lexer_.filename(); e->loc.line = tok.line; e->loc.col = tok.col; return e; } if (check(TokenType::TRUE_) || check(TokenType::FALSE_)) { auto tok = lexer_.current(); lexer_.advance(); auto e = std::make_unique<Expr>(); e->kind = Expr::BoolLiteral; e->bool_value = (tok.type == TokenType::TRUE_); return e; } if (check(TokenType::SELF)) { auto tok = lexer_.current(); lexer_.advance(); auto e = std::make_unique<Expr>(); e->kind = Expr::Identifier; e->name = tok.lexeme; return e; } if (check(TokenType::FN)) { // Lambda: fn(params) -> Type { body } SourceLoc loc; loc.file = lexer_.filename(); loc.line = lexer_.current().line; loc.col = lexer_.current().col; lexer_.advance(); expect(TokenType::LPAREN, "'('"); std::vector<Param> params; while (!check(TokenType::RPAREN) && !check(TokenType::EOF_)) { Param p; if (check(TokenType::SELF)) { p.name = "self"; lexer_.advance(); } else { auto tok = expect(TokenType::IDENTIFIER, "parameter name"); p.name = tok.lexeme; } if (check(TokenType::COLON)) { lexer_.advance(); p.type_name = parse_type_name(); } else p.type_name = "i32"; params.push_back(p); if (check(TokenType::COMMA)) lexer_.advance(); } expect(TokenType::RPAREN, "')'"); std::string ret_type = "void"; if (check(TokenType::ARROW)) { lexer_.advance(); ret_type = parse_type_name(); } auto body = parse_block(); static int lambda_counter = 0; std::string lname = "_cmm_lambda_" + std::to_string(lambda_counter++); auto e = std::make_unique<Expr>(); e->kind = Expr::Lambda; e->lambda_params = std::move(params); e->lambda_ret_type = ret_type; e->lambda_body = std::move(body); e->lambda_name = lname; e->loc = loc; return e; } if (check(TokenType::IDENTIFIER)) { auto tok = lexer_.current(); lexer_.advance(); // Check if it's a constant //fprintf(stderr, "DEBUG: ident '%s'\n", tok.lexeme.c_str()); if (auto* cd = find_const(tok.lexeme)) { auto e = std::make_unique<Expr>(); if (cd->is_float) { e->kind = Expr::FloatLiteral; e->float_value = cd->float_value; } else if (cd->is_bool) { e->kind = Expr::BoolLiteral; e->bool_value = cd->bool_value; } else { e->kind = Expr::IntLiteral; e->int_value = cd->int_value; } e->loc = cd->loc; return e; } // Type::method(args) — static call // Type::method — reference to static method (like &Type::method) if (check(TokenType::COLON2)) { lexer_.advance(); auto method_tok = expect(TokenType::IDENTIFIER, "method name"); if (check(TokenType::LPAREN)) { lexer_.advance(); auto args = parse_args(); expect(TokenType::RPAREN, "')'"); auto e = std::make_unique<Expr>(); e->kind = Expr::Call; e->name = tok.lexeme + "_" + method_tok.lexeme; e->args = std::move(args); return e; } // Method reference (no parens): treat as identifier with mangled name auto e = std::make_unique<Expr>(); e->kind = Expr::Identifier; e->name = tok.lexeme + "_" + method_tok.lexeme; return e; } // Type { field: expr } or Type<T,E> { field: expr } — struct literal // Check for generic args: look ahead for < type , type > { ident : std::string struct_type_name = tok.lexeme; if (check(TokenType::LT)) { // Only consume as generic args if followed by a valid struct literal pattern // Peek: < TYPE , TYPE > { IDENTIFIER : bool is_generic_struct = false; if (peek(1).type == TokenType::TYPE_I32 || peek(1).type == TokenType::IDENTIFIER) { // May be generic — check further // We need < something , something > { ident : // For simplicity, just look for < and then { quickly // Actually we need to parse the generic args properly // But we can't because the < might be a comparison // Only treat as generic if followed by type{, type} > { ident : // This is heuristic and may fail for complex expressions // For v1, don't parse generic args on struct literal here // Let the type annotation handle it is_generic_struct = false; } if (is_generic_struct) { lexer_.advance(); struct_type_name += "<" + parse_type_name(); while (check(TokenType::COMMA)) { lexer_.advance(); struct_type_name += "," + parse_type_name(); } expect(TokenType::GT, "'>'"); struct_type_name += ">"; } } if (check(TokenType::LBRACE) && peek(1).type == TokenType::IDENTIFIER && peek(2).type == TokenType::COLON) { lexer_.advance(); auto e = std::make_unique<Expr>(); e->kind = Expr::StructInit; e->name = struct_type_name; while (!check(TokenType::RBRACE) && !check(TokenType::EOF_)) { auto ftok = expect(TokenType::IDENTIFIER, "field name"); expect(TokenType::COLON, "':'"); auto val = parse_expr(); e->struct_fields.emplace_back(ftok.lexeme, std::move(val)); if (check(TokenType::COMMA)) lexer_.advance(); } expect(TokenType::RBRACE, "'}'"); return e; } // foo(args) — function call if (check(TokenType::LPAREN)) { lexer_.advance(); auto args = parse_args(); expect(TokenType::RPAREN, "')'"); auto e = std::make_unique<Expr>(); e->kind = Expr::Call; e->name = tok.lexeme; e->args = std::move(args); return e; } // Variable reference auto e = std::make_unique<Expr>(); e->kind = Expr::Identifier; e->name = tok.lexeme; e->loc.file = lexer_.filename(); e->loc.line = tok.line; e->loc.col = tok.col; return e; } if (check(TokenType::LBRACKET)) { lexer_.advance(); if (check(TokenType::RBRACKET)) { error("empty array literal"); auto e = std::make_unique<Expr>(); e->kind = Expr::IntLiteral; return e; } auto val = parse_expr(); if (check(TokenType::SEMICOLON)) { // [val; count] — repeat syntax lexer_.advance(); auto count_tok = expect(TokenType::NUMBER, "array count"); expect(TokenType::RBRACKET, "']'"); auto e = std::make_unique<Expr>(); e->kind = Expr::ArrayLiteral; e->array_val = std::move(val); e->array_count = count_tok.int_value; return e; } // [val1, val2, ...] — explicit values auto e = std::make_unique<Expr>(); e->kind = Expr::ArrayLiteral; e->array_values.push_back(std::move(val)); while (check(TokenType::COMMA)) { lexer_.advance(); e->array_values.push_back(parse_expr()); } expect(TokenType::RBRACKET, "']'"); e->array_count = e->array_values.size(); return e; } if (check(TokenType::LPAREN)) { lexer_.advance(); auto e = parse_expr(); expect(TokenType::RPAREN, "')'"); return e; } error("expected expression"); auto e = std::make_unique<Expr>(); e->kind = Expr::IntLiteral; return e; } std::vector<std::unique_ptr<Expr>> Parser::parse_args() { std::vector<std::unique_ptr<Expr>> args; while (!check(TokenType::RPAREN) && !check(TokenType::EOF_)) { args.push_back(parse_expr()); if (check(TokenType::COMMA)) lexer_.advance(); } return args; }