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_IDENT:
case TOK_AT: case TOK_AT:
case TOK_SHARP: case TOK_SHARP:
case TOK_DOLLAR:
case TOK_L_PAREN: case TOK_L_PAREN:
case TOK_L_BRACKET: case TOK_L_BRACKET:
case TOK_L_BRACE: case TOK_L_BRACE:
@@ -1261,6 +1262,40 @@ static spl_ast_node_ref_t parse_prefix(parser_t *p) {
if (!t) if (!t)
return 0; 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; spl_unary_op_t uop;
switch (t->type) { switch (t->type) {
case TOK_SUB: case TOK_SUB:
@@ -1738,8 +1773,6 @@ static spl_ast_node_ref_t parse_while_expr(parser_t *p) {
return 0; return 0;
advance(p); advance(p);
spl_ast_node_ref_t label = parse_label(p);
p->stop_agg++; p->stop_agg++;
spl_ast_node_ref_t cond = parse_expr(p); spl_ast_node_ref_t cond = parse_expr(p);
p->stop_agg--; 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); 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.cond = cond;
node_at(p->ast, ref)->while_expr.body = body; node_at(p->ast, ref)->while_expr.body = body;
node_at(p->ast, ref)->while_expr.else_branch = else_branch; 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; return 0;
advance(p); 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 body = parse_block(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_LOOP, kw); 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; node_at(p->ast, ref)->loop_expr.body = body;
return ref; return ref;
} }
@@ -1788,9 +1820,6 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) {
return 0; return 0;
advance(p); advance(p);
spl_ast_node_ref_t label = parse_label(p);
// 解析迭代表达式列表(用 stop_as 阻止 'as' 被误解析为类型转换)
p->stop_as = 1; p->stop_as = 1;
spl_ast_node_ref_vec_t iter_exprs; spl_ast_node_ref_vec_t iter_exprs;
vec_init(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; p->stop_as = 0;
// 必须有关键字 as
const spl_tok_t *t = peek(p); const spl_tok_t *t = peek(p);
if (!t || t->type != KW_AS) { if (!t || t->type != KW_AS) {
SPL_FATAL(t, "expected 'as' in for loop"); 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); advance(p);
// 解析绑定变量列表(允许 '_')
spl_ast_node_ref_vec_t idents; spl_ast_node_ref_vec_t idents;
vec_init(idents); vec_init(idents);
t = peek(p); t = peek(p);
@@ -1835,12 +1862,10 @@ static spl_ast_node_ref_t parse_for_expr(parser_t *p) {
vec_push(idents, id_node); vec_push(idents, id_node);
} }
// 循环体必须为块
spl_ast_node_ref_t body = parse_block(p); spl_ast_node_ref_t body = parse_block(p);
if (!body) if (!body)
return 0; return 0;
// 可选的 else 分支
spl_ast_node_ref_t else_branch = 0; spl_ast_node_ref_t else_branch = 0;
if (peek(p) && peek(p)->type == KW_ELSE) { if (peek(p) && peek(p)->type == KW_ELSE) {
advance(p); 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_ref_t ref = new_node(p, SPL_AST_EXPR_FOR, kw);
spl_ast_node_t *fe = node_at(p->ast, ref); 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.iter_exprs = iter_exprs;
fe->for_expr.idents = idents; fe->for_expr.idents = idents;
fe->for_expr.body = body; 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"); SPL_FATAL(t, "only one tail expression allowed");
} }
block->block.tail_expr = expr; 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 { } else {
SPL_FATAL(t, "expected ';' or '}' after expression"); spl_ast_node_kind_t k = node_at(p->ast, expr)->kind;
break; 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 { } else {
SPL_FATAL(t, "unrecognized token in block"); SPL_FATAL(t, "unrecognized token in block");
+67 -15
View File
@@ -912,21 +912,6 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
} }
return; return;
} }
case SPL_AST_STATEMENT_BREAK: {
if (vec_size(a->loop_stack) == 0)
return;
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
vec_push(vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).breaks, jmp);
return;
}
case SPL_AST_STATEMENT_CONTINUE: {
if (vec_size(a->loop_stack) == 0)
return;
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
usize cont = vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).cont_blk;
spl_ir_builder_control_jmp_fixup(a->ir, jmp, cont);
return;
}
case SPL_AST_STATEMENT_DEFER: case SPL_AST_STATEMENT_DEFER:
if (n->statement_defer.body) if (n->statement_defer.body)
vec_push(a->defer_stack, n->statement_defer.body); vec_push(a->defer_stack, n->statement_defer.body);
@@ -1041,6 +1026,12 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
spl_loop_ctx_t ctx = {0}; spl_loop_ctx_t ctx = {0};
ctx.cont_blk = head_blk; ctx.cont_blk = head_blk;
ctx.brk_blk = 0; ctx.brk_blk = 0;
ctx.label = NULL;
if (n->while_expr.label) {
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->while_expr.label);
if (ln && ln->kind == SPL_AST_LABEL)
ctx.label = ln->label.name;
}
vec_init(ctx.breaks); vec_init(ctx.breaks);
vec_push(a->loop_stack, ctx); vec_push(a->loop_stack, ctx);
@@ -1079,6 +1070,12 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
spl_loop_ctx_t ctx = {0}; spl_loop_ctx_t ctx = {0};
ctx.cont_blk = head_blk; ctx.cont_blk = head_blk;
ctx.brk_blk = 0; ctx.brk_blk = 0;
ctx.label = NULL;
if (n->loop_expr.label) {
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->loop_expr.label);
if (ln && ln->kind == SPL_AST_LABEL)
ctx.label = ln->label.name;
}
vec_init(ctx.breaks); vec_init(ctx.breaks);
vec_push(a->loop_stack, ctx); vec_push(a->loop_stack, ctx);
@@ -1103,6 +1100,61 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
vec_pop(a->loop_stack); vec_pop(a->loop_stack);
return; return;
} }
case SPL_AST_STATEMENT_BREAK: {
if (vec_size(a->loop_stack) == 0)
return;
const char *lbl = NULL;
if (n->statement_break.label) {
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->statement_break.label);
if (ln && ln->kind == SPL_AST_LABEL)
lbl = ln->label.name;
}
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
if (lbl) {
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
if (c->label && strcmp(c->label, lbl) == 0) {
vec_push(c->breaks, jmp);
return;
}
}
return;
}
vec_push(vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).breaks, jmp);
return;
}
case SPL_AST_STATEMENT_CONTINUE: {
if (vec_size(a->loop_stack) == 0)
return;
const char *lbl = NULL;
if (n->statement_continue.label) {
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->statement_continue.label);
if (ln && ln->kind == SPL_AST_LABEL)
lbl = ln->label.name;
}
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
if (lbl) {
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
if (c->label && strcmp(c->label, lbl) == 0) {
spl_ir_builder_control_jmp_fixup(a->ir, jmp, c->cont_blk);
return;
}
}
return;
}
usize cont = vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).cont_blk;
spl_ir_builder_control_jmp_fixup(a->ir, jmp, cont);
return;
}
case SPL_AST_EXPR_BLOCK: case SPL_AST_EXPR_BLOCK:
emit_expr(a, ref); emit_expr(a, ref);
return; return;
+1
View File
@@ -9,6 +9,7 @@ typedef MAP(spl_def_id_t, spl_ir_node_ref_t) spl_def2ir_map_t;
typedef struct { typedef struct {
usize cont_blk; usize cont_blk;
usize brk_blk; usize brk_blk;
const char *label;
spl_ir_node_ref_vec_t breaks; spl_ir_node_ref_vec_t breaks;
} spl_loop_ctx_t; } spl_loop_ctx_t;
typedef VEC(spl_loop_ctx_t) spl_loop_ctx_vec_t; typedef VEC(spl_loop_ctx_t) spl_loop_ctx_vec_t;
+89 -3
View File
@@ -1400,20 +1400,48 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
return 0; return 0;
} }
case SPL_AST_EXPR_WHILE: { case SPL_AST_EXPR_WHILE: {
const char *lbl = NULL;
if (n->while_expr.label) {
spl_ast_node_t *ln = spl_ast_node(sema->ast, n->while_expr.label);
if (ln && ln->kind == SPL_AST_LABEL)
lbl = ln->label.name;
}
vec_push(sema->label_stack, lbl);
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
sema_check(sema, n->while_expr.cond, bt); sema_check(sema, n->while_expr.cond, bt);
if (n->while_expr.body) if (n->while_expr.body)
sema_infer(sema, n->while_expr.body); sema_infer(sema, n->while_expr.body);
if (n->while_expr.else_branch) if (n->while_expr.else_branch)
sema_infer(sema, n->while_expr.else_branch); sema_infer(sema, n->while_expr.else_branch);
vec_pop(sema->label_stack);
return 0; return 0;
} }
case SPL_AST_EXPR_LOOP: { case SPL_AST_EXPR_LOOP: {
const char *lbl = NULL;
if (n->loop_expr.label) {
spl_ast_node_t *ln = spl_ast_node(sema->ast, n->loop_expr.label);
if (ln && ln->kind == SPL_AST_LABEL)
lbl = ln->label.name;
}
vec_push(sema->label_stack, lbl);
if (n->loop_expr.body) if (n->loop_expr.body)
sema_infer(sema, n->loop_expr.body); sema_infer(sema, n->loop_expr.body);
vec_pop(sema->label_stack);
return 0; return 0;
} }
case SPL_AST_EXPR_FOR: { case SPL_AST_EXPR_FOR: {
const char *lbl = NULL;
if (n->for_expr.label) {
spl_ast_node_t *ln = spl_ast_node(sema->ast, n->for_expr.label);
if (ln && ln->kind == SPL_AST_LABEL)
lbl = ln->label.name;
}
vec_push(sema->label_stack, lbl);
sema_push_scope(sema); sema_push_scope(sema);
for (usize i = 0; i < vec_size(n->for_expr.iter_exprs); ++i) { for (usize i = 0; i < vec_size(n->for_expr.iter_exprs); ++i) {
spl_lang_type_id_t container_tid = sema_infer(sema, vec_at(n->for_expr.iter_exprs, i)); spl_lang_type_id_t container_tid = sema_infer(sema, vec_at(n->for_expr.iter_exprs, i));
@@ -1439,6 +1467,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (n->for_expr.else_branch) if (n->for_expr.else_branch)
sema_infer(sema, n->for_expr.else_branch); sema_infer(sema, n->for_expr.else_branch);
sema_pop_scope(sema); sema_pop_scope(sema);
vec_pop(sema->label_stack);
return 0; return 0;
} }
case SPL_AST_EXPR_MATCH: { case SPL_AST_EXPR_MATCH: {
@@ -1711,9 +1741,64 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
} }
return 0; return 0;
} }
case SPL_AST_STATEMENT_BREAK: case SPL_AST_STATEMENT_BREAK: {
case SPL_AST_STATEMENT_CONTINUE: const char *lbl = NULL;
if (n->statement_break.label) {
spl_ast_node_t *ln = spl_ast_node(sema->ast, n->statement_break.label);
if (ln && ln->kind == SPL_AST_LABEL)
lbl = ln->label.name;
}
if (vec_size(sema->label_stack) == 0) {
SPL_ERROR(&n->dbg, "`break` outside of loop");
sema->error_count++;
return 0;
}
if (lbl) {
bool found = false;
for (usize i = vec_size(sema->label_stack); i > 0; --i) {
const char *cur = vec_at(sema->label_stack, i - 1);
if (cur && strcmp(cur, lbl) == 0) {
found = true;
break;
}
}
if (!found) {
SPL_ERROR(&n->dbg, "undefined label `$%s`", lbl);
sema->error_count++;
}
}
if (n->statement_break.expr)
sema_infer(sema, n->statement_break.expr);
return 0; return 0;
}
case SPL_AST_STATEMENT_CONTINUE: {
const char *lbl = NULL;
if (n->statement_continue.label) {
spl_ast_node_t *ln = spl_ast_node(sema->ast, n->statement_continue.label);
if (ln && ln->kind == SPL_AST_LABEL)
lbl = ln->label.name;
}
if (vec_size(sema->label_stack) == 0) {
SPL_ERROR(&n->dbg, "`continue` outside of loop");
sema->error_count++;
return 0;
}
if (lbl) {
bool found = false;
for (usize i = vec_size(sema->label_stack); i > 0; --i) {
const char *cur = vec_at(sema->label_stack, i - 1);
if (cur && strcmp(cur, lbl) == 0) {
found = true;
break;
}
}
if (!found) {
SPL_ERROR(&n->dbg, "undefined label `$%s`", lbl);
sema->error_count++;
}
}
return 0;
}
case SPL_AST_STATEMENT_DEFER: case SPL_AST_STATEMENT_DEFER:
if (n->statement_defer.body) if (n->statement_defer.body)
sema_infer(sema, n->statement_defer.body); sema_infer(sema, n->statement_defer.body);
@@ -1754,9 +1839,10 @@ void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope
sema->attr = attr; sema->attr = attr;
sema->root = (spl_symbol_t){0}; sema->root = (spl_symbol_t){0};
sema->store_scope = 0; sema->store_scope = 0;
vec_init(sema->label_stack);
} }
void spl_sema_drop(spl_sema_t *sema) { (void)sema; } void spl_sema_drop(spl_sema_t *sema) { vec_free(sema->label_stack); }
void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref) { void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref) {
if (!sema->ast || !module_ref) if (!sema->ast || !module_ref)
+1
View File
@@ -49,6 +49,7 @@ typedef struct {
spl_attr_t *attr; spl_attr_t *attr;
spl_lang_type_id_t current_aggregate_lang; spl_lang_type_id_t current_aggregate_lang;
spl_lang_type_id_t current_fn_ret_tid; spl_lang_type_id_t current_fn_ret_tid;
spl_symbol_path_t label_stack;
} spl_sema_t; } spl_sema_t;
void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope, void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope,