feat: match 表达式 (P1 #8 收官)

- lexer: TOK_MATCH, TOK_MATCH_ARROW, TOK_UNDERSCORE
- parser: parse_match_stmt() desugar → let+if-else链
- 零 sema/codegen 改动
- 4个集成测试: enum/int literal/wildcard match

P1 全部完成: type alias + enum + array + impl + match
This commit is contained in:
2026-06-05 14:41:52 +08:00
parent 9f6e695ba8
commit a15cd9d56e
8 changed files with 143 additions and 6 deletions
+93
View File
@@ -356,6 +356,95 @@ static AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) {
farr, fcount, tok_loc(s_tok));
}
// === match 语句解析(脱糖为 let + if-else 链)===
// match <expr> { pat1 => { body1 }, pat2 => { body2 }, _ => { body_default } }
// → { let __match_val = <expr>; if __match_val == pat1 { body1 } else if __match_val == pat2 { body2 } else { body_default } }
static AstNode* parse_match_stmt(Parser* p, ErrorInfo* error) {
const Token* match_tok = advance(p); // 跳过 'match'
// 解析被匹配的表达式
AstNode* matched = parse_expr(p, error);
if (!matched) return NULL;
if (!expect(p, TOK_LBRACE, error, "match 后缺少 '{'")) return NULL;
// 分配临时变量名
const char* varname = arena_strdup_impl(p->arena, "__match_val", 12);
// 收集所有分支
enum { MAX_ARMS = 64 };
bool arm_is_wildcard[MAX_ARMS];
AstNode* arm_pattern[MAX_ARMS];
AstNode* arm_body[MAX_ARMS];
int arm_count = 0;
while (peek(p)->kind != TOK_RBRACE && !error->message) {
if (arm_count >= MAX_ARMS) {
error->message = "match 分支过多 (最多64)";
error->filename = p->filename;
error->line = peek(p)->line; error->col = peek(p)->col;
return NULL;
}
if (peek(p)->kind == TOK_UNDERSCORE) {
arm_is_wildcard[arm_count] = true;
arm_pattern[arm_count] = NULL;
advance(p); // 跳过 '_'
} else {
arm_is_wildcard[arm_count] = false;
arm_pattern[arm_count] = parse_expr(p, error);
if (!arm_pattern[arm_count]) return NULL;
}
// 解析 '=>'
if (!expect(p, TOK_MATCH_ARROW, error, "match 分支缺少 '=>'")) return NULL;
// 解析分支体(必须是一个代码块)
arm_body[arm_count] = parse_block(p, error);
if (!arm_body[arm_count]) return NULL;
arm_count++;
// 跳过可选逗号
if (peek(p)->kind == TOK_COMMA) advance(p);
}
if (!expect(p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
if (arm_count == 0) {
error->message = "match 表达式至少需要一个分支";
error->filename = p->filename;
error->line = match_tok->line; error->col = match_tok->col;
return NULL;
}
// 从最后一个分支往前构建 if-else 链(最后一个分支 = 最内层 else)
AstNode* result = NULL;
for (int i = arm_count - 1; i >= 0; i--) {
if (arm_is_wildcard[i]) {
// 通配符分支:if (true) { body } else { result }
AstNode* true_cond = ast_make_literal_bool(p->arena, true, tok_loc(match_tok));
result = ast_make_if(p->arena, true_cond, arm_body[i], result, tok_loc(match_tok));
} else {
// if (__match_val == pattern) { body } else { result }
AstNode* cond = ast_make_binary(p->arena, OP_EQ,
ast_make_ident(p->arena, varname, tok_loc(match_tok)),
arm_pattern[i], tok_loc(match_tok));
result = ast_make_if(p->arena, cond, arm_body[i], result, tok_loc(match_tok));
}
}
// 构建 let __match_val = <matched>;
AstNode* let_stmt = ast_make_let(p->arena, varname, TYPE_UNKNOWN,
false, false, matched, NULL, 0, NULL, 0, tok_loc(match_tok));
// 包装为代码块: { let __match_val = <expr>; <if-else 链> }
AstNode* stmts_arr[2] = { let_stmt, result };
AstNode** stmts = arena_alloc_impl(p->arena, 2 * sizeof(AstNode*));
memcpy(stmts, stmts_arr, 2 * sizeof(AstNode*));
return ast_make_block(p->arena, stmts, 2, tok_loc(match_tok));
}
// === 语句解析 ===
static AstNode* parse_block(Parser* p, ErrorInfo* error) {
@@ -507,6 +596,10 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
return ast_make_block(p->arena, stmts, 2, tok_loc(t));
}
if (t->kind == TOK_MATCH) {
return parse_match_stmt(p, error);
}
if (t->kind == TOK_RETURN) {
advance(p);
if (match(p, TOK_SEMICOLON)) {