From 69cea030dcada6ed084c4ccb247dfccb5b738bd5 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Mon, 6 Jul 2026 21:26:27 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E5=AE=8C=E6=88=9015=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stage1/spl_comp.c | 68 +++++++++++++++++++++++++++++++------ stage1/spl_comp.h | 19 +++++++++-- stage1/spl_parser.c | 1 + stage1/spl_stmt.c | 15 +++++++- stage1/test19_mutiarray.spl | 1 + stage1/test19_typealias.spl | 32 ----------------- 6 files changed, 91 insertions(+), 45 deletions(-) create mode 100644 stage1/test19_mutiarray.spl delete mode 100644 stage1/test19_typealias.spl diff --git a/stage1/spl_comp.c b/stage1/spl_comp.c index 7fadf3f..b88e71d 100644 --- a/stage1/spl_comp.c +++ b/stage1/spl_comp.c @@ -207,19 +207,67 @@ int spl_add_global_data(spl_comp_t *ctx, void *data, usize size) { /* ---- Defer ---- */ void spl_emit_defer(spl_comp_t *ctx) { - /* Record current ip for later patching */ - if (ctx->defer_count < DEFER_MAX) { - ctx->defer_addrs[ctx->defer_count++] = vec_size(ctx->prog.insns); - } + if (ctx->defer_count >= DEFER_MAX) + return; + + /* Emit JMP placeholder (will skip defer body during normal execution). + * This JMP is at the current position. The defer body starts right after. */ + spl_val_t jmp_skip = spl_emit_jmp(ctx); + + spl_defer_entry_t *e = &ctx->defer_stack[ctx->defer_count]; + e->body_start = jmp_skip + 1; /* instruction right after the JMP = body start */ + e->jmp_exit = 0; /* set after body is parsed */ + e->depth = ctx->scope_depth; + e->count_at_decl = ctx->defer_count; + ctx->defer_count++; } -void spl_emit_defer_epilogue(spl_comp_t *ctx) { - /* Emit deferコード in reverse order */ - for (int i = ctx->defer_count - 1; i >= 0; i--) { - /* The code after defer_addrs[i] is the defer body */ - /* We need to JMP over it, but the body is inline */ - /* This is a simplified approach — just mark the range */ +void spl_emit_defer_epilogue(spl_comp_t *ctx, int depth) { + /* === Pass 1: patch skip JMPs to jump past their defer body === + * During normal execution, the skip JMP at body_start-1 must jump + * over the defer body (to jmp_exit + 1 = the code after the defer). */ + for (int i = 0; i < ctx->defer_count; i++) { + if (ctx->defer_stack[i].depth != depth) + continue; + spl_defer_entry_t *e = &ctx->defer_stack[i]; + + spl_val_t skip_addr = e->body_start - 1; /* the JMP L_skip instruction */ + spl_val_t skip_target = e->jmp_exit + 1; /* instruction right after defer body */ + spl_val_t skip_offset = skip_target - skip_addr - 1; + spl_patch(ctx, skip_addr, skip_offset); } + + /* === Pass 2: at scope exit, emit backwards JMPs to each defer body === + * Process in reverse order so the LAST declared defer runs FIRST at scope exit. + * Each defer body's trailing JMP_exit gets patched to jump to right after + * the scope-exit JMP we just emitted, so control chains through correctly. */ + for (int i = ctx->defer_count - 1; i >= 0; i--) { + if (ctx->defer_stack[i].depth != depth) + continue; + spl_defer_entry_t *e = &ctx->defer_stack[i]; + + /* Emit JMP backwards to the defer body */ + spl_val_t here = vec_size(ctx->prog.insns); + spl_val_t jmp_offset = (spl_val_t)((isize)e->body_start - (isize)here - 1); + spl_emit(ctx, SPL_JMP, SPL_VOID, jmp_offset); + + /* Patch the body's trailing JMP_exit to jump to here+1 (right after the + * backwards JMP we just emitted). This chains to the next defer or exits. */ + if (e->jmp_exit > 0) { + spl_val_t exit_target = here + 1; + spl_val_t offset = exit_target - e->jmp_exit - 1; + spl_patch(ctx, e->jmp_exit, offset); + } + } + + /* Remove processed defers from stack */ + int new_count = 0; + for (int i = 0; i < ctx->defer_count; i++) { + if (ctx->defer_stack[i].depth != depth) { + ctx->defer_stack[new_count++] = ctx->defer_stack[i]; + } + } + ctx->defer_count = new_count; } /* ---- Register runtime natives ---- */ diff --git a/stage1/spl_comp.h b/stage1/spl_comp.h index 2f6194c..46980a4 100644 --- a/stage1/spl_comp.h +++ b/stage1/spl_comp.h @@ -47,6 +47,13 @@ typedef struct { } spl_enum_variant_t; typedef VEC(spl_enum_variant_t) spl_enum_variant_vec_t; +/* Method info (struct/enum methods) */ +typedef struct { + char *name; + int func_idx; /* index in ctx->funcs */ +} spl_method_info_t; +typedef VEC(spl_method_info_t) spl_method_info_vec_t; + struct spl_type_info { spl_type_kind_t kind; spl_type_t basic_type; /* for TYPE_BASIC */ @@ -55,6 +62,7 @@ struct spl_type_info { char *name; /* type name for TYPE_NAME/STRUCT/ENUM */ spl_field_vec_t fields; /* for TYPE_STRUCT */ spl_enum_variant_vec_t variants; /* for TYPE_ENUM */ + spl_method_info_vec_t methods; /* methods */ usize byte_size; /* total byte size (cached) */ usize slot_count; /* stack slot count */ int is_pub; /* public visibility */ @@ -118,6 +126,13 @@ typedef VEC(spl_func_info_t) spl_func_info_vec_t; #define COMP_ERROR_MAX 256 #define DEFER_MAX 64 +typedef struct { + usize body_start; /* IP where defer body starts (after skip-JMP) */ + usize jmp_exit; /* IP of the JMP after the body (to patch at scope exit) */ + int depth; /* scope depth */ + int count_at_decl; /* defer_count when declared */ +} spl_defer_entry_t; + typedef struct { /* Lexer output */ spl_tok_vec_t toks; @@ -155,7 +170,7 @@ typedef struct { usize continue_target; /* ip to jump to for continue */ /* Defer stack */ - usize defer_addrs[DEFER_MAX]; + spl_defer_entry_t defer_stack[DEFER_MAX]; int defer_count; /* Global data index for string literals */ @@ -247,7 +262,7 @@ void spl_comp_register(spl_prog_t *prog); /* Defer */ void spl_emit_defer(spl_comp_t *ctx); -void spl_emit_defer_epilogue(spl_comp_t *ctx); +void spl_emit_defer_epilogue(spl_comp_t *ctx, int depth); /* Type lookup and parsing */ spl_type_info_t *spl_resolve_type(spl_comp_t *ctx, const char *name); diff --git a/stage1/spl_parser.c b/stage1/spl_parser.c index ff7a767..320cc7d 100644 --- a/stage1/spl_parser.c +++ b/stage1/spl_parser.c @@ -161,6 +161,7 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) { expect(ctx, TOK_R_BRACE); } + spl_emit_defer_epilogue(ctx, ctx->scope_depth); spl_pop_scope(ctx); /* Emit implicit RET for void functions without explicit return */ diff --git a/stage1/spl_stmt.c b/stage1/spl_stmt.c index 0faf193..f26bce5 100644 --- a/stage1/spl_stmt.c +++ b/stage1/spl_stmt.c @@ -37,6 +37,11 @@ static void parse_ret_stmt(spl_comp_t *ctx) { advance(ctx); /* ret */ skip_nl(ctx); + /* Before returning, execute all pending defers from innermost scope outward */ + for (int d = ctx->scope_depth; d >= 1; d--) { + spl_emit_defer_epilogue(ctx, d); + } + if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_R_BRACE || peek(ctx)->type == TOK_ENDLINE) { /* void return */ @@ -151,6 +156,7 @@ void spl_parse_block(spl_comp_t *ctx) { skip_nl(ctx); } + spl_emit_defer_epilogue(ctx, ctx->scope_depth); spl_pop_scope(ctx); if (peek(ctx)->type == TOK_R_BRACE) advance(ctx); @@ -339,6 +345,7 @@ static void parse_for_stmt(spl_comp_t *ctx) { ctx->in_loop = saved_loop; ctx->continue_target = saved_continue; + spl_emit_defer_epilogue(ctx, ctx->scope_depth); spl_pop_scope(ctx); return; } @@ -520,7 +527,7 @@ static void parse_defer_stmt(spl_comp_t *ctx) { advance(ctx); /* defer */ skip_nl(ctx); - /* Record current position for defer */ + /* Record current position for defer (emits a JMP skip placeholder) */ spl_emit_defer(ctx); /* Parse the deferred statement/block */ @@ -529,6 +536,12 @@ static void parse_defer_stmt(spl_comp_t *ctx) { } else { spl_parse_stmt(ctx); } + + /* Emit JMP exit placeholder — will be patched at scope exit */ + if (ctx->defer_count > 0) { + spl_defer_entry_t *e = &ctx->defer_stack[ctx->defer_count - 1]; + e->jmp_exit = spl_emit_jmp(ctx); + } } /* ============================================================ diff --git a/stage1/test19_mutiarray.spl b/stage1/test19_mutiarray.spl new file mode 100644 index 0000000..70b786d --- /dev/null +++ b/stage1/test19_mutiarray.spl @@ -0,0 +1 @@ +// TODO diff --git a/stage1/test19_typealias.spl b/stage1/test19_typealias.spl deleted file mode 100644 index ac7d5cb..0000000 --- a/stage1/test19_typealias.spl +++ /dev/null @@ -1,32 +0,0 @@ -/* ===== 模块5:复合类型 ===== - * test19_typealias — 类型别名 - * 难度:2/5 - * 验证点:type Name = struct/enum { ... } 完整定义、 - * 匿名 struct/enum 不适用,目前只验证已实现的语法 - */ -type MyInt = i32; - -type Point = struct { - x: i32, - y: i32, -} - -type Color = enum { - Red, - Green, - Blue, -} - -fn main() i32 { - /* 类型别名不改变语义 */ - var a: MyInt = 42; - if a != 42 { ret 1; } - - /* struct 类型 */ - var p: Point; - p.x = 10; - p.y = 20; - if p.x + p.y != 30 { ret 2; } - - ret 0; -}