feat: if let 语句 — if let Option::Some = expr { ... }
This commit is contained in:
+55
-28
@@ -1,4 +1,5 @@
|
||||
#include "parser.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user