stage1 支持label break, continue

This commit is contained in:
zzy committed 2026-09-14 19:35:58 +08:00
1 parent 3175e04e6e
commit 983746c797
5 files changed
+207 -36

No files matched your search

+49 -18
View File
@@ -238,6 +238,7 @@ static int can_start_expr(spl_tok_type_t t) {
case TOK_IDENT:
case TOK_AT:
case TOK_SHARP:
case TOK_DOLLAR:
case TOK_L_PAREN:
case TOK_L_BRACKET:
case TOK_L_BRACE:
@@ -1261,6 +1262,40 @@ static spl_ast_node_ref_t parse_prefix(parser_t *p) {
if (!t)
return 0;
if (t->type == TOK_DOLLAR) {
spl_ast_node_ref_t label = parse_label(p);
const spl_tok_t *kw = peek(p);
spl_ast_node_ref_t ref = 0;
if (kw && kw->type == KW_WHILE)
ref = parse_while_expr(p);
else if (kw && kw->type == KW_LOOP)
ref = parse_loop_expr(p);
else if (kw && kw->type == KW_FOR)
ref = parse_for_expr(p);
else {
SPL_FATAL(kw, "expected while/loop/for after label");
return 0;
}
if (!ref)
return 0;
spl_ast_node_t *n = node_at(p->ast, ref);
switch (n->kind) {
case SPL_AST_EXPR_WHILE:
n->while_expr.label = label;
break;
case SPL_AST_EXPR_LOOP:
n->loop_expr.label = label;
break;
case SPL_AST_EXPR_FOR:
n->for_expr.label = label;
break;
default:
break;
}
return ref;
}
spl_unary_op_t uop;
switch (t->type) {
case TOK_SUB:
@@ -1738,8 +1773,6 @@ static spl_ast_node_ref_t parse_while_expr(parser_t *p) {
return 0;
advance(p);
spl_ast_node_ref_t label = parse_label(p);
p->stop_agg++;
spl_ast_node_ref_t cond = parse_expr(p);
p->stop_agg--;
@@ -1760,7 +1793,7 @@ static spl_ast_node_ref_t parse_while_expr(parser_t *p) {
}
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_WHILE, kw);
node_at(p->ast, ref)->while_expr.label = label;
node_at(p->ast, ref)->while_expr.label = 0;
node_at(p->ast, ref)->while_expr.cond = cond;
node_at(p->ast, ref)->while_expr.body = body;
node_at(p->ast, ref)->while_expr.else_branch = else_branch;
@@ -1773,11 +1806,10 @@ static spl_ast_node_ref_t parse_loop_expr(parser_t *p) {
return 0;
advance(p);
spl_ast_node_ref_t label = parse_label(p);
spl_ast_node_ref_t body = parse_block(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_LOOP, kw);
node_at(p->ast, ref)->loop_expr.label = label;
node_at(p->ast, ref)->loop_expr.label = 0;
node_at(p->ast, ref)->loop_expr.body = body;
return ref;
}
@@ -1788,9 +1820,6 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) {
return 0;
advance(p);
spl_ast_node_ref_t label = parse_label(p);
// 解析迭代表达式列表(用 stop_as 阻止 'as' 被误解析为类型转换)
p->stop_as = 1;
spl_ast_node_ref_vec_t iter_exprs;
vec_init(iter_exprs);
@@ -1801,7 +1830,6 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) {
}
p->stop_as = 0;
// 必须有关键字 as
const spl_tok_t *t = peek(p);
if (!t || t->type != KW_AS) {
SPL_FATAL(t, "expected 'as' in for loop");
@@ -1809,7 +1837,6 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) {
}
advance(p);
// 解析绑定变量列表(允许 '_')
spl_ast_node_ref_vec_t idents;
vec_init(idents);
t = peek(p);
@@ -1835,12 +1862,10 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) {
vec_push(idents, id_node);
}
// 循环体必须为块
spl_ast_node_ref_t body = parse_block(p);
if (!body)
return 0;
// 可选的 else 分支
spl_ast_node_ref_t else_branch = 0;
if (peek(p) && peek(p)->type == KW_ELSE) {
advance(p);
@@ -1852,7 +1877,7 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) {
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_FOR, kw);
spl_ast_node_t *fe = node_at(p->ast, ref);
fe->for_expr.label = label;
fe->for_expr.label = 0;
fe->for_expr.iter_exprs = iter_exprs;
fe->for_expr.idents = idents;
fe->for_expr.body = body;
@@ -2153,12 +2178,18 @@ static spl_ast_node_ref_t parse_block(parser_t *p) {
SPL_FATAL(t, "only one tail expression allowed");
}
block->block.tail_expr = expr;
} else if (expr && node_at(p->ast, expr)->kind == SPL_AST_EXPR_BLOCK) {
vec_push(block->block.stmts, expr);
// 继续循环,处理下一个语句
} else {
SPL_FATAL(t, "expected ';' or '}' after expression");
break;
spl_ast_node_kind_t k = node_at(p->ast, expr)->kind;
bool block_like =
(k == SPL_AST_EXPR_BLOCK || k == SPL_AST_EXPR_IF || k == SPL_AST_EXPR_IFVAR ||
k == SPL_AST_EXPR_WHILE || k == SPL_AST_EXPR_LOOP || k == SPL_AST_EXPR_FOR ||
k == SPL_AST_EXPR_MATCH);
if (block_like) {
vec_push(block->block.stmts, expr);
} else {
SPL_FATAL(t, "expected ';' or '}' after expression");
break;
}
}
} else {
SPL_FATAL(t, "unrecognized token in block");