From 983746c797b61c9a68b5cfee17fd67d7a735f185 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Mon, 14 Sep 2026 19:35:58 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E6=94=AF=E6=8C=81label=20break,=20con?= =?UTF-8?q?tinue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stage1/spl_ast.c | 67 ++++++++++++++++++++++++--------- stage1/spl_ast2ir.c | 82 ++++++++++++++++++++++++++++++++-------- stage1/spl_ast2ir.h | 1 + stage1/spl_sema.c | 92 +++++++++++++++++++++++++++++++++++++++++++-- stage1/spl_sema.h | 1 + 5 files changed, 207 insertions(+), 36 deletions(-) diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index 948c77f..ca03b11 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -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"); diff --git a/stage1/spl_ast2ir.c b/stage1/spl_ast2ir.c index 39e96ab..b2e8427 100644 --- a/stage1/spl_ast2ir.c +++ b/stage1/spl_ast2ir.c @@ -912,21 +912,6 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { } 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: if (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}; ctx.cont_blk = head_blk; 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_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}; ctx.cont_blk = head_blk; 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_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); 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: emit_expr(a, ref); return; diff --git a/stage1/spl_ast2ir.h b/stage1/spl_ast2ir.h index 806b396..12a55a6 100644 --- a/stage1/spl_ast2ir.h +++ b/stage1/spl_ast2ir.h @@ -9,6 +9,7 @@ typedef MAP(spl_def_id_t, spl_ir_node_ref_t) spl_def2ir_map_t; typedef struct { usize cont_blk; usize brk_blk; + const char *label; spl_ir_node_ref_vec_t breaks; } spl_loop_ctx_t; typedef VEC(spl_loop_ctx_t) spl_loop_ctx_vec_t; diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index 34e87b6..1b43925 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -1400,20 +1400,48 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { return 0; } 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); sema_check(sema, n->while_expr.cond, bt); if (n->while_expr.body) sema_infer(sema, n->while_expr.body); if (n->while_expr.else_branch) sema_infer(sema, n->while_expr.else_branch); + + vec_pop(sema->label_stack); return 0; } 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) sema_infer(sema, n->loop_expr.body); + + vec_pop(sema->label_stack); return 0; } 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); 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)); @@ -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) sema_infer(sema, n->for_expr.else_branch); sema_pop_scope(sema); + + vec_pop(sema->label_stack); return 0; } 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; } - case SPL_AST_STATEMENT_BREAK: - case SPL_AST_STATEMENT_CONTINUE: + case SPL_AST_STATEMENT_BREAK: { + 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; + } + 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: if (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->root = (spl_symbol_t){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) { if (!sema->ast || !module_ref) diff --git a/stage1/spl_sema.h b/stage1/spl_sema.h index 5fa78cd..aa048ca 100644 --- a/stage1/spl_sema.h +++ b/stage1/spl_sema.h @@ -49,6 +49,7 @@ typedef struct { spl_attr_t *attr; spl_lang_type_id_t current_aggregate_lang; spl_lang_type_id_t current_fn_ret_tid; + spl_symbol_path_t label_stack; } spl_sema_t; void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope,