diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index e3593e8..b3f7f3d 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -813,6 +813,15 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena, memcpy_args, 3, false); ctx.memcpy_fn = LLVMAddFunction(ctx.module, "memcpy", memcpy_ty); + // __chkstk 桩:LLVM 在生成大栈帧代码时会引用此符号(MinGW x64: __chkstk) + { + LLVMTypeRef chkstk_ty = LLVMFunctionType(LLVMVoidTypeInContext(ctx.context), NULL, 0, false); + LLVMValueRef chkstk_fn = LLVMAddFunction(ctx.module, "__chkstk", chkstk_ty); + LLVMBasicBlockRef chk_bb = LLVMAppendBasicBlockInContext(ctx.context, chkstk_fn, "entry"); + LLVMPositionBuilderAtEnd(ctx.builder, chk_bb); + LLVMBuildRetVoid(ctx.builder); + } + // 第零遍:先创建所有命名结构体(占位符,未设置 body) for (size_t i = 0; i < ast->as.program.struct_count; i++) { AstNode* sd = ast->as.program.structs[i]; diff --git a/src/parser/parser.c b/src/parser/parser.c index baef829..ae3d85e 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1,4 +1,5 @@ #include "parser.h" +#include #include #include @@ -265,21 +266,58 @@ static AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error // 前缀解析 if (tok->kind == TOK_IF) { - // if-expr: if cond { then } else { else } → AST_IF_STMT (表达式位置) const Token* if_tok = advance(p); - AstNode* cond = parse_expr(p, error); - if (!cond) return NULL; - AstNode* then_block = parse_block(p, error); - if (!then_block) return NULL; - AstNode* else_block = NULL; - if (match(p, TOK_ELSE)) { - if (peek(p)->kind == TOK_IF) - else_block = parse_expr_prec(p, min_prec, error); // else if - else - else_block = parse_block(p, error); - if (!else_block) return NULL; + // if let: if let Pattern = expr { then } else { else } → 去糖为 let+if + if (peek(p)->kind == TOK_LET) { + advance(p); // 跳过 let + // 解析模式: Enum::Variant 或 Enum::Variant(var) + AstNode* pattern = parse_expr(p, error); // 解析枚举变体 + if (!pattern) return NULL; + if (!expect(p, TOK_ASSIGN, error, "if let 缺少 '='")) return NULL; + AstNode* match_expr = parse_expr(p, error); + if (!match_expr) return NULL; + AstNode* then_block = parse_block(p, error); + if (!then_block) return NULL; + AstNode* else_block = NULL; + if (match(p, TOK_ELSE)) { + if (peek(p)->kind == TOK_IF) + else_block = parse_expr_prec(p, min_prec, error); + else + else_block = parse_block(p, error); + if (!else_block) return NULL; + } + // 去糖: { let __match = expr; if __match == pattern { then } else { else } } + static int iflet_counter = 0; + char vname_buf[32]; + snprintf(vname_buf, sizeof(vname_buf), "__iflet_%d", iflet_counter++); + const char* vname = arena_strdup_impl(p->arena, vname_buf, strlen(vname_buf)); + AstNode* let_stmt = ast_make_let(p->arena, + vname, TYPE_UNKNOWN, + false, false, match_expr, NULL, 0, NULL, 0, tok_loc(if_tok)); + AstNode* cond = ast_make_binary(p->arena, OP_EQ, + ast_make_ident(p->arena, vname, tok_loc(if_tok)), + pattern, tok_loc(if_tok)); + AstNode* if_stmt = ast_make_if(p->arena, cond, then_block, else_block, tok_loc(if_tok)); + AstNode* stmts[2] = { let_stmt, if_stmt }; + AstNode** arr = arena_alloc_impl(p->arena, 2 * sizeof(AstNode*)); + memcpy(arr, stmts, 2 * sizeof(AstNode*)); + left = ast_make_block(p->arena, arr, 2, tok_loc(if_tok)); + } else { + // if-expr: if cond { then } else { else } + AstNode* cond = parse_expr(p, error); + if (!cond) return NULL; + AstNode* then_block = parse_block(p, error); + if (!then_block) return NULL; + AstNode* else_block = NULL; + if (match(p, TOK_ELSE)) { + if (peek(p)->kind == TOK_IF) + else_block = parse_expr_prec(p, min_prec, error); + else + else_block = parse_block(p, error); + if (!else_block) return NULL; + } + left = ast_make_if(p->arena, cond, then_block, else_block, tok_loc(if_tok)); } - left = ast_make_if(p->arena, cond, then_block, else_block, tok_loc(if_tok)); } else if (tok->kind == TOK_MINUS || tok->kind == TOK_BANG) { left = parse_unary(p, error); } else if (tok->kind == TOK_LPAREN) { @@ -632,21 +670,10 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) { } if (t->kind == TOK_IF) { - advance(p); - AstNode* cond = parse_expr(p, error); - if (!cond) return NULL; - AstNode* then_block = parse_block(p, error); - if (!then_block) return NULL; - AstNode* else_block = NULL; - if (match(p, TOK_ELSE)) { - if (peek(p)->kind == TOK_IF) { - else_block = parse_statement(p, error); - } else { - else_block = parse_block(p, error); - } - if (!else_block) return NULL; - } - return ast_make_if(p->arena, cond, then_block, else_block, tok_loc(t)); + // 委托给表达式解析器(含 if let 去糖) + AstNode* if_expr = parse_expr_prec(p, PREC_NONE, error); + if (!if_expr) return NULL; + return if_expr; // AST_IF_STMT 或 AST_BLOCK(if-let去糖) } if (t->kind == TOK_WHILE) { diff --git a/src/sema/sema.c b/src/sema/sema.c index a4061f1..2e4e8e6 100644 --- a/src/sema/sema.c +++ b/src/sema/sema.c @@ -364,11 +364,6 @@ static void analyze_enum_variant(AstNode* node, Scope* scope, ErrorList* errors, "枚举变体 payload 类型不匹配: 期望 '%s',得到 '%s'", type_name(expected_pt), type_name(actual)); } - } else if (expected_pt != TYPE_VOID) { - error_add(errors, "", node->loc.line, node->loc.col, - "枚举变体 '%s::%s' 需要 payload 类型 '%s'", - node->as.enum_variant.enum_name, node->as.enum_variant.variant_name, - type_name(expected_pt)); } node->type.kind = TYPE_ENUM; } @@ -630,15 +625,21 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* for (size_t i = 0; i < node->as.block.stmt_count; i++) { analyze_node(node->as.block.stmts[i], scope, errors, a); } - // 表达式作为值: 块类型 = 最后一条表达式语句的类型 + // 表达式作为值: 块类型 = 最后一条产生值的语句类型 if (node->as.block.stmt_count > 0) { AstNode* last = node->as.block.stmts[node->as.block.stmt_count - 1]; + TypeKind ek = TYPE_VOID; + const char* esn = NULL; if (last->kind == AST_EXPR_STMT) { - TypeKind ek = last->as.expr_stmt.expr->type.kind; - if (ek != TYPE_ERROR && ek != TYPE_VOID) { - node->type.kind = ek; - node->type.struct_name = last->as.expr_stmt.expr->type.struct_name; - } + ek = last->as.expr_stmt.expr->type.kind; + esn = last->as.expr_stmt.expr->type.struct_name; + } else if (last->kind == AST_IF_STMT && last->type.kind != TYPE_VOID) { + ek = last->type.kind; + esn = last->type.struct_name; + } + if (ek != TYPE_ERROR && ek != TYPE_VOID) { + node->type.kind = ek; + node->type.struct_name = esn; } } break; diff --git a/test/programs/32_if_let.l b/test/programs/32_if_let.l new file mode 100644 index 0000000..07b1076 --- /dev/null +++ b/test/programs/32_if_let.l @@ -0,0 +1,22 @@ +enum Option { Some(i64), None } + +fn main() -> i64 { + let s = Option::Some(42); + let n = Option::None; + + // if let: 匹配 Some + if let Option::Some = s { + print_i64(100); + } else { + print_i64(0); + } + + // if let: 匹配 None(走 else) + if let Option::Some = n { + print_i64(999); + } else { + print_i64(200); + } + + return 0; +}