From 0b8f649818ee26dc41fe05851b89f7d1811f6777 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Fri, 25 Sep 2026 13:46:07 +0800 Subject: [PATCH] =?UTF-8?q?stage2=20=E4=BF=AE=E5=A4=8D=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E6=9C=AA=E5=AE=8C=E6=88=90=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20=E6=8F=90=E4=BE=9B=E9=94=99=E8=AF=AF=E5=A4=84?= =?UTF-8?q?=E7=90=86=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nob/nob_data.h | 12 +++---- stage0/spl_rt.h | 28 +++++++++++++--- stage0/spl_vm.c | 5 +-- stage2/ast.spl | 13 ++++++++ stage2/ast2ir.spl | 78 +++++++++++++++++++++++++++++++++++++++++++ stage2/ir.spl | 38 ++++++++++++++++++++- stage2/ir2c.spl | 58 +++++++++++++++++++++++++++++++- stage2/ir2vm.spl | 38 ++++++++++++++++++++- stage2/ir_builder.spl | 6 ++++ stage2/mcode.spl | 20 +++++++++++ stage2/parser.spl | 39 +++++++++++++++++++++- 11 files changed, 317 insertions(+), 18 deletions(-) diff --git a/nob/nob_data.h b/nob/nob_data.h index bf46024..c5e80c2 100644 --- a/nob/nob_data.h +++ b/nob/nob_data.h @@ -96,15 +96,15 @@ static const char* splc1_deps[] = { static const char* splc2_deps[] = { /* stage3 */ - "stage3/ast2ir.spl", - "stage3/ast_clone.spl", - "stage3/ctvm.spl", - "stage3/eval.spl", - "stage3/intrin.spl", + "stage3/builtin.spl", + "stage3/hir.spl", + "stage3/hir2ir.spl", "stage3/lang_type.spl", + "stage3/lower.spl", + "stage3/scope.spl", "stage3/sema.spl", "stage3/splc2.spl", - "stage3/splrt.spl", + "stage3/tag.spl", /* stage2 */ "stage2/sys/exit.spl", "stage2/sys/file.spl", diff --git a/stage0/spl_rt.h b/stage0/spl_rt.h index 419329d..3ce5e34 100644 --- a/stage0/spl_rt.h +++ b/stage0/spl_rt.h @@ -87,12 +87,32 @@ SPL_FN u64 vm_timestamp(u64 kind) { #define SPL_VM_EMBED_IMPLIMENTATION #include "spl_vm_embed.h" -/* 配置层外部函数处理器(native 端)。VM 模式的实现见 spl_syscall.c。 - * native 的 foreign 分发尚未接入(后续),这里先提供可链接入口。 */ -SPL_FN void vm_set_foreign(void *vm, unsigned long long handler, void *ctx) { +/* 配置层外部函数处理器(native 端):把 nested VM 未解析的 native 按名分发到 + * 编译器生成的 `ct_*` 函数(表由 ir2c 生成,见 stage2/ir2c.spl)。 */ +extern void *spl_ct_lookup(const char *name); + +typedef spl_vm_val_t (*spl_native_ct_fn_t)(void *, spl_vm_val_t, spl_vm_val_t, spl_vm_val_t); + +SPL_FN spl_vm_val_t spl_native_foreign(spl_vm_t *vm, const spl_vm_call_t *call, void *user) { + void *fn; + spl_vm_val_t a0 = 0, a1 = 0; (void)vm; + if (!call) + return 0; + fn = spl_ct_lookup(call->name); + if (!fn) + return 0; + if (call->nargs > 0) + a0 = call->args[0]; + if (call->nargs > 1) + a1 = call->args[1]; + /* ct_* 统一形状:返回 u64,参数 (ctx, u64, u64);多余参数被忽略。 */ + return ((spl_native_ct_fn_t)fn)(user, a0, a1, 0); +} + +SPL_FN void vm_set_foreign(void *p, unsigned long long handler, void *ctx) { (void)handler; - (void)ctx; + spl_vm_set_foreign((spl_vm_t *)p, spl_native_foreign, ctx); } #endif /* __SPL_RT_H__ */ diff --git a/stage0/spl_vm.c b/stage0/spl_vm.c index 7b83848..204e8bb 100644 --- a/stage0/spl_vm.c +++ b/stage0/spl_vm.c @@ -1674,11 +1674,8 @@ L_SPL_STORE: spl_vm_val_t _v = POP(); spl_vm_val_t _off = POP(); void *_addr = spl_vm_xlate(vm, _off, spl_type_size(ins->type)); - if (!_addr) { - fprintf(stderr, "vm: STORE bad off=%zu sz=%d\n", (size_t)_off, (int)spl_type_size(ins->type)); - spl_vm_backtrace(vm, vm->fp); + if (!_addr) VM_ERROR("STORE: invalid address"); - } memcpy(_addr, &_v, spl_type_size(ins->type)); DISPATCH(); } diff --git a/stage2/ast.spl b/stage2/ast.spl index 606cc0d..533108b 100644 --- a/stage2/ast.spl +++ b/stage2/ast.spl @@ -50,6 +50,7 @@ type Body = enum { StatementBreak: struct { label: usize, expr: usize }, StatementContinue: struct { label: usize }, StatementDefer: struct { body: usize }, + StatementErrdefer: struct { body: usize }, // errdefer:仅错误退出时执行 StatementComptime: struct { body: usize }, StatementDecl: struct { decl: usize }, StatementExpr: struct { expr: usize }, @@ -87,6 +88,8 @@ type Body = enum { }, ExprAggregateLit: struct { name: ByteView, fields: Vec }, ExprComptimeCall: struct { name: ByteView, args: Vec }, + ExprTry: struct { value: usize }, // `try expr` + ExprCatch: struct { value: usize, pattern: usize, handler: usize }, // `expr catch { }` ExprBlock: struct { stmts: Vec, tail_expr: usize }, ExprIf: struct { cond: usize, then_block: usize, else_branch: usize }, ExprIfvar: struct { var_decl: usize, then_block: usize, else_branch: usize }, @@ -144,6 +147,7 @@ fn kind_name(body: Body): []u8 { .StatementBreak(_) => { ret "statement_break"; }, .StatementContinue(_) => { ret "statement_continue"; }, .StatementDefer(_) => { ret "statement_defer"; }, + .StatementErrdefer(_) => { ret "statement_errdefer"; }, .StatementComptime(_) => { ret "statement_comptime"; }, .ExprComptime(_) => { ret "expr_comptime"; }, .StatementDecl(_) => { ret "statement_decl"; }, @@ -171,6 +175,8 @@ fn kind_name(body: Body): []u8 { .ExprArrayLit(_) => { ret "array_literal"; }, .ExprAggregateLit(_) => { ret "aggregate_literal"; }, .ExprComptimeCall(_) => { ret "comptime_call"; }, + .ExprTry(_) => { ret "try_expr"; }, + .ExprCatch(_) => { ret "catch_expr"; }, .ExprComptimeInit(_) => { ret "comptime_init"; }, .ExprBlock(_) => { ret "block"; }, .ExprIf(_) => { ret "if_expr"; }, @@ -466,6 +472,7 @@ fn dump_node(ast: *Ast, buf: *ByteBuffer, stack: *Vec, ref: usize, last: bool): }, .StatementContinue(x) => { ok = dump_opt(ast, buf, stack, x.label, true); }, .StatementDefer(x) => { ok = dump_opt(ast, buf, stack, x.body, true); }, + .StatementErrdefer(x) => { ok = dump_opt(ast, buf, stack, x.body, true); }, .StatementComptime(x) => { ok = dump_opt(ast, buf, stack, x.body, true); }, .ExprComptime(x) => { ok = dump_opt(ast, buf, stack, x.body, true); }, .StatementDecl(d) => { ok = dump_opt(ast, buf, stack, d.decl, true); }, @@ -519,6 +526,12 @@ fn dump_node(ast: *Ast, buf: *ByteBuffer, stack: *Vec, ref: usize, last: bool): }, .ExprAggregateLit(a) => { ok = dump_list(ast, buf, stack, a.fields); }, .ExprComptimeCall(c) => { ok = dump_list(ast, buf, stack, c.args); }, + .ExprTry(t2) => { ok = dump_opt(ast, buf, stack, t2.value, true); }, + .ExprCatch(c2) => { + ok = dump_opt(ast, buf, stack, c2.value, false) && + dump_opt(ast, buf, stack, c2.pattern, false) && + dump_opt(ast, buf, stack, c2.handler, true); + }, .ExprComptimeInit(x) => { ok = dump_list(ast, buf, stack, x.fields); }, .ExprBlock(b) => { ok = dump_list(ast, buf, stack, b.stmts) && diff --git a/stage2/ast2ir.spl b/stage2/ast2ir.spl index ded4b03..a8ee609 100644 --- a/stage2/ast2ir.spl +++ b/stage2/ast2ir.spl @@ -44,6 +44,7 @@ sema: *Sema, ir: *IrBuilder, ast: *Ast, def2ir_map: Map, +glob_gidx: Map, // def_id -> gidx+1(全局变量) loop_stack: Vec, // LoopCtx defer_stack: Vec, // ast node ref cur_ret_lang: usize, @@ -105,6 +106,62 @@ fn ir_map_put(self: *Ast2Ir, def_id: usize, val: usize) { match Map.put(&self.def2ir_map, &def_id as *u8, &val as *u8) { .Ok => {}, .Err(e) => {} } } +fn glob_get(self: *Ast2Ir, def_id: usize, out: *usize): bool { + match Map.get(&self.glob_gidx, &def_id as *u8, out as *u8) { + .Found => { ret true; }, + .NotFound => { ret false; }, + } + ret false; +} + +fn glob_put(self: *Ast2Ir, def_id: usize, val: usize) { + match Map.put(&self.glob_gidx, &def_id as *u8, &val as *u8) { .Ok => {}, .Err(e) => {} } +} + +// 顶层 var/const → 模块全局(alloc 于静态存储;引用是 *T 指针常量)。 +fn emit_global_var(self: *Ast2Ir, d: *Node) { + if d == null || d.resolved_def_id == 0 { ret; } + var def_id = d.resolved_def_id; + var existing: usize = 0; + if glob_get(self, def_id, &existing) { ret; } + var lang = LangType.def_lang_id(&self.sema.types, def_id); + var ir = to_ir_type(self, lang); + if ir == 0 { ret; } + var init_ref: usize = 0; + match d.body { + .VarDecl(x) => { init_ref = x.init_expr; }, + .ConstDecl(x) => { init_ref = x.init_expr; }, + _ => {}, + } + var zero = true; + var bytes = Vec.blank(1, 1); + if init_ref != 0 { + var inode = Ast.node(self.ast, init_ref); + if inode != null { + match inode.body { + .ExprIntLit(bi) => { + var v: u64 = 0; + match BigInt.to_u64(&v, bi.value) { .Ok => {}, .Err(e) => {} } + var bits = LangType.int_bits(&self.sema.types, ir); + var size = bits / 8; + if size != 0 { + zero = false; + var i: usize = 0; + while i < size { + var b = ((v >> (8 * i)) & 255) as u8; + match Vec.push(&bytes, &b as *u8) { .Ok => {}, .Err(e) => {} } + i = i + 1; + } + } + }, + _ => {}, + } + } + } + var gidx = IrBuilder.add_global(self.ir, ir, zero, bytes); + glob_put(self, def_id, gidx + 1); +} + fn kind_is(self: *Ast2Ir, lang_id: usize, want: LangKind): bool { var e = ltn(self, lang_id); if e == null { ret false; } @@ -608,6 +665,13 @@ fn emit_lvalue(self: *Ast2Ir, ref: usize): usize { .ExprIdent(x) => { var d = defn(self, n.resolved_def_id); if d != null && @enum2int(d.kind) == @enum2int(DefKind.Fn) { ret 0; } + var g: usize = 0; + if glob_get(self, n.resolved_def_id, &g) { + var lang = node_lang(n); + var ir = to_ir_type(self, lang); + var ptr_ir = TypeTable.make_ptr(&self.sema.types.ir, ir); + ret IrBuilder.type_const_global(self.ir, ptr_ir, g - 1); + } var slot: usize = 0; if !ir_map_get(self, n.resolved_def_id, &slot) { ret 0; } ret slot; @@ -935,6 +999,13 @@ fn emit_ident(self: *Ast2Ir, n: *Node): usize { if !ir_map_get(self, n.resolved_def_id, &fn_ref) { ret 0; } ret IrBuilder.type_const_fn(self.ir, node_ir(self, n), fn_ref); } + var g: usize = 0; + if glob_get(self, n.resolved_def_id, &g) { + var ir = node_ir(self, n); + var ptr_ir = TypeTable.make_ptr(&self.sema.types.ir, ir); + var ptr = IrBuilder.type_const_global(self.ir, ptr_ir, g - 1); + ret IrBuilder.mem_load(self.ir, ir, ptr); + } var slot: usize = 0; if !ir_map_get(self, n.resolved_def_id, &slot) { ret 0; } ret IrBuilder.mem_load(self.ir, node_ir(self, n), slot); @@ -1961,6 +2032,8 @@ fn emit_container_reserve(self: *Ast2Ir, ref: usize) { } }, .TopLevelBlock(x) => { emit_container_reserve(self, dref); }, + .VarDecl(_) => { emit_global_var(self, d); }, + .ConstDecl(_) => { emit_global_var(self, d); }, _ => {}, } } @@ -1997,6 +2070,8 @@ fn emit_container_body(self: *Ast2Ir, ref: usize) { } }, .TopLevelBlock(x) => { emit_container_body(self, dref); }, + .VarDecl(_) => {}, + .ConstDecl(_) => {}, _ => {}, } } @@ -2070,6 +2145,8 @@ fn new(builder: *IrBuilder, sema: *Sema, diag: *Diag): Ast2Ir { .ast = sema.ast, .def2ir_map = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), hash_kind_usize()), + .glob_gidx = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), + hash_kind_usize()), .loop_stack = Vec.blank(@sizeof(LoopCtx), @alignof(LoopCtx)), .defer_stack = Vec.blank(@sizeof(usize), @alignof(usize)), .cur_ret_lang = 0, @@ -2089,6 +2166,7 @@ fn drop(self: *Ast2Ir) { Vec.drop(&self.loop_stack); Vec.drop(&self.defer_stack); Map.drop(&self.def2ir_map); + Map.drop(&self.glob_gidx); var k: usize = 0; while k < self.owned.len { match Vec.get(&self.owned, k) { diff --git a/stage2/ir.spl b/stage2/ir.spl index 29f4b8a..aea4288 100644 --- a/stage2/ir.spl +++ b/stage2/ir.spl @@ -82,6 +82,14 @@ type ConstLit = enum { Float: f64, Char: u8, Fn: usize, + Global: usize, // 全局变量下标(Ir.globals);值 = 指向该全局的 *T +} + +// 模块级全局变量:编译期分配的静态存储,引用时是一个 *T 指针常量(同 LLVM GlobalVariable)。 +type Global = struct { + tid: usize, + zero: bool, // true = 零初始化(BSS,不携带字节) + data: Vec, // u8 初始字节(zero=false 时使用) } type IrBody = enum { @@ -128,6 +136,7 @@ type IrFunc = struct { type Ir = @self; funcs: Vec, // IrFunc +globals: Vec, // Global // ---- 生命周期 ---- @@ -141,7 +150,8 @@ fn new_entry(): IrEntry { } fn new(): Ir { - var ir = Ir { .funcs = Vec.blank(@sizeof(IrFunc), @alignof(IrFunc)) }; + var ir = Ir { .funcs = Vec.blank(@sizeof(IrFunc), @alignof(IrFunc)), + .globals = Vec.blank(@sizeof(Global), @alignof(Global)) }; var sentinel = IrFunc { .name = ByteView.empty(), .attrs = Vec.blank(@sizeof(usize), @alignof(usize)), @@ -180,6 +190,25 @@ fn drop(self: *Ir) { i = i + 1; } Vec.drop(&self.funcs); + var g: usize = 0; + while g < self.globals.len { + var ge = (self.globals.data as *Global) + g; + Vec.drop(&ge.data); + g = g + 1; + } + Vec.drop(&self.globals); +} + +// 追加一个全局变量;返回其下标(gidx)。bytes 的所有权转移进表。 +fn add_global(self: *Ir, tid: usize, zero: bool, bytes: Vec): usize { + var g = Global { .tid = tid, .zero = zero, .data = bytes }; + match Vec.push(&self.globals, &g as *u8) { .Ok => {}, .Err(error) => { ret 0; } } + ret self.globals.len - 1; +} + +fn global_at(self: *Ir, gidx: usize): *Global { + if gidx >= self.globals.len { ret null; } + ret (self.globals.data as *Global) + gidx; } fn alloc_fn(self: *Ir): usize { @@ -394,6 +423,13 @@ fn dump_body(out: *ByteBuffer, ty: *TypeTable, e: *IrEntry): bool { }, .Const(c) => { if !dump_type(out, ty, c.tid) { ret false; } + match c.lit { + .Global(g) => { + if !out_str(out, " global#") { ret false; } + ret out_u(out, g); + }, + _ => {}, + } var te = TypeTable.node(ty, c.tid); var is_float = false; var is_fn = false; diff --git a/stage2/ir2c.spl b/stage2/ir2c.spl index f947cd9..269b682 100644 --- a/stage2/ir2c.spl +++ b/stage2/ir2c.spl @@ -18,7 +18,7 @@ type .{ .Layout } = @import("./layout.spl"); type AttrM = @import("./attr.spl"); type .{ .Attr } = @import("./attr.spl"); type IrM = @import("./ir.spl"); -type .{ .Ir, .IrFunc, .IrEntry } = @import("./ir.spl"); +type .{ .Ir, .IrFunc, .IrEntry, .Global } = @import("./ir.spl"); type Ir2C = @self; @@ -570,6 +570,7 @@ fn emit_const(self: *Ir2C, ref: usize, n: *IrEntry) { } }, .Ptr(v) => { put(self, "(void*)"); put_u(self, v); }, + .Global(g) => { put(self, "(void*)spl_g_"); put_u(self, g); }, .Float(v) => { put(self, "0.0"); }, .Fn(fid) => { put(self, "(void*)&"); c_fn_name(self, fid); }, } @@ -1240,6 +1241,32 @@ fn find_main(self: *Ir2C): usize { fn run(self: *Ir2C) { put(self, "#include \"spl_rt.h\"\n"); + // 模块级全局变量(Zero → BSS:无初始化式)。 + var gi: usize = 0; + while gi < self.ir.globals.len { + var g = (self.ir.globals.data as *Global) + gi; + var sz = type_size(self, g.tid); + if sz == 0 { sz = 1; } + put(self, "static unsigned char spl_g_"); + put_u(self, gi); + put(self, "["); + put_u(self, sz); + put(self, "]"); + if !g.zero { + put(self, " = {"); + var k: usize = 0; + while k < g.data.len { + if k > 0 { put(self, ", "); } + put_u(self, ((g.data.data as *u8) + k).* as usize); + k = k + 1; + } + if g.data.len == 0 { put(self, "0"); } + put(self, "}"); + } + put(self, ";\n"); + gi = gi + 1; + } + var i: usize = 1; while i < self.ir.funcs.len { var f = IrM.func(self.ir, i); @@ -1256,6 +1283,7 @@ fn run(self: *Ir2C) { } i = i + 1; } + emit_ct_table(self); var m = find_main(self); if m != 0 { var f = IrM.func(self.ir, m); @@ -1283,6 +1311,34 @@ fn run(self: *Ir2C) { } } +// compiler function(`ct_` 前缀)回调表:供 native 端 vm_set_foreign 按名分发。 +fn emit_ct_table(self: *Ir2C) { + put(self, "static const struct { const char *name; void *fn; } spl_ct_tab[] = {\n"); + var n: usize = 0; + var i: usize = 1; + while i < self.ir.funcs.len { + var f = IrM.func(self.ir, i); + if f != null && !fn_is_extern(self, f) && + ByteView.starts_with(f.name, ByteView.from_slice("ct_")) { + put(self, " {\""); + put_bv(self, f.name); + put(self, "\", (void*)f"); + put_u(self, i); + put(self, "},\n"); + n = n + 1; + } + i = i + 1; + } + if n == 0 { put(self, " {0, 0},\n"); } + put(self, "};\n"); + put(self, "void *spl_ct_lookup(const char *name) {\n"); + put(self, " unsigned long i;\n"); + put(self, " for (i = 0; i < sizeof(spl_ct_tab)/sizeof(spl_ct_tab[0]); i++)\n"); + put(self, " if (spl_ct_tab[i].name && strcmp(spl_ct_tab[i].name, name) == 0) return spl_ct_tab[i].fn;\n"); + put(self, " return 0;\n"); + put(self, "}\n"); +} + fn new(ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr, out: *ByteBuffer): Ir2C { ret Ir2C { .ir = ir, diff --git a/stage2/ir2vm.spl b/stage2/ir2vm.spl index 992e675..5cbc33c 100644 --- a/stage2/ir2vm.spl +++ b/stage2/ir2vm.spl @@ -16,7 +16,7 @@ type .{ .Layout } = @import("./layout.spl"); type AttrM = @import("./attr.spl"); type .{ .Attr, .AttrArg } = @import("./attr.spl"); type IrM = @import("./ir.spl"); -type .{ .Ir, .IrFunc, .IrEntry } = @import("./ir.spl"); +type .{ .Ir, .IrFunc, .IrEntry, .Global } = @import("./ir.spl"); type Mcode = @import("./mcode.spl"); type .{ .Prog, .Op, .VmKind, .VmIns, .VmFunc } = @import("./mcode.spl"); type Mem = @import("sys/mem.spl"); @@ -28,6 +28,7 @@ ty: *TypeTable, attr: *Attr, layout: *Layout, extern_native: Vec, // isize +global_gaddr: Vec, // usize:每个全局变量在 prog.gdata 的下标 prog: Prog, // ---- 类型/布局查询 ---- @@ -589,6 +590,23 @@ fn cg_const(cg: *Cgen, ref: usize, n: *IrEntry) { var te = TypeTable.node(ctx.ty, tid); if te == null { ret; } + // 全局变量引用:Const{ lit = Global(gidx) } → GADDR(该全局的运行时地址)。 + match n.body { + .Const(c) => { + match c.lit { + .Global(g) => { + var di: usize = 0; + if g < ctx.global_gaddr.len { di = (ctx.global_gaddr.data as *usize)[g]; } + emit(cg, .Gaddr, .Void, di); + cg_store_slot(cg, ref, .Ptr); + ret; + }, + _ => {}, + } + }, + _ => {}, + } + match te.node { .Fn(f) => { var cref = const_fn(n); @@ -1213,6 +1231,7 @@ fn init(ctx: *Ir2Vm, ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr) { ctx.attr = attr; ctx.layout = layout; ctx.extern_native = Vec.blank(@sizeof(isize), @alignof(isize)); + ctx.global_gaddr = Vec.blank(@sizeof(usize), @alignof(usize)); match Mcode.new() { .Ok(v) => { ctx.prog = v; }, @@ -1223,6 +1242,7 @@ fn init(ctx: *Ir2Vm, ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr) { fn drop(ctx: *Ir2Vm) { Mcode.drop(&ctx.prog); Vec.drop(&ctx.extern_native); + Vec.drop(&ctx.global_gaddr); } fn run_func(ctx: *Ir2Vm, ref: usize): i32 { @@ -1253,6 +1273,22 @@ fn run(ctx: *Ir2Vm): i32 { i = i + 1; } + // 登记全局变量到 prog.gdata(Zero→零填/BSS,Bytes→拷贝),记下运行时下标。 + var gi: usize = 0; + while gi < ctx.ir.globals.len { + var g = (ctx.ir.globals.data as *Global) + gi; + var gsize = ir_type_size(ctx, g.tid); + var didx: usize = 0; + if g.zero { + didx = Mcode.add_zero_data(&ctx.prog, gsize); + } else { + didx = Mcode.add_data(&ctx.prog, g.data.data as usize, gsize); + } + var dv = didx; + match Vec.push(&ctx.global_gaddr, &dv as *u8) { .Ok => {}, .Err(error) => {} } + gi = gi + 1; + } + // 哨兵:保证真实函数入口地址非零。 ignore_usize(Mcode.add_instr(&ctx.prog, .Halt, .Void, 0)); diff --git a/stage2/ir_builder.spl b/stage2/ir_builder.spl index a8b282a..f919eca 100644 --- a/stage2/ir_builder.spl +++ b/stage2/ir_builder.spl @@ -285,6 +285,12 @@ fn type_const_float(self: *IrBuilder, tid: usize, val: f64): usize { ret const_n fn type_const_char(self: *IrBuilder, tid: usize, val: u8): usize { ret const_node(self, tid, .Char(val)); } fn type_const_fn(self: *IrBuilder, tid: usize, val: usize): usize { ret const_node(self, tid, .Fn(val)); } fn type_const_bytes(self: *IrBuilder, tid: usize, data: usize): usize { ret const_node(self, tid, .Ptr(data)); } +fn type_const_global(self: *IrBuilder, tid: usize, gidx: usize): usize { ret const_node(self, tid, .Global(gidx)); } + +// 追加模块级全局变量;返回 gidx。bytes 所有权转移进 Ir。 +fn add_global(self: *IrBuilder, tid: usize, zero: bool, bytes: Vec): usize { + ret Ir.add_global(&self.ir, tid, zero, bytes); +} // ---- type ops ---- diff --git a/stage2/mcode.spl b/stage2/mcode.spl index 372ae8e..b25b75b 100644 --- a/stage2/mcode.spl +++ b/stage2/mcode.spl @@ -314,6 +314,26 @@ fn add_data(self: *Prog, ptr: usize, size: usize): usize { ret self.gdata.len - 1; } +// 追加一条 size 字节的零初始化全局数据(BSS 语义);返回其索引。 +fn add_zero_data(self: *Prog, size: usize): usize { + var entry = ByteBuffer.new(); + match ByteBuffer.reserve(&entry, size) { + .Ok => {}, + .Err(error) => { ByteBuffer.drop(&entry); ret 0; }, + } + if size != 0 { + entry.storage.len = size; + var p = entry.storage.data as *u8; + var i: usize = 0; + while i < size { p[i] = 0; i = i + 1; } + } + match Vec.push(&self.gdata, &entry as *u8) { + .Ok => {}, + .Err(error) => { ByteBuffer.drop(&entry); ret 0; }, + } + ret self.gdata.len - 1; +} + // 返回 name 对应的 native 索引;不存在则登记。name 为空指针时返回 -1。 fn get_or_add_native(self: *Prog, name: ByteView): isize { if name.ptr == null { ret -1; } diff --git a/stage2/parser.spl b/stage2/parser.spl index 8fa6508..88c25bd 100644 --- a/stage2/parser.spl +++ b/stage2/parser.spl @@ -282,6 +282,7 @@ fn can_start_expr(kind: TokenKind): bool { .For => { ret true; }, .Match => { ret true; }, .Comptime => { ret true; }, + .Try => { ret true; }, _ => { ret false; }, } }, @@ -321,6 +322,7 @@ fn can_start_statement(kind: TokenKind): bool { .Break => { ret true; }, .Continue => { ret true; }, .Defer => { ret true; }, + .Errdefer => { ret true; }, .Var => { ret true; }, .Const => { ret true; }, .Type => { ret true; }, @@ -1237,7 +1239,19 @@ fn parse_expr_prec(self: *Parser, min_prec: i32): usize { } fn parse_expr(self: *Parser): usize { - ret parse_expr_prec(self, 1); + var e = parse_expr_prec(self, 1); + // `expr catch `:catch 用解包语法绑定错误。 + while !self.failed { + var t = peek(self); + if t == null { break; } + if !kind_is_keyword(t.kind, .Catch) { break; } + advance(self); + var pat = parse_pattern(self); + if pat == 0 { ret e; } + var handler = parse_block(self); + e = new_node(self, .ExprCatch(.{ .value = e, .pattern = pat, .handler = handler }), t); + } + ret e; } fn parse_cast(self: *Parser): usize { @@ -1444,6 +1458,12 @@ fn parse_primary(self: *Parser): usize { if @enum2int(k) == @enum2int(Keyword.Loop) { ret parse_loop_expr(self); } if @enum2int(k) == @enum2int(Keyword.For) { ret parse_for_expr(self); } if @enum2int(k) == @enum2int(Keyword.Match) { ret parse_match_expr(self); } + // `try `:错误上抛前缀。 + if @enum2int(k) == @enum2int(Keyword.Try) { + advance(self); + var tv = parse_expr(self); + ret new_node(self, .ExprTry(.{ .value = tv }), t); + } // `comptime `:编译期表达式(可调用普通函数、返回类型等)。 if @enum2int(k) == @enum2int(Keyword.Comptime) { advance(self); @@ -1958,6 +1978,22 @@ fn parse_defer_stmt(self: *Parser): usize { ret new_node(self, .StatementDefer(.{ .body = body }), kw); } +fn parse_errdefer_stmt(self: *Parser): usize { + var kw = peek(self); + if kw == null || !kind_is_keyword(kw.kind, .Errdefer) { ret 0; } + advance(self); + var body: usize = 0; + var t = peek(self); + if t != null && kind_is_punct(t.kind, .LBrace) { body = parse_block(self); } + else if t != null && can_start_statement(t.kind) { body = parse_statement(self); } + else { + body = parse_expr(self); + t = peek(self); + if t != null && kind_is_punct(t.kind, .Semicolon) { advance(self); } + } + ret new_node(self, .StatementErrdefer(.{ .body = body }), kw); +} + fn parse_comptime_stmt(self: *Parser): usize { var kw = peek(self); if kw == null || !kind_is_keyword(kw.kind, .Comptime) { ret 0; } @@ -1979,6 +2015,7 @@ fn parse_statement(self: *Parser): usize { if @enum2int(k) == @enum2int(Keyword.Break) { ret parse_break_stmt(self); } if @enum2int(k) == @enum2int(Keyword.Continue) { ret parse_continue_stmt(self); } if @enum2int(k) == @enum2int(Keyword.Defer) { ret parse_defer_stmt(self); } + if @enum2int(k) == @enum2int(Keyword.Errdefer) { ret parse_errdefer_stmt(self); } if @enum2int(k) == @enum2int(Keyword.Comptime) { ret parse_comptime_stmt(self); } if @enum2int(k) == @enum2int(Keyword.Var) || @enum2int(k) == @enum2int(Keyword.Const) ||