feat: if let 语句 — if let Option::Some = expr { ... }
This commit is contained in:
@@ -813,6 +813,15 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
|
|||||||
memcpy_args, 3, false);
|
memcpy_args, 3, false);
|
||||||
ctx.memcpy_fn = LLVMAddFunction(ctx.module, "memcpy", memcpy_ty);
|
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)
|
// 第零遍:先创建所有命名结构体(占位符,未设置 body)
|
||||||
for (size_t i = 0; i < ast->as.program.struct_count; i++) {
|
for (size_t i = 0; i < ast->as.program.struct_count; i++) {
|
||||||
AstNode* sd = ast->as.program.structs[i];
|
AstNode* sd = ast->as.program.structs[i];
|
||||||
|
|||||||
+44
-17
@@ -1,4 +1,5 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@@ -265,8 +266,44 @@ static AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error
|
|||||||
|
|
||||||
// 前缀解析
|
// 前缀解析
|
||||||
if (tok->kind == TOK_IF) {
|
if (tok->kind == TOK_IF) {
|
||||||
// if-expr: if cond { then } else { else } → AST_IF_STMT (表达式位置)
|
|
||||||
const Token* if_tok = advance(p);
|
const Token* if_tok = advance(p);
|
||||||
|
// 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);
|
AstNode* cond = parse_expr(p, error);
|
||||||
if (!cond) return NULL;
|
if (!cond) return NULL;
|
||||||
AstNode* then_block = parse_block(p, error);
|
AstNode* then_block = parse_block(p, error);
|
||||||
@@ -274,12 +311,13 @@ static AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error
|
|||||||
AstNode* else_block = NULL;
|
AstNode* else_block = NULL;
|
||||||
if (match(p, TOK_ELSE)) {
|
if (match(p, TOK_ELSE)) {
|
||||||
if (peek(p)->kind == TOK_IF)
|
if (peek(p)->kind == TOK_IF)
|
||||||
else_block = parse_expr_prec(p, min_prec, error); // else if
|
else_block = parse_expr_prec(p, min_prec, error);
|
||||||
else
|
else
|
||||||
else_block = parse_block(p, error);
|
else_block = parse_block(p, error);
|
||||||
if (!else_block) return NULL;
|
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) {
|
} else if (tok->kind == TOK_MINUS || tok->kind == TOK_BANG) {
|
||||||
left = parse_unary(p, error);
|
left = parse_unary(p, error);
|
||||||
} else if (tok->kind == TOK_LPAREN) {
|
} else if (tok->kind == TOK_LPAREN) {
|
||||||
@@ -632,21 +670,10 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (t->kind == TOK_IF) {
|
if (t->kind == TOK_IF) {
|
||||||
advance(p);
|
// 委托给表达式解析器(含 if let 去糖)
|
||||||
AstNode* cond = parse_expr(p, error);
|
AstNode* if_expr = parse_expr_prec(p, PREC_NONE, error);
|
||||||
if (!cond) return NULL;
|
if (!if_expr) return NULL;
|
||||||
AstNode* then_block = parse_block(p, error);
|
return if_expr; // AST_IF_STMT 或 AST_BLOCK(if-let去糖)
|
||||||
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 (t->kind == TOK_WHILE) {
|
if (t->kind == TOK_WHILE) {
|
||||||
|
|||||||
+10
-9
@@ -364,11 +364,6 @@ static void analyze_enum_variant(AstNode* node, Scope* scope, ErrorList* errors,
|
|||||||
"枚举变体 payload 类型不匹配: 期望 '%s',得到 '%s'",
|
"枚举变体 payload 类型不匹配: 期望 '%s',得到 '%s'",
|
||||||
type_name(expected_pt), type_name(actual));
|
type_name(expected_pt), type_name(actual));
|
||||||
}
|
}
|
||||||
} else if (expected_pt != TYPE_VOID) {
|
|
||||||
error_add(errors, "<sema>", 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;
|
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++) {
|
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
|
||||||
analyze_node(node->as.block.stmts[i], scope, errors, a);
|
analyze_node(node->as.block.stmts[i], scope, errors, a);
|
||||||
}
|
}
|
||||||
// 表达式作为值: 块类型 = 最后一条表达式语句的类型
|
// 表达式作为值: 块类型 = 最后一条产生值的语句类型
|
||||||
if (node->as.block.stmt_count > 0) {
|
if (node->as.block.stmt_count > 0) {
|
||||||
AstNode* last = node->as.block.stmts[node->as.block.stmt_count - 1];
|
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) {
|
if (last->kind == AST_EXPR_STMT) {
|
||||||
TypeKind ek = last->as.expr_stmt.expr->type.kind;
|
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) {
|
if (ek != TYPE_ERROR && ek != TYPE_VOID) {
|
||||||
node->type.kind = ek;
|
node->type.kind = ek;
|
||||||
node->type.struct_name = last->as.expr_stmt.expr->type.struct_name;
|
node->type.struct_name = esn;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user