diff --git a/stage1/spl_ir2vm.c b/stage1/spl_ir2vm.c index 42c0a96..b2bd984 100644 --- a/stage1/spl_ir2vm.c +++ b/stage1/spl_ir2vm.c @@ -1081,7 +1081,9 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { spl_type_id_t ret_t = n->control_call.tid; bool ret_is_sret = ir_is_aggregate(ctx, ret_t); usize sret_off = 0; - usize j = 0; + /* j = 本节点已压入 tracked 块之上的值的个数(用于栈化 PICK 距离)。 + 先压 2 个 ABI 空闲 slot,故从 2 起算。 */ + usize j = 2; /* ABI:实参下方预留 2 个空闲 slot(PAD0/PAD1)。 */ CG_PUSH(cg, SPL_U64, 0); @@ -1090,7 +1092,7 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { if (ret_is_sret) { sret_off = vec_at(cg->frame.slots, ref).data_off; CG_LADDR(cg, sret_off); - j = 1; + j = 3; } for (usize i = 0; i < nargs; ++i) { spl_ir_node_ref_t pref = vec_at(n->control_call.params, i); diff --git a/stage2/ast.spl b/stage2/ast.spl index 57057df..33e460d 100644 --- a/stage2/ast.spl +++ b/stage2/ast.spl @@ -1,9 +1,7 @@ // Expect retcode = 0 -// AST:用 ADT(enum 带载荷)表达节点,节点引用是 arena 序号 usize。 -// stage1 的 C 结构只是「手写 union 模拟 ADT」;这里直接用 SPL 的 enum 载荷, -// 不照抄 union 布局,只要求最终 dump / 语义与 stage1 一致。 -// 索引 0 为 NONE 哨兵(与 stage1 一致)。 +// AST:节点为带载荷 ADT,节点引用是 arena 序号(0 为 NONE 哨兵)。最终 dump/语义须与 +// splc0 一致。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -18,7 +16,6 @@ type .{ .Sources, .Source, .set_at } = @import("utils/source.spl"); // 算子不另立 enum:AST 直接存词法 Punct。一元/二元由节点 kind 区分 // (一元:Sub=负 / Not=! / BitNot=~ / And=& / Mul=.*;二元即对应 Punct)。 -// ---- 节点体(ADT;variant 名 = stage1 的 kind 名;载荷用内联匿名 struct)---- type Body = enum { None, @@ -302,11 +299,11 @@ fn alloc(self: *Ast, body: Body, span: Span): usize { } // 注册一段已解码的字符串字节(Ast 拥有;ByteView 指向其中,生命周期同 Ast)。 -// 空字符串也保证非空 data 指针(镜像 stage1:空字面量仍有稳定的非空字节地址)。 +// 空字符串也保证非空 data 指针(空字面量仍有稳定非空地址)。 fn push_string(self: *Ast, bytes: ByteBuffer): ByteView { var b = bytes; if b.storage.len == 0 { - match ByteBuffer.reserve(&b, 1) { .Ok => {}, .Err(error) => {} } + ByteBuffer.reserve(&b, 1); } @assert(b.storage.data != null, "ast string pool must be non-null"); // 直接构造,避免 from_slice 把空串规范成 null 视图。 @@ -329,7 +326,6 @@ fn ref_vec(): Vec { ret Vec.blank(@sizeof(usize), @alignof(usize)); } -// ---- dump(镜像 stage1 spl_ast_dump)---- // // AST: // `-/|-kind #ref [line:col] @@ -607,7 +603,6 @@ fn dump(ast: *Ast, out: *ByteBuffer): bool { ret dump_node(ast, out, &stack, ast.root, true); } -// ---- 测试 ---- fn test_kind_names() { @assert(ByteView.eq(ByteView.from_slice(kind_name(.None)), ByteView.from_slice("none")), diff --git a/stage2/ast2ir.spl b/stage2/ast2ir.spl index ac5c31c..0809963 100644 --- a/stage2/ast2ir.spl +++ b/stage2/ast2ir.spl @@ -1,8 +1,7 @@ // Expect retcode = 0 -// AST -> SIR(移植自 stage1/spl_ast2ir.c)。两遍:先 reserve 所有函数(拿稳定 -// func ref),再发射函数体。def2ir_map 记录 def -> IR 槽位(变量=内存指针, -// 函数=func ref)。loop_stack/defer_stack 驱动 break/continue/ret 的收尾。 +// AST -> IR。两遍:先 reserve 所有函数拿稳定 func ref,再发射函数体;def2ir_map +// 记录 def -> 槽位(变量=内存指针,函数=func ref)。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -52,7 +51,6 @@ cur_defer_base: usize, diag: *Diag, owned: Vec, // ByteBuffer:为 dbg.panic 消息提供稳定存储 -// ---- 小工具 ---- fn list_at(v: Vec, i: usize): usize { if i >= v.len { ret 0; } @@ -60,7 +58,7 @@ fn list_at(v: Vec, i: usize): usize { } fn push_u(v: *Vec, x: usize) { - match Vec.push(v, &x as *u8) { .Ok => {}, .Err(e) => {} } + Vec.push(v, &x as *u8); } fn irt(self: *Ast2Ir, id: usize): *TypeEntry { @@ -103,7 +101,7 @@ fn ir_map_get(self: *Ast2Ir, def_id: usize, out: *usize): bool { } 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) => {} } + Map.put(&self.def2ir_map, &def_id as *u8, &val as *u8); } fn glob_get(self: *Ast2Ir, def_id: usize, out: *usize): bool { @@ -115,7 +113,7 @@ fn glob_get(self: *Ast2Ir, def_id: usize, out: *usize): bool { } 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) => {} } + Map.put(&self.glob_gidx, &def_id as *u8, &val as *u8); } // 顶层 var/const → 模块全局(alloc 于静态存储;引用是 *T 指针常量)。 @@ -141,7 +139,7 @@ fn emit_global_var(self: *Ast2Ir, d: *Node) { match inode.body { .ExprIntLit(bi) => { var v: u64 = 0; - match BigInt.to_u64(&v, bi.value) { .Ok => {}, .Err(e) => {} } + BigInt.to_u64(&v, bi.value); var bits = LangType.int_bits(&self.sema.types, ir); var size = bits / 8; if size != 0 { @@ -149,7 +147,7 @@ fn emit_global_var(self: *Ast2Ir, d: *Node) { 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) => {} } + Vec.push(&bytes, &b as *u8); i = i + 1; } } @@ -184,7 +182,7 @@ fn int_lit_u64(n: *Node): u64 { match n.body { .ExprIntLit(&x) => { var out: u64 = 0; - match BigInt.to_u64(&out, x.value) { .Ok => {}, .Err(e) => {} } + BigInt.to_u64(&out, x.value); ret out; }, _ => {}, @@ -198,7 +196,6 @@ fn ir_kind_of(self: *Ast2Ir, ref: usize): IrKind { ret e.kind; } -// ---- 零值 ---- fn emit_zero_value(self: *Ast2Ir, tid: usize): usize { var tn = irt(self, tid); @@ -277,7 +274,6 @@ fn variant_at(v: Vec, idx: usize): usize { ret m.type_id; } -// ---- 模式绑定 ---- fn pattern_has_ref(self: *Ast2Ir, pat_ref: usize): bool { if pat_ref == 0 { ret false; } @@ -334,7 +330,7 @@ fn emit_pattern_bind(self: *Ast2Ir, pat_ref: usize, src_ptr: usize, tid: usize, if place_mode { var slot = IrBuilder.mem_alloca(self.ir, tid, const_usize(self, 1)); var v = IrBuilder.mem_load(self.ir, tid, src_ptr); - ignore_usize(IrBuilder.mem_store(self.ir, tid, slot, v)); + IrBuilder.mem_store(self.ir, tid, slot, v); ir_map_put(self, pat.resolved_def_id, slot); } else { ir_map_put(self, pat.resolved_def_id, src_ptr); @@ -348,7 +344,7 @@ fn emit_pattern_bind(self: *Ast2Ir, pat_ref: usize, src_ptr: usize, tid: usize, if in != null { ptr_tid = node_ir(self, in); } if ptr_tid == 0 { ptr_tid = TypeTable.make_ptr(&self.sema.types.ir, tid); } var slot = IrBuilder.mem_alloca(self.ir, ptr_tid, const_usize(self, 1)); - ignore_usize(IrBuilder.mem_store(self.ir, ptr_tid, slot, src_ptr)); + IrBuilder.mem_store(self.ir, ptr_tid, slot, src_ptr); emit_pattern_bind(self, x.pat, slot, ptr_tid, false); ret; }, @@ -539,7 +535,7 @@ fn copy_attrs_node(self: *Ast2Ir, n: *Node, ir_ref: usize) { var i: usize = 0; while i < n.attrs.len { var a = list_at(n.attrs, i); - match Vec.push(&irn.attrs, &a as *u8) { .Ok => {}, .Err(e) => {} } + Vec.push(&irn.attrs, &a as *u8); i = i + 1; } } @@ -551,12 +547,11 @@ fn copy_attrs_func(self: *Ast2Ir, n: *Node, fn_ref: usize) { var i: usize = 0; while i < n.attrs.len { var a = list_at(n.attrs, i); - match Vec.push(&irf.attrs, &a as *u8) { .Ok => {}, .Err(e) => {} } + Vec.push(&irf.attrs, &a as *u8); i = i + 1; } } -// ---- intrinsic ---- fn ast2ir_intrin_cast(self: *Ast2Ir, n: *Node, in: Intrin, args: Vec): usize { if args.len < 1 { @@ -579,38 +574,39 @@ fn ast2ir_intrin_cast(self: *Ast2Ir, n: *Node, in: Intrin, args: Vec): usize { } fn ast2ir_intrin_call(self: *Ast2Ir, n: *Node, in: Intrin, args: Vec): usize { - if @enum2int(in) == @enum2int(Intrin.BitSizeof) { - var arg = Ast.node(self.ast, list_at(args, 0)); - ret IrBuilder.type_bitsizeof(self.ir, node_ir(self, arg)); - } - if @enum2int(in) == @enum2int(Intrin.Sizeof) { - var arg = Ast.node(self.ast, list_at(args, 0)); - ret IrBuilder.type_sizeof(self.ir, node_ir(self, arg)); - } - if @enum2int(in) == @enum2int(Intrin.Alignof) { - var arg = Ast.node(self.ast, list_at(args, 0)); - ret IrBuilder.type_alignof(self.ir, node_ir(self, arg)); - } - if @enum2int(in) == @enum2int(Intrin.Enum2Int) { - var src = Ast.node(self.ast, list_at(args, 0)); - var v = emit_expr(self, list_at(args, 0)); - if v == 0 { ret 0; } - var agg_t = node_ir(self, src); - var tag_t = node_ir(self, n); - if agg_t == 0 || tag_t == 0 { ret 0; } - ret IrBuilder.agg_extract(self.ir, agg_t, tag_t, 0, v); - } - if @enum2int(in) == @enum2int(Intrin.FieldCount) { - var arg = Ast.node(self.ast, list_at(args, 0)); - ret IrBuilder.type_field_count(self.ir, node_ir(self, arg)); - } - if @enum2int(in) == @enum2int(Intrin.OffsetOf) { - var arg = Ast.node(self.ast, list_at(args, 0)); - var agg_t = node_ir(self, arg); - if agg_t == 0 { ret 0; } - var fnode = Ast.node(self.ast, list_at(args, 1)); - var idx: usize = 0; - if fnode != null { + match in { + .BitSizeof => { + var arg = Ast.node(self.ast, list_at(args, 0)); + ret IrBuilder.type_bitsizeof(self.ir, node_ir(self, arg)); + }, + .Sizeof => { + var arg = Ast.node(self.ast, list_at(args, 0)); + ret IrBuilder.type_sizeof(self.ir, node_ir(self, arg)); + }, + .Alignof => { + var arg = Ast.node(self.ast, list_at(args, 0)); + ret IrBuilder.type_alignof(self.ir, node_ir(self, arg)); + }, + .Enum2Int => { + var src = Ast.node(self.ast, list_at(args, 0)); + var v = emit_expr(self, list_at(args, 0)); + if v == 0 { ret 0; } + var agg_t = node_ir(self, src); + var tag_t = node_ir(self, n); + if agg_t == 0 || tag_t == 0 { ret 0; } + ret IrBuilder.agg_extract(self.ir, agg_t, tag_t, 0, v); + }, + .FieldCount => { + var arg = Ast.node(self.ast, list_at(args, 0)); + ret IrBuilder.type_field_count(self.ir, node_ir(self, arg)); + }, + .OffsetOf => { + var arg = Ast.node(self.ast, list_at(args, 0)); + var agg_t = node_ir(self, arg); + if agg_t == 0 { ret 0; } + var fnode = Ast.node(self.ast, list_at(args, 1)); + if fnode == null { ret 0; } + var idx: usize = 0; match fnode.body { .ExprIntLit(x) => { idx = int_lit_u64(fnode) as usize; }, .ExprIdent(e) => { @@ -618,29 +614,16 @@ fn ast2ir_intrin_call(self: *Ast2Ir, n: *Node, in: Intrin, args: Vec): usize { }, _ => { ret 0; }, } - } else { - ret 0; - } - var idx_node = const_usize(self, idx); - ret IrBuilder.type_offsetof(self.ir, agg_t, idx_node); - } - if @enum2int(in) == @enum2int(Intrin.Assert) { - ret ast2ir_intrin_assert(self, n, args); - } - if @enum2int(in) == @enum2int(Intrin.IntCast) || - @enum2int(in) == @enum2int(Intrin.Truncate) || - @enum2int(in) == @enum2int(Intrin.BitCast) || - @enum2int(in) == @enum2int(Intrin.FloatCast) || - @enum2int(in) == @enum2int(Intrin.Float2Int) || - @enum2int(in) == @enum2int(Intrin.Int2Float) || - @enum2int(in) == @enum2int(Intrin.Bool2Int) || - @enum2int(in) == @enum2int(Intrin.Ptr2Int) || - @enum2int(in) == @enum2int(Intrin.Int2Ptr) || - @enum2int(in) == @enum2int(Intrin.PtrCast) { - ret ast2ir_intrin_cast(self, n, in, args); - } - if @enum2int(in) == @enum2int(Intrin.Breakpoint) { - ret IrBuilder.dbg_breakpoint(self.ir); + var idx_node = const_usize(self, idx); + ret IrBuilder.type_offsetof(self.ir, agg_t, idx_node); + }, + .Assert => { ret ast2ir_intrin_assert(self, n, args); }, + .IntCast, .Truncate, .BitCast, .FloatCast, .Float2Int, .Int2Float, + .Bool2Int, .Ptr2Int, .Int2Ptr, .PtrCast => { + ret ast2ir_intrin_cast(self, n, in, args); + }, + .Breakpoint => { ret IrBuilder.dbg_breakpoint(self.ir); }, + _ => { ret 0; }, } ret 0; } @@ -665,22 +648,22 @@ fn ast2ir_intrin_assert(self: *Ast2Ir, n: *Node, args: Vec): usize { if self.sema.sources != null && n.span.file != no_file() { var src = set_at(self.sema.sources, n.span.file); if src != null { - ignore_bool(append_bytes(&msg, ByteView.as_slice(src.fname))); + append_bytes(&msg, ByteView.as_slice(src.fname)); var pos = Source.line_col(src.*, n.span.start); - ignore_bool(append_bytes(&msg, ":")); - ignore_bool(append_num(&msg, pos.line)); - ignore_bool(append_bytes(&msg, ":")); - ignore_bool(append_num(&msg, pos.col)); + append_bytes(&msg, ":"); + append_num(&msg, pos.line); + append_bytes(&msg, ":"); + append_num(&msg, pos.col); } } - ignore_bool(append_bytes(&msg, ": assert failed")); + append_bytes(&msg, ": assert failed"); if args.len == 2 { var mn = Ast.node(self.ast, list_at(args, 1)); if mn != null { match mn.body { .ExprStringLit(sl) => { - ignore_bool(append_bytes(&msg, ": ")); - ignore_bool(append_bytes(&msg, ByteView.as_slice(sl.data))); + append_bytes(&msg, ": "); + append_bytes(&msg, ByteView.as_slice(sl.data)); }, _ => {}, } @@ -688,8 +671,8 @@ fn ast2ir_intrin_assert(self: *Ast2Ir, n: *Node, args: Vec): usize { } var msg_view = ByteView.from_slice(ByteBuffer.as_slice(msg)); @assert(msg_view.len == 0 || msg_view.ptr != null, "panic message bytes must be non-null"); - ignore_usize(IrBuilder.dbg_panic(self.ir, msg_view)); - ignore_usize(IrBuilder.control_trap(self.ir)); + IrBuilder.dbg_panic(self.ir, msg_view); + IrBuilder.control_trap(self.ir); IrBuilder.block_end(self.ir); var cont_blk = IrBuilder.block_begin(self.ir); @@ -707,7 +690,6 @@ fn append_num(buf: *ByteBuffer, v: usize): bool { ret false; } -fn ignore_bool(b: bool) {} fn ast2ir_intrin_field(self: *Ast2Ir, n: *Node, in: Intrin): usize { if @enum2int(in) == @enum2int(Intrin.Len) { ret ast2ir_intrin_len(self, n); } @@ -742,7 +724,6 @@ fn ast2ir_intrin_len(self: *Ast2Ir, n: *Node): usize { ret 0; } -// ---- 左值 ---- fn emit_lvalue(self: *Ast2Ir, ref: usize): usize { var n = Ast.node(self.ast, ref); @@ -857,33 +838,32 @@ fn extra_elem(e: LangEntry): usize { ret 0; } -fn ignore_usize(x: usize) {} -// ---- 转换 ---- fn ast2ir_emit_cast_builtin(self: *Ast2Ir, n: *Node, in: Intrin, ft: usize, tt: usize, v: usize): usize { - if @enum2int(in) == @enum2int(Intrin.IntCast) { - var fs = irt(self, ft); - if fs != null { - match fs.node { - .Int(x) => { if x.is_signed { ret IrBuilder.cast_sext(self.ir, ft, tt, v); } }, - _ => {}, + match in { + .IntCast => { + var fs = irt(self, ft); + if fs != null { + match fs.node { + .Int(x) => { if x.is_signed { ret IrBuilder.cast_sext(self.ir, ft, tt, v); } }, + _ => {}, + } } - } - ret IrBuilder.cast_zext(self.ir, ft, tt, v); + ret IrBuilder.cast_zext(self.ir, ft, tt, v); + }, + .Truncate => { ret IrBuilder.cast_trunc(self.ir, ft, tt, v); }, + .BitCast => { ret IrBuilder.cast_bitcast(self.ir, ft, tt, v); }, + .FloatCast => { ret ir_float_cast(self, ft, tt, v); }, + .Float2Int => { ret IrBuilder.case_float2int(self.ir, ft, tt, v); }, + .Int2Float => { ret IrBuilder.case_int2float(self.ir, ft, tt, v); }, + .Bool2Int => { ret IrBuilder.cast_bool2int(self.ir, ft, tt, v); }, + .Ptr2Int => { ret IrBuilder.cast_ptr2int(self.ir, ft, tt, v); }, + .Int2Ptr => { ret IrBuilder.cast_int2ptr(self.ir, ft, tt, v); }, + .PtrCast => { ret IrBuilder.cast_bitcast(self.ir, ft, tt, v); }, + _ => {}, } - if @enum2int(in) == @enum2int(Intrin.Truncate) { ret IrBuilder.cast_trunc(self.ir, ft, tt, v); } - if @enum2int(in) == @enum2int(Intrin.BitCast) { ret IrBuilder.cast_bitcast(self.ir, ft, tt, v); } - if @enum2int(in) == @enum2int(Intrin.FloatCast) { - ret ir_float_cast(self, ft, tt, v); - } - if @enum2int(in) == @enum2int(Intrin.Float2Int) { ret IrBuilder.case_float2int(self.ir, ft, tt, v); } - if @enum2int(in) == @enum2int(Intrin.Int2Float) { ret IrBuilder.case_int2float(self.ir, ft, tt, v); } - if @enum2int(in) == @enum2int(Intrin.Bool2Int) { ret IrBuilder.cast_bool2int(self.ir, ft, tt, v); } - if @enum2int(in) == @enum2int(Intrin.Ptr2Int) { ret IrBuilder.cast_ptr2int(self.ir, ft, tt, v); } - if @enum2int(in) == @enum2int(Intrin.Int2Ptr) { ret IrBuilder.cast_int2ptr(self.ir, ft, tt, v); } - if @enum2int(in) == @enum2int(Intrin.PtrCast) { ret IrBuilder.cast_bitcast(self.ir, ft, tt, v); } Diag.err(self.diag, n.span, .Internal, "ast2ir: unknown cast builtin"); ret 0; } @@ -968,19 +948,18 @@ fn ast2ir_enum_variant(self: *Ast2Ir, n: *Node): usize { var eptr = IrBuilder.mem_alloca(self.ir, t, const_usize(self, 1)); var tptr = IrBuilder.mem_field(self.ir, t, eptr, 0); var tag_val = IrBuilder.type_const_int(self.ir, tag_ir, vidx); - ignore_usize(IrBuilder.mem_store(self.ir, tag_ir, tptr, tag_val)); + IrBuilder.mem_store(self.ir, tag_ir, tptr, tag_val); if vidx < variants.len { var payload_ir = variant_at(variants, vidx); if payload_ir != 0 { var pptr = IrBuilder.mem_field(self.ir, t, eptr, vidx + 1); var zero = emit_zero_value(self, payload_ir); - ignore_usize(IrBuilder.mem_store(self.ir, payload_ir, pptr, zero)); + IrBuilder.mem_store(self.ir, payload_ir, pptr, zero); } } ret eptr; } -// ---- 表达式 ---- fn emit_expr(self: *Ast2Ir, ref: usize): usize { var val = emit_expr_raw(self, ref); @@ -1120,7 +1099,7 @@ fn emit_binary(self: *Ast2Ir, n: *Node, op: Punct, left: usize, right: usize): u if ptr == 0 || v == 0 { ret 0; } var ln = Ast.node(self.ast, left); var t = node_ir(self, ln); - ignore_usize(IrBuilder.mem_store(self.ir, t, ptr, v)); + IrBuilder.mem_store(self.ir, t, ptr, v); ret v; } if is_assign_arith(op) { ret emit_assign_arith(self, op, left, right); } @@ -1199,7 +1178,7 @@ fn emit_assign_arith(self: *Ast2Ir, op: Punct, left: usize, right: usize): usize else if punct_is(op, .RShAssign) { res = IrBuilder.arith_shr(self.ir, t, lv, rv); } else { ret 0; } if res == 0 { ret 0; } - ignore_usize(IrBuilder.mem_store(self.ir, t, ptr, res)); + IrBuilder.mem_store(self.ir, t, ptr, res); ret res; } @@ -1210,14 +1189,14 @@ fn emit_short_circuit(self: *Ast2Ir, op: Punct, left: usize, right: usize): usiz var l = emit_expr(self, left); if l == 0 { ret 0; } - ignore_usize(IrBuilder.mem_store(self.ir, b_ir, slot, l)); + IrBuilder.mem_store(self.ir, b_ir, slot, l); var br = IrBuilder.control_br(self.ir, l); IrBuilder.block_end(self.ir); var rhs_blk = IrBuilder.block_begin(self.ir); var r = emit_expr(self, right); - if r != 0 { ignore_usize(IrBuilder.mem_store(self.ir, b_ir, slot, r)); } + if r != 0 { IrBuilder.mem_store(self.ir, b_ir, slot, r); } var rhs_end: usize = 0; if !self.ir.terminated { rhs_end = IrBuilder.control_jmp(self.ir); } IrBuilder.block_end(self.ir); @@ -1371,7 +1350,7 @@ fn emit_array_to_slice(self: *Ast2Ir, n: *Node, t: usize, elems: Vec, elem_lang: var fptr = IrBuilder.mem_field(self.ir, arr_ir, slot, i); var v = emit_expr(self, list_at(elems, i)); if v == 0 { ret 0; } - ignore_usize(IrBuilder.mem_store(self.ir, elem_ir, fptr, v)); + IrBuilder.mem_store(self.ir, elem_ir, fptr, v); i = i + 1; } base = IrBuilder.mem_field(self.ir, arr_ir, slot, 0); @@ -1413,13 +1392,13 @@ fn emit_aggregate_lit(self: *Ast2Ir, n: *Node, type_name: ByteView, fields: Vec) var eptr = IrBuilder.mem_alloca(self.ir, t, const_usize(self, 1)); var tptr = IrBuilder.mem_field(self.ir, t, eptr, 0); var tag_val = IrBuilder.type_const_int(self.ir, tag_ir, vidx); - ignore_usize(IrBuilder.mem_store(self.ir, tag_ir, tptr, tag_val)); + IrBuilder.mem_store(self.ir, tag_ir, tptr, tag_val); if iexpr != 0 { var payload_ir = variant_at(variants, vidx); var pptr = IrBuilder.mem_field(self.ir, t, eptr, vidx + 1); var payload = emit_expr(self, iexpr); if payload == 0 { ret 0; } - ignore_usize(IrBuilder.mem_store(self.ir, payload_ir, pptr, payload)); + IrBuilder.mem_store(self.ir, payload_ir, pptr, payload); } ret eptr; } @@ -1474,7 +1453,7 @@ fn emit_aggregate_lit(self: *Ast2Ir, n: *Node, type_name: ByteView, fields: Vec) } fn set_u(v: *Vec, i: usize, x: usize) { - match Vec.set(v, i, &x as *u8) { .Ok => {}, .Err(e) => {} } + Vec.set(v, i, &x as *u8); } fn emit_deferred_until(self: *Ast2Ir, base: usize) { @@ -1545,7 +1524,7 @@ fn emit_match(self: *Ast2Ir, n: *Node, matched_ref: usize, arms: Vec): usize { scrut_slot = IrBuilder.mem_alloca(self.ir, matched_ir, const_usize(self, 1)); var scrut_val = emit_expr(self, matched_ref); if scrut_val == 0 { ret 0; } - ignore_usize(IrBuilder.mem_store(self.ir, matched_ir, scrut_slot, scrut_val)); + IrBuilder.mem_store(self.ir, matched_ir, scrut_slot, scrut_val); } var narms = arms.len; @@ -1567,7 +1546,7 @@ fn emit_match(self: *Ast2Ir, n: *Node, matched_ref: usize, arms: Vec): usize { push_u(&arm_branches, IrBuilder.control_jmp(self.ir)); } IrBuilder.block_end(self.ir); - if i + 1 < narms { ignore_usize(IrBuilder.block_begin(self.ir)); } + if i + 1 < narms { IrBuilder.block_begin(self.ir); } i = i + 1; } var no_match_blk = IrBuilder.block_begin(self.ir); @@ -1585,7 +1564,7 @@ fn emit_match(self: *Ast2Ir, n: *Node, matched_ref: usize, arms: Vec): usize { var body: usize = 0; match arm.body { .MatchArm(ma) => { pat = ma.pattern; body = ma.body; }, _ => {} } emit_pattern_bind(self, pat, scrut_slot, matched_ir, matched_place_mode); - if body != 0 { ignore_usize(emit_expr(self, body)); } + if body != 0 { emit_expr(self, body); } } var j: usize = 0; if !self.ir.terminated { j = IrBuilder.control_jmp(self.ir); } @@ -1600,12 +1579,14 @@ fn emit_match(self: *Ast2Ir, n: *Node, matched_ref: usize, arms: Vec): usize { if branch != 0 { var bk = ir_kind_of(self, branch); var body_blk = list_at(body_blks, i); - if @enum2int(bk) == @enum2int(IrKind.ControlBr) { - var next_blk = no_match_blk; - if i + 1 < narms { next_blk = list_at(cond_blks, i + 1); } - IrBuilder.control_br_fixup(self.ir, branch, body_blk, next_blk); - } else if @enum2int(bk) == @enum2int(IrKind.ControlJmp) { - IrBuilder.control_jmp_fixup(self.ir, branch, body_blk); + match bk { + .ControlBr => { + var next_blk = no_match_blk; + if i + 1 < narms { next_blk = list_at(cond_blks, i + 1); } + IrBuilder.control_br_fixup(self.ir, branch, body_blk, next_blk); + }, + .ControlJmp => { IrBuilder.control_jmp_fixup(self.ir, branch, body_blk); }, + _ => {}, } } i = i + 1; @@ -1682,7 +1663,6 @@ fn emit_slice(self: *Ast2Ir, n: *Node, obj_ref: usize, begin_ref: usize, end_ref ret node; } -// ---- if / loop ---- fn emit_if_like(self: *Ast2Ir, ref: usize): usize { var n = Ast.node(self.ast, ref); @@ -1729,7 +1709,7 @@ fn emit_if_like(self: *Ast2Ir, ref: usize): usize { var then_v: usize = 0; if then_ref != 0 { then_v = emit_expr(self, then_ref); } if result_slot != 0 && then_v != 0 { - ignore_usize(IrBuilder.mem_store(self.ir, result_t, result_slot, then_v)); + IrBuilder.mem_store(self.ir, result_t, result_slot, then_v); } var then_end: usize = 0; if !self.ir.terminated { then_end = IrBuilder.control_jmp(self.ir); } @@ -1739,7 +1719,7 @@ fn emit_if_like(self: *Ast2Ir, ref: usize): usize { var else_v: usize = 0; if else_ref != 0 { else_v = emit_expr(self, else_ref); } if result_slot != 0 && else_v != 0 { - ignore_usize(IrBuilder.mem_store(self.ir, result_t, result_slot, else_v)); + IrBuilder.mem_store(self.ir, result_t, result_slot, else_v); } var else_end: usize = 0; if !self.ir.terminated { else_end = IrBuilder.control_jmp(self.ir); } @@ -1815,9 +1795,9 @@ fn emit_loop_like(self: *Ast2Ir, ref: usize): usize { } } if label_ref != 0 { ctx.label = label_name_of(self, label_ref); } - match Vec.push(&self.loop_stack, &ctx as *u8) { .Ok => {}, .Err(e) => {} } + Vec.push(&self.loop_stack, &ctx as *u8); - if body_ref != 0 { ignore_usize(emit_expr(self, body_ref)); } + if body_ref != 0 { emit_expr(self, body_ref); } var body_end: usize = 0; if !self.ir.terminated { body_end = IrBuilder.control_jmp(self.ir); } @@ -1827,7 +1807,7 @@ fn emit_loop_like(self: *Ast2Ir, ref: usize): usize { var else_v: usize = 0; if is_while && else_ref != 0 { else_v = emit_expr(self, else_ref); } if result_slot != 0 && else_v != 0 { - ignore_usize(IrBuilder.mem_store(self.ir, result_t, result_slot, else_v)); + IrBuilder.mem_store(self.ir, result_t, result_slot, else_v); } if pre_jmp != 0 { IrBuilder.control_jmp_fixup(self.ir, pre_jmp, cont_blk); } if br != 0 { IrBuilder.control_br_fixup(self.ir, br, body_blk, after_blk); } @@ -1858,7 +1838,7 @@ fn pop_loop(self: *Ast2Ir) { .cont_blk = 0, .defer_base = 0, .label = ByteView.empty(), .breaks = Vec.blank(@sizeof(usize), @alignof(usize)), .result_slot = 0, .result_tid = 0, }; - match Vec.pop(&self.loop_stack, &out as *u8) { .Ok => {}, .Err(e) => {} } + Vec.pop(&self.loop_stack, &out as *u8); } fn label_name_of(self: *Ast2Ir, ref: usize): ByteView { @@ -1896,7 +1876,7 @@ fn emit_break_stmt(self: *Ast2Ir, n: *Node): usize { if expr_ref != 0 && target.result_slot != 0 { var bv = emit_expr(self, expr_ref); if bv != 0 { - ignore_usize(IrBuilder.mem_store(self.ir, target.result_tid, target.result_slot, bv)); + IrBuilder.mem_store(self.ir, target.result_tid, target.result_slot, bv); } } emit_deferred_until(self, target.defer_base); @@ -1907,7 +1887,6 @@ fn emit_break_stmt(self: *Ast2Ir, n: *Node): usize { ret 0; } -// ---- 语句 / 声明 ---- fn emit_stmt(self: *Ast2Ir, ref: usize) { var n = Ast.node(self.ast, ref); @@ -1918,20 +1897,20 @@ fn emit_stmt(self: *Ast2Ir, ref: usize) { var v: usize = 0; if x.expr != 0 { v = emit_expr(self, x.expr); } emit_deferred_until(self, self.cur_defer_base); - if !self.ir.terminated { ignore_usize(IrBuilder.control_ret(self.ir, ret_ir, v)); } + if !self.ir.terminated { IrBuilder.control_ret(self.ir, ret_ir, v); } }, .StatementDefer(&x) => { if x.body != 0 { push_u(&self.defer_stack, x.body); } }, - .StatementComptime(&x) => { if x.body != 0 { ignore_usize(emit_expr(self, x.body)); } }, + .StatementComptime(&x) => { if x.body != 0 { emit_expr(self, x.body); } }, .StatementDecl(&x) => { if x.decl != 0 { emit_decl(self, x.decl); } }, - .StatementExpr(&x) => { if x.expr != 0 { ignore_usize(emit_expr(self, x.expr)); } }, - .ExprIf(&x) => { ignore_usize(emit_if_like(self, ref)); }, - .ExprIfvar(&x) => { ignore_usize(emit_if_like(self, ref)); }, - .ExprWhile(&x) => { ignore_usize(emit_loop_like(self, ref)); }, - .ExprLoop(&x) => { ignore_usize(emit_loop_like(self, ref)); }, - .StatementBreak(&x) => { ignore_usize(emit_break_stmt(self, n)); }, + .StatementExpr(&x) => { if x.expr != 0 { emit_expr(self, x.expr); } }, + .ExprIf(&x) => { emit_if_like(self, ref); }, + .ExprIfvar(&x) => { emit_if_like(self, ref); }, + .ExprWhile(&x) => { emit_loop_like(self, ref); }, + .ExprLoop(&x) => { emit_loop_like(self, ref); }, + .StatementBreak(&x) => { emit_break_stmt(self, n); }, .StatementContinue(&x) => { emit_continue_stmt(self, n); }, - .ExprBlock(&x) => { ignore_usize(emit_expr(self, ref)); }, - _ => { ignore_usize(emit_expr(self, ref)); }, + .ExprBlock(&x) => { emit_expr(self, ref); }, + _ => { emit_expr(self, ref); }, } } @@ -1957,8 +1936,8 @@ fn emit_decl(self: *Ast2Ir, ref: usize) { var n = Ast.node(self.ast, ref); if n == null { ret; } match n.body { - .VarDecl(&x) => { if self.ir.current_fn != 0 { ignore_usize(emit_var_decl(self, n)); } }, - .ConstDecl(&x) => { if self.ir.current_fn != 0 { ignore_usize(emit_var_decl(self, n)); } }, + .VarDecl(&x) => { if self.ir.current_fn != 0 { emit_var_decl(self, n); } }, + .ConstDecl(&x) => { if self.ir.current_fn != 0 { emit_var_decl(self, n); } }, _ => {}, } } @@ -1989,8 +1968,8 @@ fn fn_name_of(n: *Node): ByteView { fn diag_name(self: *Ast2Ir, span: Span, code: Code, prefix: []u8, name: ByteView) { var b = ByteBuffer.new(); defer { ByteBuffer.drop(&b); } - match ByteBuffer.append(&b, prefix) { .Ok => {}, .Err(e) => {} } - match ByteBuffer.append(&b, ByteView.as_slice(name)) { .Ok => {}, .Err(e) => {} } + ByteBuffer.append(&b, prefix); + ByteBuffer.append(&b, ByteView.as_slice(name)); Diag.err(self.diag, span, code, ByteBuffer.as_slice(b)); } @@ -2014,7 +1993,7 @@ fn emit_fn_body(self: *Ast2Ir, n: *Node) { var defer_base = self.cur_defer_base; var loop_base = self.loop_stack.len; - ignore_usize(IrBuilder.block_begin(self.ir)); + IrBuilder.block_begin(self.ir); var params = Vec.blank(@sizeof(usize), @alignof(usize)); var body_ref: usize = 0; @@ -2031,23 +2010,23 @@ fn emit_fn_body(self: *Ast2Ir, n: *Node) { var pv = IrBuilder.control_param(self.ir, p_ir, idx); var one = const_usize(self, 1); var slot = IrBuilder.mem_alloca(self.ir, p_ir, one); - ignore_usize(IrBuilder.mem_store(self.ir, p_ir, slot, pv)); + IrBuilder.mem_store(self.ir, p_ir, slot, pv); ir_map_put(self, pd.resolved_def_id, slot); } } i = i + 1; } - if body_ref != 0 { ignore_usize(emit_expr(self, body_ref)); } + if body_ref != 0 { emit_expr(self, body_ref); } if !self.ir.terminated { emit_deferred_until(self, defer_base); } if !self.ir.terminated { if ret_is_unit { - ignore_usize(IrBuilder.control_ret(self.ir, ret_ir, 0)); + IrBuilder.control_ret(self.ir, ret_ir, 0); } else if ret_ir != 0 { var zero = emit_zero_value(self, ret_ir); - ignore_usize(IrBuilder.control_ret(self.ir, ret_ir, zero)); + IrBuilder.control_ret(self.ir, ret_ir, zero); } else { - ignore_usize(IrBuilder.control_unreachable(self.ir)); + IrBuilder.control_unreachable(self.ir); } } @@ -2077,7 +2056,7 @@ fn emit_aggregate_fns_reserve(self: *Ast2Ir, te: *Node) { var mn = Ast.node(self.ast, list_at(members, i)); if mn != null { match mn.body { - .FnDecl(x) => { ignore_usize(emit_fn_reserve(self, mn)); }, + .FnDecl(x) => { emit_fn_reserve(self, mn); }, .MemberDecl(md) => { if md.type_expr != 0 { var mt = Ast.node(self.ast, md.type_expr); @@ -2138,7 +2117,7 @@ fn emit_container_reserve(self: *Ast2Ir, ref: usize) { var d = Ast.node(self.ast, dref); if d != null { match d.body { - .FnDecl(x) => { ignore_usize(emit_fn_reserve(self, d)); }, + .FnDecl(x) => { emit_fn_reserve(self, d); }, .TypeDecl(td) => { var tpat = Ast.node(self.ast, td.pattern); if tpat != null && is_pattern_ident(tpat) { @@ -2251,7 +2230,6 @@ fn emit_implicit_cast(self: *Ast2Ir, n: *Node, ft: usize, tt: usize, v: usize): ret 0; } -// ---- 驱动 ---- fn new(builder: *IrBuilder, sema: *Sema, diag: *Diag): Ast2Ir { ret Ast2Ir { @@ -2330,6 +2308,5 @@ fn list_ptr(v: Vec, i: usize): *Ast { ret null; } -// ---- 测试 ---- fn main() {} diff --git a/stage2/attr.spl b/stage2/attr.spl index 99e464e..33ec9a6 100644 --- a/stage2/attr.spl +++ b/stage2/attr.spl @@ -1,8 +1,7 @@ // Expect retcode = 0 -// 属性注册表与属性节点(移植自 stage1/spl_attr.c)。注册表是数据:内置属性 -// 在 register_builtins 里登记,查找按 (ns, name)。节点记录命中信息 + 实参。 -// 新增属性只加注册项,不改 sema 逻辑(对应 SPL.md 的 @/# 扩展点)。 +// 属性注册表:内置属性在 register_builtins 登记,按 (ns, name) 查找。新增属性只加 +// 注册项,不改 sema 逻辑(SPL.md 的 @/# 扩展点)。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -163,10 +162,7 @@ fn alloc(self: *Attr, info_index: usize, args: Vec): usize { } fn registry_add(self: *Attr, info: AttrInfo) { - match Vec.push(&self.registry, &info as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.push(&self.registry, &info as *u8); } // 返回注册表下标(>=1)或 0。 @@ -205,7 +201,6 @@ fn register_builtins(self: *Attr) { registry_add(self, make_info("", "export", .Ir, .Decl, .Optional, 1, 1)); } -// ---- dump(镜像 stage1 spl_attr_dump / spl_attr_dump_id)---- fn push_out(buf: *ByteBuffer, bytes: []u8): bool { match ByteBuffer.append(buf, bytes) { @@ -341,7 +336,6 @@ fn dump(self: *Attr, out: *ByteBuffer): bool { ret true; } -// ---- 测试 ---- fn expect_text(buf: ByteBuffer, expected: []u8) { var got = ByteBuffer.as_slice(buf); diff --git a/stage2/def.spl b/stage2/def.spl index 0bb6a00..0a22c1e 100644 --- a/stage2/def.spl +++ b/stage2/def.spl @@ -1,12 +1,7 @@ // Expect retcode = 0 -// 声明句柄表(移植自 stage1/spl_lang_type.h 的 spl_def_node_t 部分)。 -// DefId 是「声明」的稳定身份:作用域符号、AST 节点 resolved_def_id、以及将来 -// comptime 生成的声明都用它。前向引用/环形引用由 state 状态机表达。 -// -// 与 stage1 的差异:owner_ast 改为不透明 `*any`(借用),使本表不依赖具体 AST -// 表示,便于将来 comptime/序列化复用;sema 侧自行 cast 回 *Ast。 -// 名称是 ByteView(借用源/AST),本表不做拥有。 +// 声明句柄表。DefId 是声明的稳定身份:作用域符号、节点 resolved_def_id、comptime +// 生成的声明都用它;前向/环形引用由 state 状态机表达。owner_ast 为不透明 *any。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -84,7 +79,7 @@ fn drop(self: *DefTable) { Vec.drop(&self.table); } -// id 0 与越界均返回 null(对应 stage1 spl_def_node)。 +// id 0 与越界均返回 null。 fn node(self: *DefTable, id: usize): *DefNode { if id == 0 || id >= self.table.len { ret null; } ret (self.table.data as *DefNode) + id; @@ -129,7 +124,6 @@ fn get_lang_id(self: *DefTable, id: usize): usize { ret d.lang_id; } -// ---- 分类 ---- fn kind_name(kind: DefKind): []u8 { match kind { @@ -156,7 +150,7 @@ fn state_name(state: DeclState): []u8 { ret "unknown"; } -// 能作为类型使用的 def(对应 stage1 sema_def_is_type)。 +// 能作为类型使用的 def。 fn is_type_kind(kind: DefKind): bool { match kind { .Scalar => { ret true; }, @@ -169,7 +163,6 @@ fn is_type_kind(kind: DefKind): bool { ret false; } -// ---- dump(镜像 stage1 spl_type_def_dump 的文本)---- fn push_out(buf: *ByteBuffer, bytes: []u8): bool { match ByteBuffer.append(buf, bytes) { @@ -203,7 +196,6 @@ fn dump(self: *DefTable, id: usize, out: *ByteBuffer): bool { ret push_out(out, ByteView.as_slice(d.name)); } -// ---- 测试 ---- fn test_alloc_and_state() { var dt: DefTable = undefined; diff --git a/stage2/diag.spl b/stage2/diag.spl index cdf49db..5498d24 100644 --- a/stage2/diag.spl +++ b/stage2/diag.spl @@ -1,14 +1,7 @@ // Expect retcode = 0 -// 丰富诊断(参考 rustc / Clang / Swift 的设计,不照搬 stage1 C 实现): -// Severity Note/Help/Warning/Error/Fatal -// Code 固定语义枚举 + 稳定 E 码;集中管理,利于 diff -// Span 字节区间 {file,start,end};file 是 Sources 的下标,NO_FILE 表示无位置 -// Label 主/次标签(span + 文本),可多个 -// Child 子诊断(note/help,可带 span),挂在条目上 -// 渲染:人类可读(源码行 + caret 下划线)与 JSON(字段稳定)双格式。 -// 位置只存下标,渲染时经 Sources 解析行列/取行,避免复制文件名。 -// 消息按拥有型 Str 保存;条目拥有其 labels/children;clear/drop 释放全部内部资源。 +// 丰富诊断:Severity / 稳定 E 码 / Span / Label / Child,渲染为人类可读或 JSON。 +// 位置只存下标,渲染时经 Sources 解析行列;条目拥有其字符串与 labels/children。 type .{ .Error, .Status, .make } = @import("./utils/error.spl"); type .{ .Vec } = @import("./utils/vec.spl"); @@ -181,7 +174,6 @@ fn has_error(self: Diag): bool { ret self.errors > 0; } fn has_fatal(self: Diag): bool { ret self.fatals > 0; } -// ---- 采集 ---- // 追加一条诊断,返回其下标(失败返回 no_file())。span 为主位置。 fn emit(self: *Diag, severity: Severity, stage: Stage, code: Code, span: Span, @@ -265,7 +257,6 @@ fn attach_child(self: *Diag, severity: Severity, span: Span, msg: []u8): Status ret .Ok; } -// ---- 名称 ---- fn severity_name(severity: Severity): []u8 { match severity { @@ -370,7 +361,6 @@ fn code_name(code: Code): []u8 { ret "none"; } -// ---- 渲染:公共小工具 ---- fn append_num(out: *ByteBuffer, value: usize): Status { ret append_usize(out, value, 10, false); @@ -519,7 +509,6 @@ fn render_human(self: *Diag, out: *ByteBuffer): Status { ret .Ok; } -// ---- JSON 渲染(字段稳定,供 LSP / diff 工具)---- fn append_json_hex4(out: *ByteBuffer, b: u8): Status { var hex: []u8 = "0123456789abcdef"; @@ -661,7 +650,6 @@ fn render_json(self: *Diag, out: *ByteBuffer): Status { ret ByteBuffer.append_byte(out, ']'); } -// ---- 生命周期 ---- fn drop_item(it: *Item) { Str.drop(&it.message); @@ -700,7 +688,6 @@ fn drop(self: *Diag) { self.sources = null; } -// ---- 测试辅助 ---- fn view(text: []u8): ByteView { ret ByteView.from_slice(text); diff --git a/stage2/eval.spl b/stage2/eval.spl index 2459122..4616ba7 100644 --- a/stage2/eval.spl +++ b/stage2/eval.spl @@ -1,22 +1,16 @@ // Expect retcode = 0 -// comptime / const 求值的**接口 seam**(本轮只占位,不实现求值)。 -// -// 目标:把「编译期求值」从 sema 主体里隔离出来,将来接一个解释器(可直接复用 -// VM 或 AST 求值器)时不动 sema 结构。sema 只在 comptime 语句 / const 初始化 / -// @import 等点调用这里;未实现时统一返回 NotConst(= 放弃折叠,不报错)。 -// -// 分块编译相关:eval 未来的产物是「编译期生成的声明」,统一经 DeclSink 登记, -// 由驱动在固定点循环里插入并触发重跑;eval 自己不直接改 sema 表,避免重入。 +// comptime/const 求值的接口 seam:sema 只在此调用,未实现时返回 NotConst(放弃折叠、 +// 不报错)。编译期生成的声明经 DeclSink 登记,不改 sema 表。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); type Ast = @import("./ast.spl"); type Diag = @import("./diag.spl"); -// 编译期值:占位。未来扩展为 BigInt / 聚合 / 类型句柄等。 +// 编译期值(当前仅标量)。 type EvalValue = enum { - Int: usize, // TODO: BigInt + Int: usize, Bool: bool, } @@ -36,14 +30,13 @@ type DeclSinkResult = enum { Err: Error, } -// 求值上下文(借用 sink 与 diag;本轮不持有所有权)。 +// 求值上下文:sink/diag 均借用,不持有所有权。 type Eval = @self; sink: *DeclSink, // 借用,可为 null diag: *Diag, // 借用,可为 null -enabled: bool, // false = 完全不求值(等价旧行为) +enabled: bool, // false = 完全不求值 -// ---- DeclSink ---- fn sink_new(): DeclSinkResult { var s = DeclSink { .items = Vec.blank(@sizeof(usize), @alignof(usize)) }; @@ -66,7 +59,6 @@ fn sink_len(self: *DeclSink): usize { ret self.items.len; } -// ---- Eval ---- fn new(sink: *DeclSink, diag: *Diag, enabled: bool): Eval { ret Eval { @@ -80,25 +72,24 @@ fn is_enabled(self: *Eval): bool { ret self.enabled; } -// 求值一个表达式。本轮一律 NotConst(可由调用方作为「放弃折叠」处理)。 +// 求值表达式:当前一律 NotConst(调用方按“放弃折叠”处理)。 fn eval_expr(self: *Eval, ast: *Ast, ref: usize): EvalOutcome { if !self.enabled { ret .NotConst; } ret .NotConst; } -// 执行一个 comptime 块(可能产生声明,登记到 sink)。本轮不做。 +// 执行 comptime 块;当前不实现,直接 NotConst。 fn run_block(self: *Eval, ast: *Ast, ref: usize): EvalOutcome { if !self.enabled { ret .NotConst; } ret .NotConst; } -// 顶层 const 初始化求值。本轮不做。 +// 顶层 const 初始化求值;当前不实现。 fn eval_const_init(self: *Eval, ast: *Ast, ref: usize): EvalOutcome { if !self.enabled { ret .NotConst; } ret .NotConst; } -// ---- 测试 ---- fn test_sink() { var sink: DeclSink = undefined; diff --git a/stage2/intrin.spl b/stage2/intrin.spl index c5ddf4b..e761a66 100644 --- a/stage2/intrin.spl +++ b/stage2/intrin.spl @@ -1,8 +1,7 @@ // Expect retcode = 0 -// 内建(intrinsic)注册表(移植自 stage1/spl_intrin.c)。表是数据:按 kind 查 -// 描述信息,按名字/字段/`as` 转换规则反查 kind。新增内建只改 info_at, -// 不改 sema 逻辑(对应 SPL.md 的 @/# 扩展点)。 +// 内建注册表:按 Intrin 查描述信息,按名字/字段/`as` 规则反查 Intrin。新增内建只改 +// info_at,不改 sema 逻辑(SPL.md 的 @/# 扩展点)。 type .{ .ByteView } = @import("utils/byte_view.spl"); type TypeTable = @import("./type_table.spl"); @@ -63,7 +62,7 @@ fn kind_is(a: LangKind, b: LangKind): bool { ret @enum2int(a) == @enum2int(b); } -// 与 stage1 表逐项对应(枚举顺序即 kind 数值)。 +// 枚举顺序即 kind 数值(与 splc0 表一致)。 fn info_at(index: usize): IntrinInfo { match index { 1 => { @@ -250,7 +249,6 @@ fn lookup_cast(ir: *TypeTable, ft: usize, tt: usize): Intrin { ret .None; } -// ---- 测试 ---- fn test_info_table() { var d = info(.Sizeof); diff --git a/stage2/ir.spl b/stage2/ir.spl index aea4288..a9db723 100644 --- a/stage2/ir.spl +++ b/stage2/ir.spl @@ -1,10 +1,7 @@ // Expect retcode = 0 -// SIR 中间表示(移植自 stage1/spl_ir.c/.h)。节点用 arena 序号引用(0 = error), -// 按函数分桶。节点公共字段(kind/dbg/attrs)在外层 entry,kind 专属载荷在 ADT -// IrBody;kind 与载荷变体一一对应(多种 kind 可共享同一载荷形状)。 -// -// builder 维护当前函数/基本块/fixup 表,负责发射节点与回填跳转。 +// SIR 中间表示:节点用 arena 序号引用(0=error),按函数分桶;公共字段在 IrEntry, +// kind 专属载荷在 IrBody ADT(kind 与载荷一一对应)。builder 负责发射与跳转回填。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -138,7 +135,6 @@ type Ir = @self; funcs: Vec, // IrFunc globals: Vec, // Global -// ---- 生命周期 ---- fn new_entry(): IrEntry { ret IrEntry { @@ -159,8 +155,8 @@ fn new(): Ir { .nodes = Vec.blank(@sizeof(IrEntry), @alignof(IrEntry)), }; var sn = new_entry(); - match Vec.push(&sentinel.nodes, &sn as *u8) { .Ok => {}, .Err(error) => {} } - match Vec.push(&ir.funcs, &sentinel as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&sentinel.nodes, &sn as *u8); + Vec.push(&ir.funcs, &sentinel as *u8); ret ir; } @@ -307,7 +303,6 @@ fn kind_name(kind: IrKind): []u8 { ret "?"; } -// ---- dump ---- fn out_str(out: *ByteBuffer, s: []u8): bool { match ByteBuffer.append(out, s) { .Ok => { ret true; }, .Err(error) => { ret false; } } @@ -360,11 +355,10 @@ fn dump_body(out: *ByteBuffer, ty: *TypeTable, e: *IrEntry): bool { .Arith(a) => { if !dump_type(out, ty, a.tid) { ret false; } if !dump_ref(out, a.left) { ret false; } - // 一元 arith(neg/abs/not)不打印 right(镜像 stage1)。 - if @enum2int(e.kind) == @enum2int(IrKind.ArithNeg) || - @enum2int(e.kind) == @enum2int(IrKind.ArithAbs) || - @enum2int(e.kind) == @enum2int(IrKind.ArithNot) { - ret true; + // 一元 arith(neg/abs/not)不打印 right。 + match e.kind { + .ArithNeg, .ArithAbs, .ArithNot => { ret true; }, + _ => {}, } ret dump_ref(out, a.right); }, @@ -465,7 +459,7 @@ fn dump_body(out: *ByteBuffer, ty: *TypeTable, e: *IrEntry): bool { match ByteBuffer.append_byte(out, cv as u8) { .Ok => {}, .Err(error) => { ret false; } } ret out_str(out, "'"); } - // stage1 对其他常量统一按 int_lit 打印(union 别名)。 + // 其他常量统一按 int_lit 打印(union 别名)。 var iv: usize = 0; match c.lit { .Int(v) => { iv = v; }, @@ -582,7 +576,6 @@ fn dump(self: *Ir, ty: *TypeTable, attr: *Attr, out: *ByteBuffer): bool { ret true; } -// ---- 测试 ---- fn test_kinds() { @assert(ByteView.eq(ByteView.from_slice(kind_name(.ArithAdd)), ByteView.from_slice("arith.add")), diff --git a/stage2/ir2c.spl b/stage2/ir2c.spl index 4e8702d..b0c82b7 100644 --- a/stage2/ir2c.spl +++ b/stage2/ir2c.spl @@ -1,12 +1,7 @@ // Expect retcode = 0 -// IR -> C99 后端(P1a 子集)。 -// -// 设计:每个 IR ref 一个 C 局部变量(C 编译器 -O2 会做 mem2reg),标签用 goto; -// 类型直接由 IR 的 tid 决定,生成期无运行时分发。 -// -// 每个非 extern 函数的 C 名为 `spl_f`;extern 函数直接用其 SPL 名 -// (由 runtime 提供)。暂不支持聚合/切片/全局数据。 +// IR -> C99。每个 IR ref 生成一个 C 局部变量(交给 C 编译器 mem2reg),标签用 goto; +// 类型由 IR tid 决定,生成期无运行时分发。非 extern 函数名为 `spl_f`。 type .{ .Vec } = @import("utils/vec.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); @@ -83,7 +78,6 @@ fn put_unsupported(self: *Ir2C, what: []u8) { put(self, " */\n"); } -// ---- 类型查询 ---- fn info_of(self: *Ir2C, tid: usize): *LayoutM.LayoutInfo { ret LayoutM.info_of(self.layout, tid); @@ -168,7 +162,6 @@ fn fn_ret_type(self: *Ir2C, fn_tid: usize): usize { ret 0; } -// ---- C 类型 ---- fn put_type(self: *Ir2C, tid: usize): bool { var te = TypeTable.node(self.ty, tid); @@ -231,7 +224,6 @@ fn c_fn_name(self: *Ir2C, fid: usize) { put_u(self, fid); } -// ---- 常量解析 ---- fn const_node(self: *Ir2C, f: *IrFunc, ref: usize): usize { if ref == 0 || ref >= f.nodes.len { ret 0; } @@ -250,7 +242,6 @@ fn const_node(self: *Ir2C, f: *IrFunc, ref: usize): usize { ret 0; } -// ---- 聚合字段 ---- fn field_tid(self: *Ir2C, tid: usize, idx: usize): usize { var te = TypeTable.node(self.ty, tid); @@ -436,7 +427,6 @@ fn emit_agg_insert(self: *Ir2C, ref: usize, n: *IrEntry) { } } -// ---- 节点发射 ---- fn emit_arith(self: *Ir2C, ref: usize, n: *IrEntry) { match n.body { @@ -1224,7 +1214,6 @@ fn emit_def(self: *Ir2C, fid: usize) { put(self, "spl_trap();\n}\n"); } -// ---- driver ---- fn find_main(self: *Ir2C): usize { var i: usize = 1; diff --git a/stage2/ir2vm.spl b/stage2/ir2vm.spl index 29a2d77..1d92350 100644 --- a/stage2/ir2vm.spl +++ b/stage2/ir2vm.spl @@ -1,11 +1,7 @@ // Expect retcode = 0 -// IR -> VM 机器码(移植自 stage1/spl_ir2vm.c)。 -// 依赖:IR(ir.spl)、IR 类型表(type_table.spl)、布局(layout.spl)、 -// 属性(attr.spl)、字节码容器(mcode.spl)。 -// -// extern_native 用「按函数 ref 下标的 isize 数组」代替 stage1 的 map: -// 默认 -1 表示非 extern,>=0 表示 native 索引(语义等价)。 +// IR -> VM 字节码。extern_native 是按函数 ref 下标的 isize 数组:-1 非 extern, +// >=0 为 native 索引。 type .{ .Vec } = @import("utils/vec.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); @@ -19,7 +15,7 @@ type IrM = @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"); +type Mem = @import("utils/memory.spl"); type Ir2Vm = @self; @@ -31,7 +27,6 @@ extern_native: Vec, // isize global_gaddr: Vec, // usize:每个全局变量在 prog.gdata 的下标 prog: Prog, -// ---- 类型/布局查询 ---- fn info_of(ctx: *Ir2Vm, tid: usize): *LayoutM.LayoutInfo { ret LayoutM.info_of(ctx.layout, tid); @@ -187,7 +182,6 @@ fn ir_result_tid(ctx: *Ir2Vm, n: *IrEntry): usize { ret 0; } -// ---- 小工具 ---- // 内部热路径:假定索引有效,直接取址(省去 Vec.get/valid)。 fn usize_at(v: *Vec, i: usize): usize { @@ -195,7 +189,7 @@ fn usize_at(v: *Vec, i: usize): usize { } fn push_usize(v: *Vec, x: usize) { - ignore_bool(Vec.push_raw(v, &x as *u8)); + Vec.push_raw(v, &x as *u8); } fn fnode(f: *IrFunc, i: usize): *IrEntry { @@ -239,7 +233,6 @@ fn const_fn(n: *IrEntry): usize { ret 0; } -// ---- extern ---- fn fn_check_extern(ctx: *Ir2Vm, f: *IrFunc): bool { if ctx.attr == null || f == null { ret false; } @@ -275,7 +268,6 @@ fn extern_set(ctx: *Ir2Vm, ref: usize, value: isize) { } } -// ---- 帧布局 ---- type Slot = struct { result_off: usize, @@ -363,7 +355,7 @@ fn frame_build(fl: *FrameLayout, ctx: *Ir2Vm, fid: usize) { var i: usize = 0; while i < n { var blank: Slot = .{ .result_off = 0, .data_off = 0 }; - ignore_bool(Vec.push_raw(&fl.slots, &blank as *u8)); + Vec.push_raw(&fl.slots, &blank as *u8); i = i + 1; } @@ -397,7 +389,6 @@ fn frame_drop(fl: *FrameLayout) { Vec.drop(&fl.slots); } -// ---- cgen ---- type FixKind = enum { Jmp, @@ -432,7 +423,7 @@ fn emit(cg: *Cgen, op: Op, ty: VmKind, imm: usize) { prog.insns.len = i + 1; ret; } - ignore_usize(Mcode.add_instr(prog, op, ty, imm)); + Mcode.add_instr(prog, op, ty, imm); } fn ip_of(cg: *Cgen): usize { @@ -534,7 +525,7 @@ fn cg_add_fix(cg: *Cgen, ins_idx: usize, kind: FixKind, node_target: usize, fn_t .node_target = node_target, .fn_target = fn_target, }; - match Vec.push(cg.fixups, &fx as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(cg.fixups, &fx as *u8); } fn arith_tid(n: *IrEntry): usize { @@ -696,7 +687,7 @@ fn cg_cast(cg: *Cgen, ref: usize, n: *IrEntry) { } else if f_bool && t_int { emit(cg, .Zext, .Void, 1); } - ignore_bool(t_bool); + t_bool; cg_store_slot(cg, ref, tk); }, _ => {}, @@ -1148,7 +1139,6 @@ fn cmp_tid(n: *IrEntry): usize { ret 0; } -// ---- 翻译 ---- fn translate_function(ctx: *Ir2Vm, fid: usize, all_fixups: *Vec): usize { var irf = IrM.func(ctx.ir, fid); @@ -1172,7 +1162,7 @@ fn translate_function(ctx: *Ir2Vm, fid: usize, all_fixups: *Vec): usize { var func_ip = ip_of(&cg); - ignore_usize(Mcode.add_func(&ctx.prog, irf.name, fn_nargs(ctx, irf.fn_tid), func_ip)); + Mcode.add_func(&ctx.prog, irf.name, fn_nargs(ctx, irf.fn_tid), func_ip); var local_slots = (cg.frame.frame_bytes - cg.frame.args_bytes + 7) / 8; emit(&cg, .Alloc, .Void, local_slots); @@ -1193,23 +1183,19 @@ fn translate_function(ctx: *Ir2Vm, fid: usize, all_fixups: *Vec): usize { i = 0; while i < local_fixups.len { - match Vec.get(&local_fixups, i) { - .Ok(ptr) => { - var fx = ptr as *Fix; - if @enum2int(fx.kind) == @enum2int(FixKind.Jmp) { - var ins = ins_ptr(&ctx.prog, fx.ins_idx); - if ins != null { - var target_ip: usize = 0; - if fx.node_target < nnodes { - target_ip = usize_at(&cg.node_ip, fx.node_target); - } - ins.imm = target_ip - fx.ins_idx - 1; + var fx = (local_fixups.data as *Fix) + i; + match fx.kind { + .Jmp => { + var ins = ins_ptr(&ctx.prog, fx.ins_idx); + if ins != null { + var target_ip: usize = 0; + if fx.node_target < nnodes { + target_ip = usize_at(&cg.node_ip, fx.node_target); } - } else if @enum2int(fx.kind) == @enum2int(FixKind.Fnaddr) { - match Vec.push(all_fixups, ptr as *u8) { .Ok => {}, .Err(error) => {} } + ins.imm = target_ip - fx.ins_idx - 1; } }, - .Err(error) => {}, + .Fnaddr => { Vec.push(all_fixups, fx as *u8); }, } i = i + 1; } @@ -1220,9 +1206,8 @@ fn translate_function(ctx: *Ir2Vm, fid: usize, all_fixups: *Vec): usize { ret func_ip; } -// ---- 生命周期 / 入口 ---- -// 就地初始化(避免返回含 Prog 的大聚合;对应 stage1 spl_ir2vm_init)。 +// 就地初始化,避免返回含 Prog 的大聚合。 fn init(ctx: *Ir2Vm, ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr) { ctx.ir = ir; ctx.ty = ty; @@ -1246,7 +1231,7 @@ fn drop(ctx: *Ir2Vm) { fn run_func(ctx: *Ir2Vm, ref: usize): i32 { var all_fixups = Vec.blank(@sizeof(Fix), @alignof(Fix)); defer { Vec.drop(&all_fixups); } - ignore_usize(translate_function(ctx, ref, &all_fixups)); + translate_function(ctx, ref, &all_fixups); ret 0; } @@ -1258,7 +1243,7 @@ fn run(ctx: *Ir2Vm): i32 { var i: usize = 0; while i < n { var v: isize = -1; - match Vec.push(&ctx.extern_native, &v as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&ctx.extern_native, &v as *u8); i = i + 1; } i = 1; @@ -1283,12 +1268,12 @@ fn run(ctx: *Ir2Vm): i32 { 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) => {} } + Vec.push(&ctx.global_gaddr, &dv as *u8); gi = gi + 1; } // 哨兵:保证真实函数入口地址非零。 - ignore_usize(Mcode.add_instr(&ctx.prog, .Halt, .Void, 0)); + Mcode.add_instr(&ctx.prog, .Halt, .Void, 0); // 预分配指令容量(按 IR 节点数粗略估计),减少逐条 append 的扩容/拷贝。 var est: usize = 16; @@ -1298,7 +1283,7 @@ fn run(ctx: *Ir2Vm): i32 { if irf != null { est = est + irf.nodes.len * 8 + 32; } i = i + 1; } - match Vec.reserve(&ctx.prog.insns, est) { .Ok => {}, .Err(error) => {} } + Vec.reserve(&ctx.prog.insns, est); // Pass 2:翻译非 extern 函数。 var fid_ip = Vec.blank(@sizeof(usize), @alignof(usize)); @@ -1382,12 +1367,8 @@ fn store(ctx: *Ir2Vm, path: ByteView): bool { ret false; } -// ---- 工具 ---- -fn ignore_usize(v: usize) {} -fn ignore_bool(b: bool) {} -// ---- 测试 ---- fn main() { var ir = IrM.new(); diff --git a/stage2/ir_builder.spl b/stage2/ir_builder.spl index 6eba8a7..6dbe4ad 100644 --- a/stage2/ir_builder.spl +++ b/stage2/ir_builder.spl @@ -1,7 +1,6 @@ // Expect retcode = 0 -// SIR builder (IrBuilder). Split from ir.spl: stage1 ast2ir -// infinitely recurses on same-file @self nesting; cross-file is fine. +// IR 构建器:单独成文件,以免 ast2ir 在同文件 @self 嵌套时无限递归。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -18,8 +17,6 @@ fn list_at(v: Vec, i: usize): usize { ret ((v.data as *usize) + i).*; } -// ---- builder ---- - type FixKind = enum { BrTrue, BrFalse, Jmp } type Fix = struct { @@ -46,13 +43,9 @@ fn builder_alloc(self: *IrBuilder, kind: IrKind): usize { e.kind = kind; e.dbg = self.dbg; } - if self.current_block >= self.blocks.len { ret ref; } - match Vec.get(&self.blocks, self.current_block) { - .Ok(p) => { - var slot = p as *usize; - if slot.* == 0 { slot.* = ref; } - }, - .Err(error) => {}, + if self.current_block < self.blocks.len { + var slot = (self.blocks.data as *usize) + self.current_block; + if slot.* == 0 { slot.* = ref; } } ret ref; } @@ -113,25 +106,18 @@ fn fn_begin_at(self: *IrBuilder, fid: usize) { fn fn_end(self: *IrBuilder) { var k: usize = 0; while k < self.fixups.len { - match Vec.get(&self.fixups, k) { - .Ok(fp) => { - var fx = fp as *Fix; - var e = Ir.node(&self.ir, self.current_fn, fx.node); - if e != null { - var target: usize = 0; - if fx.block < self.blocks.len { target = list_at(self.blocks, fx.block); } - if target != 0 { - if @enum2int(fx.slot) == @enum2int(FixKind.BrTrue) { - match e.body { .Br(&b) => { b.true_label = target; }, _ => {} } - } else if @enum2int(fx.slot) == @enum2int(FixKind.BrFalse) { - match e.body { .Br(&b) => { b.false_label = target; }, _ => {} } - } else { - match e.body { .Jmp(&j) => { j.label = target; }, _ => {} } - } - } + var fx = (self.fixups.data as *Fix) + k; + var e = Ir.node(&self.ir, self.current_fn, fx.node); + if e != null { + var target: usize = 0; + if fx.block < self.blocks.len { target = list_at(self.blocks, fx.block); } + if target != 0 { + match fx.slot { + .BrTrue => { match e.body { .Br(&b) => { b.true_label = target; }, _ => {} } }, + .BrFalse => { match e.body { .Br(&b) => { b.false_label = target; }, _ => {} } }, + .Jmp => { match e.body { .Jmp(&j) => { j.label = target; }, _ => {} } }, } - }, - .Err(error) => {}, + } } k = k + 1; } @@ -143,7 +129,7 @@ fn fn_end(self: *IrBuilder) { fn block_begin(self: *IrBuilder): usize { var zero: usize = 0; - match Vec.push(&self.blocks, &zero as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&self.blocks, &zero as *u8); var block = self.blocks.len - 1; self.current_block = block; self.terminated = false; @@ -151,10 +137,9 @@ fn block_begin(self: *IrBuilder): usize { } fn block_end(self: *IrBuilder) { - // terminated 与空块校验在 stage1 为 Panic;这里保持同样约束但不终止进程。 + // 空实现:本实现不做 terminated/空块校验(不终止进程)。 } -// ---- arith / cmp / cast ---- fn set_arith(self: *IrBuilder, kind: IrKind, tid: usize, left: usize, right: usize): usize { var ref = builder_alloc(self, kind); @@ -211,7 +196,6 @@ fn cast_bool2int(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret se fn case_int2float(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CaseInt2float, f, t, v); } fn case_float2int(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CaseFloat2int, f, t, v); } -// ---- memory ---- fn mem_alloca(self: *IrBuilder, tid: usize, count: usize): usize { var ref = builder_alloc(self, .MemAlloca); @@ -269,7 +253,6 @@ fn mem_set(self: *IrBuilder, tid: usize, dst: usize, val: usize, size: usize): u ret ref; } -// ---- type const ---- fn const_node(self: *IrBuilder, tid: usize, lit: ConstLit): usize { var ref = builder_alloc(self, .TypeConst); @@ -292,7 +275,6 @@ fn add_global(self: *IrBuilder, tid: usize, zero: bool, bytes: Vec): usize { ret Ir.add_global(&self.ir, tid, zero, bytes); } -// ---- type ops ---- fn type_bitsizeof(self: *IrBuilder, tid: usize): usize { var ref = builder_alloc(self, .TypeBitsizeof); @@ -329,7 +311,6 @@ fn type_field_count(self: *IrBuilder, tid: usize): usize { ret ref; } -// ---- agg ---- fn agg_construct(self: *IrBuilder, tid: usize): usize { var ref = builder_alloc(self, .AggConstruct); @@ -343,12 +324,8 @@ fn agg_construct(self: *IrBuilder, tid: usize): usize { fn agg_construct_field(self: *IrBuilder, node_ref: usize, field: usize) { var e = Ir.node(&self.ir, self.current_fn, node_ref); if e == null { ret; } - // 载荷按值绑定:改副本后写回。 match e.body { - .AggConstruct(a) => { - match Vec.push(&a.fields, &field as *u8) { .Ok => {}, .Err(error) => {} } - e.body = .AggConstruct(a); - }, + .AggConstruct(&a) => { Vec.push(&a.fields, &field as *u8); }, _ => {}, } } @@ -369,7 +346,6 @@ fn agg_insert(self: *IrBuilder, tid: usize, field_idx: usize, agg: usize, field: ret ref; } -// ---- control ---- fn control_select(self: *IrBuilder, tid: usize, cond: usize, tv: usize, fv: usize): usize { var ref = builder_alloc(self, .ControlSelect); @@ -388,9 +364,9 @@ fn control_br(self: *IrBuilder, cond: usize): usize { fn control_br_fixup(self: *IrBuilder, ref: usize, true_block: usize, false_block: usize) { var f1 = Fix { .node = ref, .slot = .BrTrue, .block = true_block }; - match Vec.push(&self.fixups, &f1 as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&self.fixups, &f1 as *u8); var f2 = Fix { .node = ref, .slot = .BrFalse, .block = false_block }; - match Vec.push(&self.fixups, &f2 as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&self.fixups, &f2 as *u8); } fn control_jmp(self: *IrBuilder): usize { @@ -403,7 +379,7 @@ fn control_jmp(self: *IrBuilder): usize { fn control_jmp_fixup(self: *IrBuilder, ref: usize, target_block: usize) { var fx = Fix { .node = ref, .slot = .Jmp, .block = target_block }; - match Vec.push(&self.fixups, &fx as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&self.fixups, &fx as *u8); } fn control_call(self: *IrBuilder, tid: usize, fn_ref: usize): usize { @@ -419,12 +395,8 @@ fn control_call(self: *IrBuilder, tid: usize, fn_ref: usize): usize { fn control_call_param(self: *IrBuilder, call_node: usize, arg: usize) { var e = Ir.node(&self.ir, self.current_fn, call_node); if e == null { ret; } - // 载荷按值绑定:改副本后写回。 match e.body { - .Call(c) => { - match Vec.push(&c.params, &arg as *u8) { .Ok => {}, .Err(error) => {} } - e.body = .Call(c); - }, + .Call(&c) => { Vec.push(&c.params, &arg as *u8); }, _ => {}, } } diff --git a/stage2/lang_type.spl b/stage2/lang_type.spl index 1695a38..ffe0d07 100644 --- a/stage2/lang_type.spl +++ b/stage2/lang_type.spl @@ -1,11 +1,7 @@ // Expect retcode = 0 -// 语言类型表(移植自 stage1/spl_lang_type.c):在 IR 类型表(type_table.spl) -// 之上,登记「语言层类型」= IR 类型 id + 语言种类 + 聚合方法表,同样 hash-consing。 -// 另持有声明句柄表(def.spl)与语言类型子类型/求交/字面量适配。 -// -// 语言类型是 sema 的主类型:AST 节点 resolved_lang_tid、def.lang_id 都指这里。 -// 名称/方法名是 ByteView(借用);聚合方法表与 tuple/fn 的载荷 Vec 由本表拥有。 +// 语言类型表:在 IR 类型表之上登记「语言层类型」(IR 类型 id + 种类 + 聚合成员), +// 按结构 hash-consing。sema 的 resolved_lang_tid / def.lang_id 都指向这里。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -77,7 +73,6 @@ type LangTypeResult = enum { Err: Error, } -// ---- 小工具 ---- fn seed(): usize { ret 14695981039346656037; @@ -142,7 +137,6 @@ fn elem_of(entry: LangEntry): usize { ret 0; } -// ---- 生命周期 ---- fn new_entry(kind: LangKind, ir_type_id: usize): LangEntry { ret LangEntry { @@ -215,7 +209,7 @@ fn drop(self: *LangType) { TypeTable.drop(&self.ir); } -// id 0 与越界返回 null(对应 stage1 spl_lang_type_node)。 +// id 0 与越界返回 null。 fn lang_node(self: *LangType, id: usize): *LangEntry { if id == 0 || id >= self.lang_table.len { ret null; } ret (self.lang_table.data as *LangEntry) + id; @@ -231,7 +225,6 @@ fn get_ir_type(self: *LangType, lang_id: usize): usize { ret ir_type(self, lang_id); } -// ---- IR 类型槽位预留(自引用聚合)---- fn reserve_ir(self: *LangType): usize { ret TypeTable.reserve(&self.ir); @@ -241,7 +234,6 @@ fn define_ir(self: *LangType, id: usize, src: *TypeNode) { TypeTable.define(&self.ir, id, src); } -// ---- def 便捷封装(sema 侧只用 LangType)---- fn alloc_def(self: *LangType, kind: DefKind, name: ByteView, span: Span, owner: *any, ast_node_ref: usize): usize { @@ -266,7 +258,6 @@ fn def_is_type(self: *LangType, id: usize): bool { ret DefTable.is_type_kind(d.kind); } -// ---- intern ---- fn free_extra(e: *LangEntry) { match e.extra { @@ -423,10 +414,7 @@ fn fold_insert(self: *LangType, hash: usize, id: usize) { var e = lang_node(self, id); if e == null { ret; } e.hash_next = old; - match Map.put(&self.fold, &hash as *u8, &id as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Map.put(&self.fold, &hash as *u8, &id as *u8); } // intern 一个 probe:命中释放载荷并返回已有 id;否则复制入表。probe 返回后失效。 @@ -460,7 +448,6 @@ fn push_simple(self: *LangType, kind: LangKind, ir: usize): usize { ret push(self, &e); } -// ---- builders ---- fn make_error(self: *LangType): usize { ret push_simple(self, .Error, TypeTable.make_error(&self.ir)); @@ -560,13 +547,10 @@ fn make_range(self: *LangType, elem_lang: usize): usize { ret push(self, &e); } -// 为 tuple 字段生成稳定的十进制名字("0"/"1"/...),镜像 stage1。 +// tuple 字段用稳定的十进制名("0"/"1"/...)。 fn intern_index_name(self: *LangType, value: usize): ByteView { var b = ByteBuffer.new(); - match append_usize(&b, value, 10, false) { - .Ok => {}, - .Err(error) => {}, - } + append_usize(&b, value, 10, false); var view = ByteView.from_slice(ByteBuffer.as_slice(b)); match Vec.push(&self.owned_names, &b as *u8) { .Ok => {}, @@ -646,7 +630,7 @@ fn parse_bits(rest: []u8): usize { ret value; } -// 内置类型名:bool/void/isize/usize/any/iN/uN/fN(对应 stage1 spl_type_lookup_builtin)。 +// 内置类型名:bool/void/isize/usize/any/iN/uN/fN。 fn lookup_builtin(self: *LangType, name: ByteView): usize { if name.len == 0 { ret 0; } if ByteView.eq(name, ByteView.from_slice("bool")) { ret make_bool(self); } @@ -675,7 +659,6 @@ fn lookup_builtin(self: *LangType, name: ByteView): usize { ret 0; } -// ---- IR 位宽读取 ---- fn int_bits(self: *LangType, ir_id: usize): usize { var te = TypeTable.node(&self.ir, ir_id); @@ -707,7 +690,6 @@ fn float_bits(self: *LangType, ir_id: usize): usize { ret 0; } -// ---- 语言层子类型 / 求交 / 字面量适配 ---- fn is_subtype(self: *LangType, sub: usize, super: usize): bool { if sub == 0 || super == 0 { ret false; } @@ -838,7 +820,7 @@ fn int_fits(self: *LangType, target: usize, value: BigInt): bool { .Err(error) => { ret false; }, } - // 镜像 stage1:目标位宽 >= 64 时不做边界检查(其 mpa 只存低 64 位)。 + // 目标位宽 >= 64 时不做边界检查(mpa 只存低 64 位)。 if bits >= 64 { ret true; } var u: u64 = 0; @@ -860,7 +842,6 @@ fn int_fits(self: *LangType, target: usize, value: BigInt): bool { ret false; } -// ---- dump(镜像 stage1 spl_lang_type_dump)---- fn push_out(buf: *ByteBuffer, bytes: []u8): bool { match ByteBuffer.append(buf, bytes) { @@ -898,10 +879,7 @@ fn dump_rec(self: *LangType, id: usize, out: *ByteBuffer, stack: *Vec): bool { if e == null { if !push_out(out, "none") { ret false; } var dropped: usize = 0; - match Vec.pop(stack, &dropped as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.pop(stack, &dropped as *u8); ret true; } @@ -941,7 +919,7 @@ fn dump_rec(self: *LangType, id: usize, out: *ByteBuffer, stack: *Vec): bool { if !push_out(out, "[") { ok = false; } if ok && !push_usize(out, len) { ok = false; } if ok && !push_out(out, "]") { ok = false; } - // 镜像 stage1:数组直接 dump IR 类型(会重复一次 [N])。 + // 数组直接 dump IR 类型(会重复一次 [N])。 if ok { ok = TypeTable.pure_dump(&self.ir, e.ir_type_id, out); } }, .Slice => { @@ -995,10 +973,7 @@ fn dump_rec(self: *LangType, id: usize, out: *ByteBuffer, stack: *Vec): bool { } var dropped2: usize = 0; - match Vec.pop(stack, &dropped2 as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.pop(stack, &dropped2 as *u8); ret ok; } @@ -1008,7 +983,6 @@ fn dump(self: *LangType, id: usize, out: *ByteBuffer): bool { ret dump_rec(self, id, out, &stack); } -// ---- 测试 ---- fn expect_text(buf: ByteBuffer, expected: []u8) { var got = ByteBuffer.as_slice(buf); diff --git a/stage2/layout.spl b/stage2/layout.spl index 959e372..19b2368 100644 --- a/stage2/layout.spl +++ b/stage2/layout.spl @@ -1,9 +1,7 @@ // Expect retcode = 0 -// 目标布局(移植自 stage1/spl_layout.c)。输入是 IR 类型表 TypeTable; -// 为每个类型计算 size_bits / align_bits / 字段位偏移,供 ir2vm 使用。 -// 默认 64 位平台:标量按 1/2/4/8 字节对齐,指针 = usize,聚合按最大字段对齐 -// 且不允许重排(与 stage1 的默认策略一致)。 +// 目标布局:由 IR 类型表计算 size/align/字段位偏移,供 ir2vm 使用。默认 64 位平台, +// 聚合按最大字段对齐且不重排。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -47,7 +45,7 @@ fn info_at(self: *Layout, id: usize): *LayoutInfo { ret (self.infos.data as *LayoutInfo) + id; } -// 未解析或越界返回 null(对应 stage1 spl_layout_info_of)。 +// 未解析或越界返回 null。 fn info_of(self: *Layout, id: usize): *LayoutInfo { var info = info_at(self, id); if info == null || !info.resolved { ret null; } @@ -84,10 +82,7 @@ fn ensure(self: *Layout, n: usize) { } fn push_usize(v: *Vec, x: usize) { - match Vec.push(v, &x as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.push(v, &x as *u8); } fn usize_at(v: *Vec, i: usize): usize { diff --git a/stage2/lexer.spl b/stage2/lexer.spl index ef6dc13..8636142 100644 --- a/stage2/lexer.spl +++ b/stage2/lexer.spl @@ -1,9 +1,7 @@ // Expect retcode = 0 -// 词法分析器:字节流 -> Vec。镜像 stage1/spl_lexer.c 的行为: -// 行注释作为 token 产出;块注释(可嵌套)整体跳过;换行产出 Endline;EOF 产出 Eof。 -// 复用 utils/ascii 做字符分类;整型/字符在词法期解码后放进 TokenKind 载荷。 -// Token.text 借用输入字节,不复制。 +// 字节流 -> Vec。行为镜像 splc0(保证 diff):行注释作为 token 产出,块注释 +//(可嵌套)跳过,换行产 Endline,EOF 产 Eof。Token.text 借用输入,不复制。 type .{ .Vec, .VecResult } = @import("utils/vec.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); @@ -80,7 +78,6 @@ fn decode_char(text: ByteView): u8 { ret e; } -// ---- 读取辅助 ---- fn has2(self: *Lexer, ch: u8): bool { ret self.pos + 1 < self.src.len && self.src.ptr[self.pos + 1] == ch; @@ -120,7 +117,6 @@ fn op3(self: *Lexer, out: *Vec, punct: Punct, start: usize, line: usize, col: us emit_to(self, out, .Punct(punct), start, start + 3, line, col); } -// ---- 复合扫描 ---- fn scan_int(self: *Lexer, out: *Vec, start: usize, line: usize, col: usize) { var p = self.pos; @@ -453,7 +449,6 @@ fn lex(src: ByteView, diag: *Diag, file: usize): VecResult { ret .Ok(out); } -// ---- 测试辅助 ---- fn view(text: []u8): ByteView { ret ByteView.from_slice(text); diff --git a/stage2/mcode.spl b/stage2/mcode.spl index 18f73fa..17dd6b9 100644 --- a/stage2/mcode.spl +++ b/stage2/mcode.spl @@ -1,28 +1,15 @@ // Expect retcode = 0 -// SPL VM 机器码容器(移植自 stage0/spl_mcode.c 的构建/序列化/dump 部分)。 -// 只负责「内存中的 prog」与「写入 .sir」,不包含反序列化(由 C 侧 spl_cli 读)。 -// -// 字符串一律是 ByteView(借用上层 IR/attr 的名称,本模块不复制、不释放); -// gdata 条目是 ByteBuffer,由本模块拥有并释放。 -// -// 二进制格式(元数据字段均为 u64 小端): -// [HEADER] magic(8) nfuncs(8) ninsns(8) nnatives(8) nstrs(8) ndata(8) -// [FUNCS] 每项: name_len(8) name(pad8, 含结尾 NUL) idx_of_strtab(8) -// nargs(8) ninsns(8) address(8) -// [INSTRS] 每项: opcode(2) type(2) imm(8) = 12 字节 -// [NATIVES] 每项: name_len(8) name(pad8, 含结尾 NUL) idx_of_strtab(8) -// [STRTAB] 每项: slen(8) str(pad8) -// [GDATA] 每项: dsize(8) data(pad8) +// VM 字节码容器:内存中的 Prog 与 .sir 序列化(反序列化在 C 侧 spl_cli)。 +// 字符串用 ByteView 借用、不拥有;gdata 条目为 ByteBuffer,由本模块拥有释放。 type .{ .Error, .Status, .make } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .append_usize, .append_i64 } = @import("utils/fmt.spl"); -type Mem = @import("sys/mem.spl"); -type File = @import("sys/file.spl"); -type .{ .open_cstr, .write_all, .read_all } = @import("utils/io.spl"); +type Mem = @import("utils/memory.spl"); +type .{ .open_cstr, .write_all, .read_all, .File } = @import("utils/io.spl"); type Op = enum { Error, @@ -208,7 +195,6 @@ fn kind_name(k: VmKind): []u8 { ret "???"; } -// ---- 生命周期 ---- fn new(): ProgResult { var prog = Prog { @@ -264,7 +250,6 @@ fn drop(self: *Prog) { Vec.drop(&self.insns); } -// ---- 构建 ---- fn add_instr(self: *Prog, op: Op, ty: VmKind, imm: usize): usize { var i = self.insns.len; @@ -306,7 +291,7 @@ fn add_data(self: *Prog, ptr: usize, size: usize): usize { } if size != 0 { if ptr == 0 { ByteBuffer.drop(&entry); ret 0; } - ignore_ptr(Mem.copy(entry.storage.data as *any, ptr as *any, size)); + Mem.copy(entry.storage.data as *any, ptr as *any, size); entry.storage.len = size; } match Vec.push(&self.gdata, &entry as *u8) { @@ -353,7 +338,6 @@ fn get_or_add_native(self: *Prog, name: ByteView): isize { ret (self.natives.len - 1) as isize; } -// ---- dump(输出必须与 stage0 spl_prog_dump 逐字节一致)---- fn out_s(out: *ByteBuffer, s: []u8): bool { match ByteBuffer.append(out, s) { .Ok => { ret true; }, .Err(error) => { ret false; } } @@ -470,21 +454,23 @@ fn dump(self: *Prog, out: *ByteBuffer): bool { if !out_s(out, " ") { ret false; } if !out_i(out, ins.imm as i64) { ret false; } - if @enum2int(ins.opcode) == @enum2int(Op.Jmp) || - @enum2int(ins.opcode) == @enum2int(Op.Bz) || - @enum2int(ins.opcode) == @enum2int(Op.Bnz) { - if !out_s(out, " ; -> ") { ret false; } - if !out_u(out, i + 1 + ins.imm) { ret false; } - } else if @enum2int(ins.opcode) == @enum2int(Op.Call) { - if !out_s(out, " ; nargs=") { ret false; } - if !out_u(out, ins.imm) { ret false; } - if !out_s(out, ", from stack") { ret false; } - } else if @enum2int(ins.opcode) == @enum2int(Op.Calli) { - if !out_s(out, " ; indirect call") { ret false; } - } else if @enum2int(ins.opcode) == @enum2int(Op.Gaddr) { - if !out_s(out, " ; gdata[") { ret false; } - if !out_u(out, ins.imm) { ret false; } - if !out_s(out, "]") { ret false; } + match ins.opcode { + .Jmp, .Bz, .Bnz => { + if !out_s(out, " ; -> ") { ret false; } + if !out_u(out, i + 1 + ins.imm) { ret false; } + }, + .Call => { + if !out_s(out, " ; nargs=") { ret false; } + if !out_u(out, ins.imm) { ret false; } + if !out_s(out, ", from stack") { ret false; } + }, + .Calli => { if !out_s(out, " ; indirect call") { ret false; } }, + .Gaddr => { + if !out_s(out, " ; gdata[") { ret false; } + if !out_u(out, ins.imm) { ret false; } + if !out_s(out, "]") { ret false; } + }, + _ => {}, } if !out_s(out, "\n") { ret false; } i = i + 1; @@ -513,14 +499,13 @@ fn str_at(self: *Prog, i: usize): ByteView { ret ByteView.empty(); } -// ---- 序列化 ---- fn align8(n: usize): usize { ret (n + 7) & (~(7 as usize)); } -// 说明:以下 put_* 直接写入已预留容量的 ByteBuffer 存储(store 已按精确总大小 reserve), -// 跳过 ByteBuffer.append → Vec.append 的校验/拷贝路径。若容量不足会越界,故 store 先校验容量。 +// put_* 直接写入已预留容量的 ByteBuffer 存储(store 已按精确总大小 reserve),跳过 +// append 的校验/拷贝;容量不足会越界,故 store 先校验容量。 fn put_u8(out: *ByteBuffer, b: u8): bool { out.storage.data[out.storage.len] = b; @@ -545,7 +530,7 @@ fn put_u64(out: *ByteBuffer, v: usize): bool { fn put_zeros(out: *ByteBuffer, n: usize): bool { if n != 0 { - ignore_ptr(Mem.set((out.storage.data + out.storage.len) as *any, 0, n)); + Mem.set((out.storage.data + out.storage.len) as *any, 0, n); out.storage.len = out.storage.len + n; } ret true; @@ -602,7 +587,7 @@ fn encode(self: *Prog, out: *ByteBuffer): Status { total = total + 8 + align8(e.storage.len); fi = fi + 1; } - match ByteBuffer.reserve(out, total) { .Ok => {}, .Err(error) => {} } + ByteBuffer.reserve(out, total); if out.storage.cap < total || out.storage.data == null { ret .Err(make(.Io)); } if !put_view(out, ByteView.from_slice("SPLBIN")) { ret .Err(make(.Io)); } @@ -702,10 +687,7 @@ fn serialize(self: *Prog, out: *ByteBuffer): Status { ret encode(self, out); } -fn ignore_ptr(p: *any) {} -fn ignore_usize(v: usize) {} -// ---- 测试 ---- fn test_dump_basic() { var pr: Prog = undefined; @@ -715,7 +697,7 @@ fn test_dump_basic() { } defer { drop(&pr); } - ignore_usize(add_instr(&pr, .Halt, .Void, 0)); + add_instr(&pr, .Halt, .Void, 0); var out = ByteBuffer.new(); defer { ByteBuffer.drop(&out); } @@ -763,8 +745,8 @@ fn test_store_roundtrip() { } defer { drop(&pr); } - ignore_usize(add_func(&pr, ByteView.from_slice("main"), 0, 0)); - ignore_usize(add_instr(&pr, .Halt, .Void, 0)); + add_func(&pr, ByteView.from_slice("main"), 0, 0); + add_instr(&pr, .Halt, .Void, 0); var path = ByteView.from_slice("build/_mcode_roundtrip.tmp"); match store(&pr, path) { diff --git a/stage2/parser.spl b/stage2/parser.spl index 02e7c9c..f107f11 100644 --- a/stage2/parser.spl +++ b/stage2/parser.spl @@ -1,7 +1,6 @@ // Expect retcode = 0 -// Parser:token 流 -> Ast(ADT 节点)。C 版只作控制流参考,节点分配顺序需与 stage1 -// 一致,以保证 dump 的 #ref 可对比。pos 在 token 向量上移动,自动跳过 trivia。 +// token 流 -> Ast。节点分配顺序必须与 splc0 一致,否则 dump 的 #ref 无法逐字节对比。 type .{ .Vec } = @import("utils/vec.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); @@ -41,7 +40,6 @@ fn new(ast: *Ast, toks: Vec, diag: *Diag): Parser { }; } -// ---- token 访问 ---- fn token_ptr(self: *Parser, index: usize): *Token { if index >= self.toks.len { ret null; } @@ -138,7 +136,6 @@ fn at_eof(self: *Parser): bool { ret false; } -// ---- 错误 ---- fn span_of(self: *Parser, tok: *Token): Span { if tok == null { ret span_none(); } @@ -151,7 +148,7 @@ fn parse_error(self: *Parser, tok: *Token, what: []u8) { Diag.err(self.diag, span_of(self, tok), .ParseExpected, what); } -// 转义解码(镜像 stage1 spl_decode_escape):去掉引号,处理 \n \t \r \0 \\ \' \" \xHH。 +// 转义解码:去掉引号,处理 \n \t \r \0 \\ \' \" \xHH。 fn hex_digit(c: u8): u8 { if c >= '0' && c <= '9' { ret c - '0'; } if c >= 'a' && c <= 'f' { ret (c - 'a') + 10; } @@ -172,9 +169,7 @@ fn decode_str(t: ByteView): ByteBuffer { if e == 'x' && i + 3 < end { var hi = hex_digit(t.ptr[i + 2]); var lo = hex_digit(t.ptr[i + 3]); - match ByteBuffer.append_byte(&out, (hi * 16 + lo) as u8) { - .Ok => {}, .Err(error) => {}, - } + ByteBuffer.append_byte(&out, (hi * 16 + lo) as u8); i = i + 4; } else { var d: u8 = e; @@ -182,11 +177,11 @@ fn decode_str(t: ByteView): ByteBuffer { else if e == 't' { d = '\t'; } else if e == 'r' { d = '\r'; } else if e == '0' { d = 0; } - match ByteBuffer.append_byte(&out, d) { .Ok => {}, .Err(error) => {} } + ByteBuffer.append_byte(&out, d); i = i + 2; } } else { - match ByteBuffer.append_byte(&out, c) { .Ok => {}, .Err(error) => {} } + ByteBuffer.append_byte(&out, c); i = i + 1; } } @@ -203,7 +198,6 @@ fn expect_punct(self: *Parser, punct: Punct, what: []u8): bool { ret true; } -// ---- 节点 ---- fn new_node(self: *Parser, body: Body, tok: *Token): usize { ret Ast.alloc(self.ast, body, span_of(self, tok)); @@ -262,7 +256,6 @@ fn int_token_u64(self: *Parser, tok: *Token, radix: Radix): u64 { ret v; } -// ---- 判定(stage1 can_start_*)---- fn can_start_expr(kind: TokenKind): bool { match kind { @@ -335,11 +328,10 @@ fn can_start_statement(kind: TokenKind): bool { ret false; } -// ---- 模式(M3.2 子集:ident / _ / .variant / tuple / .{ } )---- fn parse_pattern_aggregate(self: *Parser, start: *Token): usize { if !expect_punct(self, .LBrace, "'{' after '.'") { ret 0; } - // stage1 先分配 PATTERN_AGGREGATE,再解析字段。 + // 先分配 PATTERN_AGGREGATE,再解析字段。 var ref = new_node(self, .PatternAggregate(.{ .items = ref_vec() }), start); var fields = ref_vec(); while !self.failed { @@ -354,7 +346,7 @@ fn parse_pattern_aggregate(self: *Parser, start: *Token): usize { if name == null { break; } match name.kind { .Ident => {}, _ => { break; } } advance(self); - // stage1 先分配 PATTERN_FIELD,再解析可选子模式。 + // 先分配 PATTERN_FIELD,再解析可选子模式。 var fre = new_node(self, .PatternField(.{ .name = name.text, .pattern = 0, @@ -449,7 +441,7 @@ fn parse_pattern_atom(self: *Parser): usize { if nx == null { ret 0; } match nx.kind { .Ident => {}, _ => { ret 0; } } advance(self); - // stage1 先分配 PATTERN_DOT,再解析子模式。 + // 先分配 PATTERN_DOT,再解析子模式。 var ref = new_node(self, .PatternDot(.{ .name = nx.text, .sub_pattern = 0, @@ -472,7 +464,7 @@ fn parse_pattern_atom(self: *Parser): usize { }, .LParen => { advance(self); - // stage1 先分配 PATTERN_TUPLE,再解析内部模式。 + // 先分配 PATTERN_TUPLE,再解析内部模式。 var ref = new_node(self, .PatternTuple(.{ .items = ref_vec() }), t); if at_punct(self, .RParen) { advance(self); @@ -562,7 +554,6 @@ fn parse_pattern(self: *Parser): usize { ret new_node(self, .PatternList(.{ .items = atoms }), peek(self)); } -// ---- 声明 ---- fn parse_tag_list(self: *Parser, out: *Vec, is_external: bool, allow_at: bool, bang_only: bool) { while !self.failed { @@ -593,7 +584,7 @@ fn parse_tag_list(self: *Parser, out: *Vec, is_external: bool, allow_at: bool, b if t == null { ret; } match t.kind { .Ident => {}, _ => { parse_error(self, t, "expected tag name"); ret; } } advance(self); - // stage1 先分配 tag 节点,再解析参数。 + // 先分配 tag 节点,再解析参数。 var body: Body = .TagItem(.{ .is_at = is_at, .is_external = ext_here, @@ -724,20 +715,16 @@ fn token_starts_type(t: *Token): bool { match t.kind { .Ident => { ret true; }, .Keyword(k) => { - if @enum2int(k) == @enum2int(Keyword.Type) { ret true; } - if @enum2int(k) == @enum2int(Keyword.Bool) { ret true; } - if @enum2int(k) == @enum2int(Keyword.Any) { ret true; } - if @enum2int(k) == @enum2int(Keyword.Fn) { ret true; } - if @enum2int(k) == @enum2int(Keyword.Struct) { ret true; } - if @enum2int(k) == @enum2int(Keyword.Union) { ret true; } - if @enum2int(k) == @enum2int(Keyword.Enum) { ret true; } - if @enum2int(k) == @enum2int(Keyword.Shape) { ret true; } + match k { + .Type, .Bool, .Any, .Fn, .Struct, .Union, .Enum, .Shape => { ret true; }, + _ => {}, + } }, .Punct(p) => { - if @enum2int(p) == @enum2int(Punct.Mul) { ret true; } - if @enum2int(p) == @enum2int(Punct.LBracket) { ret true; } - if @enum2int(p) == @enum2int(Punct.At) { ret true; } - if @enum2int(p) == @enum2int(Punct.Sharp) { ret true; } + match p { + .Mul, .LBracket, .At, .Sharp => { ret true; }, + _ => {}, + } }, _ => {}, } @@ -795,7 +782,7 @@ fn parse_type_decl(self: *Parser, tags: Vec): usize { var pattern = parse_pattern(self); if pattern == 0 { ret 0; } if !expect_punct(self, .Assign, "'=' in type declaration") { ret 0; } - // stage1 先分配 TYPE_DECL 再解析 type_expr(影响 #ref 顺序)。 + // 先分配 TYPE_DECL 再解析 type_expr(影响 #ref 顺序)。 var ref = new_node(self, .TypeDecl(.{ .attr_list = tags, .pattern = pattern, @@ -913,32 +900,33 @@ fn parse_container_declaration(self: *Parser): usize { match t.kind { .Eof => { ret 0; }, .Keyword(k) => { - if @enum2int(k) == @enum2int(Keyword.Fn) { ret parse_fn_decl(self, tags, false); } - if @enum2int(k) == @enum2int(Keyword.Type) { ret parse_type_decl(self, tags); } - if @enum2int(k) == @enum2int(Keyword.Var) { - ret parse_var_const_decl(self, tags, false); - } - if @enum2int(k) == @enum2int(Keyword.Const) { - ret parse_var_const_decl(self, tags, true); - } - if @enum2int(k) == @enum2int(Keyword.Comptime) { - // `comptime fn ...` -> 标记为编译期函数;否则 `comptime { }` 声明。 - var nxt = peek_next(self); - if nxt != null && kind_is_keyword(nxt.kind, .Fn) { - advance(self); - ret parse_fn_decl(self, tags, true); - } - ret parse_comptime_decl(self); + match k { + .Fn => { ret parse_fn_decl(self, tags, false); }, + .Type => { ret parse_type_decl(self, tags); }, + .Var => { ret parse_var_const_decl(self, tags, false); }, + .Const => { ret parse_var_const_decl(self, tags, true); }, + .Comptime => { + var nxt = peek_next(self); + if nxt != null && kind_is_keyword(nxt.kind, .Fn) { + advance(self); + ret parse_fn_decl(self, tags, true); + } + ret parse_comptime_decl(self); + }, + _ => {}, } }, .Ident => { ret parse_member_decl(self, tags); }, .Punct(p) => { - if @enum2int(p) == @enum2int(Punct.LBrace) { - var block = parse_block(self); - ret new_node(self, .TopLevelBlock(.{ - .tag_list = tags, - .block = block, - }), t); + match p { + .LBrace => { + var block = parse_block(self); + ret new_node(self, .TopLevelBlock(.{ + .tag_list = tags, + .block = block, + }), t); + }, + _ => {}, } }, _ => {}, @@ -948,7 +936,6 @@ fn parse_container_declaration(self: *Parser): usize { ret 0; } -// ---- 类型 ---- fn parse_type_comptime_call(self: *Parser): usize { var start = peek(self); @@ -977,7 +964,7 @@ fn parse_type_base(self: *Parser): usize { if kind_is_keyword(bt.kind, .Fn) { advance(self); if !expect_punct(self, .LParen, "'(' in function type") { ret 0; } - // stage1 先分配 TYPE_FN,再解析参数与返回类型。 + // 先分配 TYPE_FN,再解析参数与返回类型。 var ref = new_node(self, .TypeFn(.{ .is_comptime = false, .params = ref_vec(), @@ -1011,10 +998,13 @@ fn parse_type_base(self: *Parser): usize { match bt.kind { .Keyword(k) => { var kind_name: []u8 = ""; - if @enum2int(k) == @enum2int(Keyword.Struct) { kind_name = "struct"; } - else if @enum2int(k) == @enum2int(Keyword.Union) { kind_name = "union"; } - else if @enum2int(k) == @enum2int(Keyword.Enum) { kind_name = "enum"; } - else if @enum2int(k) == @enum2int(Keyword.Shape) { kind_name = "shape"; } + match k { + .Struct => { kind_name = "struct"; }, + .Union => { kind_name = "union"; }, + .Enum => { kind_name = "enum"; }, + .Shape => { kind_name = "shape"; }, + _ => {}, + } if kind_name.len != 0 { advance(self); if !expect_punct(self, .LBrace, "'{' in aggregate type") { ret 0; } @@ -1088,20 +1078,21 @@ fn parse_type_base(self: *Parser): usize { }), bt); }, .Keyword(k) => { - // stage1 is_builtin_type_kw:bool / any 作为类型路径;stage3 增加 `type`。 - if @enum2int(k) == @enum2int(Keyword.Bool) || - @enum2int(k) == @enum2int(Keyword.Any) || - @enum2int(k) == @enum2int(Keyword.Type) { - advance(self); - ret new_node(self, .TypePath(.{ - .name = bt.text, - .generic_args = ref_vec(), - }), bt); + match k { + .Bool, .Any, .Type => { + advance(self); + ret new_node(self, .TypePath(.{ + .name = bt.text, + .generic_args = ref_vec(), + }), bt); + }, + _ => {}, } }, .Punct(p) => { - if @enum2int(p) == @enum2int(Punct.At) || @enum2int(p) == @enum2int(Punct.Sharp) { - ret parse_type_comptime_call(self); + match p { + .At, .Sharp => { ret parse_type_comptime_call(self); }, + _ => {}, } }, _ => {}, @@ -1116,7 +1107,7 @@ fn parse_type_expr(self: *Parser): usize { if kind_is_punct(t.kind, .Mul) { advance(self); - // stage1 先分配 POINTER,再解析 pointee。 + // 先分配 POINTER,再解析 pointee。 var ref = new_node(self, .TypePointer(.{ .pointee = 0 }), t); var pointee = parse_type_expr(self); var pn = Ast.node(self.ast, ref); @@ -1200,7 +1191,6 @@ fn parse_type_expr(self: *Parser): usize { ret base; } -// ---- 表达式 ---- type BinInfo = struct { op: Punct, prec: i32, right: bool } type BinResult = enum { No, Yes: BinInfo } @@ -1367,7 +1357,7 @@ fn parse_postfix(self: *Parser): usize { if kind_is_punct(t.kind, .LParen) { advance(self); - // stage1 先分配 CALL,再解析实参(影响 #ref 顺序)。 + // 先分配 CALL,再解析实参(影响 #ref 顺序)。 var ref = new_node(self, .ExprCall(.{ .callee = expr, .args = ref_vec() }), t); var args = parse_expr_list(self); var cn = Ast.node(self.ast, ref); @@ -1480,47 +1470,31 @@ fn parse_primary(self: *Parser): usize { ret new_node(self, .ExprStringLit(.{ .data = Ast.push_string(self.ast, decode_str(t.text)) }), t); }, .Keyword(k) => { - if @enum2int(k) == @enum2int(Keyword.True) { - advance(self); - ret new_node(self, .ExprBoolLit(.{ .value = true }), t); - } - if @enum2int(k) == @enum2int(Keyword.False) { - advance(self); - ret new_node(self, .ExprBoolLit(.{ .value = false }), t); - } - if @enum2int(k) == @enum2int(Keyword.Null) { - advance(self); - ret new_node(self, .ExprNullLit, t); - } - if @enum2int(k) == @enum2int(Keyword.Undefined) { - advance(self); - ret new_node(self, .ExprUndefinedLit, t); - } - if @enum2int(k) == @enum2int(Keyword.If) { ret parse_if_expr(self); } - if @enum2int(k) == @enum2int(Keyword.While) { ret parse_while_expr(self); } - 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); - var cbody = parse_expr(self); - ret new_node(self, .ExprComptime(.{ .body = cbody }), t); - } - // 类型即表达式:仅在 comptime 上下文内允许 `struct { ... }` 等聚合类型。 - if self.comptime_depth > 0 { - if @enum2int(k) == @enum2int(Keyword.Struct) || - @enum2int(k) == @enum2int(Keyword.Union) || - @enum2int(k) == @enum2int(Keyword.Enum) || - @enum2int(k) == @enum2int(Keyword.Shape) { - ret parse_type_base(self); - } + match k { + .True => { advance(self); ret new_node(self, .ExprBoolLit(.{ .value = true }), t); }, + .False => { advance(self); ret new_node(self, .ExprBoolLit(.{ .value = false }), t); }, + .Null => { advance(self); ret new_node(self, .ExprNullLit, t); }, + .Undefined => { advance(self); ret new_node(self, .ExprUndefinedLit, t); }, + .If => { ret parse_if_expr(self); }, + .While => { ret parse_while_expr(self); }, + .Loop => { ret parse_loop_expr(self); }, + .For => { ret parse_for_expr(self); }, + .Match => { ret parse_match_expr(self); }, + .Try => { + advance(self); + var tv = parse_expr(self); + ret new_node(self, .ExprTry(.{ .value = tv }), t); + }, + .Comptime => { + advance(self); + var cbody = parse_expr(self); + ret new_node(self, .ExprComptime(.{ .body = cbody }), t); + }, + .Struct, .Union, .Enum, .Shape => { + // 类型即表达式仅限 comptime 上下文。 + if self.comptime_depth > 0 { ret parse_type_base(self); } + }, + _ => {}, } parse_error(self, t, "unrecognized expression"); ret 0; @@ -1528,7 +1502,7 @@ fn parse_primary(self: *Parser): usize { .Ident => { advance(self); if at_punct(self, .LBrace) && self.stop_agg == 0 { - // stage1 先分配 AGGREGATE_LIT,再解析字段。 + // 先分配 AGGREGATE_LIT,再解析字段。 var ref = new_node(self, .ExprAggregateLit(.{ .name = t.text, .fields = ref_vec(), @@ -1536,10 +1510,7 @@ fn parse_primary(self: *Parser): usize { var fields = parse_aggregate_fields(self); var an = Ast.node(self.ast, ref); match an.body { - .ExprAggregateLit(a) => { - a.fields = fields; - an.body = .ExprAggregateLit(a); - }, + .ExprAggregateLit(&a) => { a.fields = fields; }, _ => {}, } ret ref; @@ -1547,71 +1518,69 @@ fn parse_primary(self: *Parser): usize { ret new_node(self, .ExprIdent(.{ .name = t.text }), t); }, .Punct(p) => { - if @enum2int(p) == @enum2int(Punct.Dot) { - advance(self); - var nx = peek(self); - if nx == null { parse_error(self, t, "unexpected '.'"); ret 0; } - if kind_is_punct(nx.kind, .LBrace) && self.stop_agg == 0 { - var ref = new_node(self, .ExprAggregateLit(.{ - .name = ByteView.empty(), - .fields = ref_vec(), - }), t); - var fields = parse_aggregate_fields(self); - var an = Ast.node(self.ast, ref); - match an.body { - .ExprAggregateLit(a) => { - a.fields = fields; - an.body = .ExprAggregateLit(a); - }, - _ => {}, + match p { + .Dot => { + advance(self); + var nx = peek(self); + if nx == null { parse_error(self, t, "unexpected '.'"); ret 0; } + if kind_is_punct(nx.kind, .LBrace) && self.stop_agg == 0 { + var ref = new_node(self, .ExprAggregateLit(.{ + .name = ByteView.empty(), + .fields = ref_vec(), + }), t); + var fields = parse_aggregate_fields(self); + var an = Ast.node(self.ast, ref); + match an.body { + .ExprAggregateLit(&a) => { a.fields = fields; }, + _ => {}, + } + ret ref; } - ret ref; - } - if kind_is_punct(nx.kind, .LBracket) { - advance(self); - var elems = parse_expr_list(self); - if !expect_punct(self, .RBracket, "']' in array literal") { ret 0; } - ret new_node(self, .ExprArrayLit(.{ - .has_len = false, - .len = 0, - .is_underscore_len = false, - .elem_type = 0, - .elems = elems, - }), t); - } - var is_ident = false; - match nx.kind { .Ident => { is_ident = true; }, _ => {} } - if is_ident { ret parse_variant_construct(self, t); } - parse_error(self, nx, "expected '{', '[' or identifier after '.'"); - ret 0; - } - if @enum2int(p) == @enum2int(Punct.LBracket) { ret parse_array_literal(self); } - if @enum2int(p) == @enum2int(Punct.LBrace) { ret parse_block(self); } - if @enum2int(p) == @enum2int(Punct.At) || @enum2int(p) == @enum2int(Punct.Sharp) { - ret parse_comptime_call(self); - } - if @enum2int(p) == @enum2int(Punct.LParen) { - advance(self); - var elems = ref_vec(); - if at_punct(self, .RParen) { - advance(self); - ret new_node(self, .ExprTuple(.{ .items = elems }), t); - } - var first = parse_expr(self); - if at_punct(self, .Comma) { - match Vec.push(&elems, &first as *u8) { .Ok => {}, .Err(e) => { ret 0; } } - while at_punct(self, .Comma) { + if kind_is_punct(nx.kind, .LBracket) { advance(self); - if at_punct(self, .RParen) { break; } - var nx = parse_expr(self); - match Vec.push(&elems, &nx as *u8) { .Ok => {}, .Err(e) => { ret 0; } } + var elems = parse_expr_list(self); + if !expect_punct(self, .RBracket, "']' in array literal") { ret 0; } + ret new_node(self, .ExprArrayLit(.{ + .has_len = false, + .len = 0, + .is_underscore_len = false, + .elem_type = 0, + .elems = elems, + }), t); } - expect_punct(self, .RParen, "')' in tuple literal"); - ret new_node(self, .ExprTuple(.{ .items = elems }), t); - } - expect_punct(self, .RParen, "')' in paren expression"); - Vec.drop(&elems); - ret first; + var is_ident = false; + match nx.kind { .Ident => { is_ident = true; }, _ => {} } + if is_ident { ret parse_variant_construct(self, t); } + parse_error(self, nx, "expected '{', '[' or identifier after '.'"); + ret 0; + }, + .LBracket => { ret parse_array_literal(self); }, + .LBrace => { ret parse_block(self); }, + .At, .Sharp => { ret parse_comptime_call(self); }, + .LParen => { + advance(self); + var elems = ref_vec(); + if at_punct(self, .RParen) { + advance(self); + ret new_node(self, .ExprTuple(.{ .items = elems }), t); + } + var first = parse_expr(self); + if at_punct(self, .Comma) { + Vec.push(&elems, &first as *u8); + while at_punct(self, .Comma) { + advance(self); + if at_punct(self, .RParen) { break; } + var nx = parse_expr(self); + Vec.push(&elems, &nx as *u8); + } + expect_punct(self, .RParen, "')' in tuple literal"); + ret new_node(self, .ExprTuple(.{ .items = elems }), t); + } + expect_punct(self, .RParen, "')' in paren expression"); + Vec.drop(&elems); + ret first; + }, + _ => {}, } }, _ => {}, @@ -1761,7 +1730,6 @@ fn parse_expr_list(self: *Parser): Vec { ret vec; } -// ---- if / while / loop / for / match ---- fn parse_if_expr(self: *Parser): usize { var kw = peek(self); @@ -1928,7 +1896,7 @@ fn parse_match_expr(self: *Parser): usize { if at_punct(self, .Comma) { advance(self); } } if !expect_punct(self, .RBrace, "'}' in match") { ret 0; } - // stage1 先分配 MATCH_EXPR,再逐个分配 MATCH_ARM。 + // 先分配 MATCH_EXPR,再逐个分配 MATCH_ARM。 var ref = new_node(self, .ExprMatch(.{ .matched_expr = matched, .arms = ref_vec(), @@ -1957,7 +1925,6 @@ fn parse_match_expr(self: *Parser): usize { ret ref; } -// ---- 语句 ---- fn parse_ret_stmt(self: *Parser): usize { var kw = peek(self); @@ -2054,27 +2021,26 @@ fn parse_statement(self: *Parser): usize { match t.kind { .Keyword(k) => { - if @enum2int(k) == @enum2int(Keyword.Ret) { ret parse_ret_stmt(self); } - 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) || - @enum2int(k) == @enum2int(Keyword.Type) { - var tags = ref_vec(); - parse_tag_list(self, &tags, false, false, false); - var decl: usize = 0; - if @enum2int(k) == @enum2int(Keyword.Var) { - decl = parse_var_const_decl(self, tags, false); - } else if @enum2int(k) == @enum2int(Keyword.Const) { - decl = parse_var_const_decl(self, tags, true); - } else { - decl = parse_type_decl(self, tags); - } - if decl == 0 { ret 0; } - ret new_node(self, .StatementDecl(.{ .decl = decl }), t); + match k { + .Ret => { ret parse_ret_stmt(self); }, + .Break => { ret parse_break_stmt(self); }, + .Continue => { ret parse_continue_stmt(self); }, + .Defer => { ret parse_defer_stmt(self); }, + .Errdefer => { ret parse_errdefer_stmt(self); }, + .Comptime => { ret parse_comptime_stmt(self); }, + .Var, .Const, .Type => { + var tags = ref_vec(); + parse_tag_list(self, &tags, false, false, false); + var decl: usize = 0; + match k { + .Var => { decl = parse_var_const_decl(self, tags, false); }, + .Const => { decl = parse_var_const_decl(self, tags, true); }, + _ => { decl = parse_type_decl(self, tags); }, + } + if decl == 0 { ret 0; } + ret new_node(self, .StatementDecl(.{ .decl = decl }), t); + }, + _ => {}, } }, _ => {}, @@ -2179,7 +2145,7 @@ fn block_push_stmt(self: *Parser, ref: usize, stmt: usize) { var n = Ast.node(self.ast, ref); match n.body { .ExprBlock(b) => { - match Vec.push(&b.stmts, &stmt as *u8) { .Ok => {}, .Err(e) => {} } + Vec.push(&b.stmts, &stmt as *u8); n.body = .ExprBlock(b); }, _ => {}, @@ -2200,7 +2166,6 @@ fn block_set_tail(self: *Parser, ref: usize, expr: usize) { } } -// ---- 入口 ---- fn skip_to_sync(self: *Parser) { while !self.failed { @@ -2215,7 +2180,7 @@ fn skip_to_sync(self: *Parser) { } } -// 解析整个文件;Root/ContainerMembers 最后分配(与 stage1 一致)。 +// 解析整个文件;Root/ContainerMembers 最后分配(#ref 顺序须与 splc0 一致)。 fn parse(self: *Parser) { var external_tags = ref_vec(); var declarations = ref_vec(); @@ -2258,7 +2223,6 @@ fn parse(self: *Parser) { self.ast.root = root; } -// ---- 测试 ---- fn lex_tokens(src: []u8): Vec { var out = Vec.blank(@sizeof(Token), @alignof(Token)); @@ -2322,7 +2286,7 @@ fn expect_text(buf: *ByteBuffer, expected: []u8) { } } -// 与 stage1 `splc0 --dump ast` 输出逐字节一致(含 #ref 与 [line:col])。 +// 与 splc0 --dump ast 逐字节一致(含 #ref 与 [line:col])。 fn test_parse_decls() { var src: []u8 = "type Point = struct { x: i32, y: i32 };\nfn f(a: i32): i32;\n"; var toks = lex_tokens(src); @@ -2354,7 +2318,7 @@ fn test_parse_decls() { "AST:\n`-root #13\n `-container_members #12\n |-type_decl #2 [1:1]\n | |-pattern_ident #1 [1:6]\n | `-type_aggregate #3 [1:14]\n | |-member_decl #5 [1:23]\n | | |-type_path #4 [1:26]\n | `-member_decl #7 [1:31]\n | |-type_path #6 [1:34]\n `-fn_decl #11 [2:1]\n `-param_decl #9 [2:6]\n `-type_path #8 [2:9]\n |-type_path #10 [2:15]\n"); } -// 表达式/语句/块:与 001_main.spl 的 stage1 dump 逐字节一致。 +// 表达式/语句/块:与 splc0 dump 逐字节一致。 fn test_parse_main() { var src: []u8 = "// Expect retcode = 0\n\nfn main(): i32 {\n ret 0;\n}\n"; var toks = lex_tokens(src); @@ -2386,7 +2350,7 @@ fn test_parse_main() { "AST:\n`-root #7\n `-container_members #6\n `-fn_decl #5 [3:1]\n |-type_path #1 [3:12]\n `-block #2 [3:16]\n `-statement_ret #4 [4:5]\n `-int_lit #3 [4:9]\n"); } -// 任意宽度整数:2^64 也能正确解析(stage1 u64 之外);含分隔符与多进制。 +// 任意宽度整数:2^64 也能正确解析;含分隔符与多进制。 fn check_int(src: []u8, expected: []u8) { var toks = lex_tokens(src); defer { Vec.drop(&toks); } diff --git a/stage2/scope.spl b/stage2/scope.spl index f28fd94..0c71f06 100644 --- a/stage2/scope.spl +++ b/stage2/scope.spl @@ -1,9 +1,7 @@ // Expect retcode = 0 -// 作用域树(移植自 stage1/spl_scope.c)。每个作用域是一张名字 -> Symbol 表, -// 节点用 parent 指向父作用域;查找从 current_scope 沿父链上溯(支持遮蔽)。 -// 名字是 ByteView(借用源/AST);Map 复制键值字节,但 ByteView 指向的字节由 -// 调用方保证存活。node 字段是 def.spl 的 DefId。 +// 作用域树:名字 -> Symbol,节点经 parent 上溯查找(支持遮蔽)。名字借用源字节, +// 存活由调用方保证;node 为 def.spl 的 DefId。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -134,7 +132,6 @@ fn find(self: *Scope, name: ByteView, out: *Symbol): bool { ret false; } -// ---- 测试 ---- fn sym(name: []u8, kind: SymbolKind, node: usize): Symbol { ret Symbol { diff --git a/stage2/sema.spl b/stage2/sema.spl index 4ec32d0..cb1b052 100644 --- a/stage2/sema.spl +++ b/stage2/sema.spl @@ -1,11 +1,7 @@ // Expect retcode = 0 -// 语义分析(移植自 stage1/spl_sema.c)。持有语言类型表 / 作用域树 / 属性表 / -// comptime 接口;AST 与诊断是借用。阶段:collect_names -> collect_type_unpacks -// -> 模块根聚合 -> collect_types -> collect_signatures -> infer。 -// -// 与 stage1 的差异:诊断消息从简(不逐字复刻);类型系统/def/scope/attr/intrin -// 全部走 stage2 模块;comptime 只走 eval seam(本轮不求值,返回 NotConst)。 +// 语义分析:名字/类型/def 解析与推断。持有类型表、作用域树、属性表;AST 与诊断 +// 为借用。comptime 求值经 eval seam 注入。 type .{ .Error, .Status } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -34,7 +30,7 @@ type .{ .Lexer } = @import("./lexer.spl"); type .{ .Parser } = @import("./parser.spl"); type .{ .set_new, .set_add, .set_drop } = @import("utils/source.spl"); -// 模块加载接口(seam):驱动提供;本轮可为 null。 +// 模块加载接口(seam):由驱动提供;可为 null。 type LoadResult = enum { Ok: *Ast, Missing, @@ -66,7 +62,6 @@ type SemaResult = enum { Err: Error, } -// ---- 小工具 ---- fn list_at(v: Vec, i: usize): usize { if i >= v.len { ret 0; } @@ -74,17 +69,11 @@ fn list_at(v: Vec, i: usize): usize { } fn push_u(v: *Vec, x: usize) { - match Vec.push(v, &x as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.push(v, &x as *u8); } fn push_view(v: *Vec, x: ByteView) { - match Vec.push(v, &x as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.push(v, &x as *u8); } fn ref_vec(): Vec { @@ -138,7 +127,7 @@ fn lang_from_ir(self: *Sema, ir: usize): usize { while i < self.types.lang_table.len { var e = LangType.lang_node(&self.types, i); if e != null && e.ir_type_id == ir { - match Map.put(&self.ir_to_lang, &ir as *u8, &i as *u8) { .Ok => {}, .Err(error) => {} } + Map.put(&self.ir_to_lang, &ir as *u8, &i as *u8); ret i; } i = i + 1; @@ -163,7 +152,6 @@ fn def_state_is(d: *DefNode, want: DeclState): bool { ret @enum2int(d.state) == @enum2int(want); } -// ---- 诊断(消息从简;类型名走 dump 到缓冲)---- fn diag(self: *Sema, span: Span, code: Code, msg: []u8) { Diag.err(self.diag, span, code, msg); @@ -172,15 +160,15 @@ fn diag(self: *Sema, span: Span, code: Code, msg: []u8) { fn diag_name(self: *Sema, span: Span, code: Code, prefix: []u8, name: ByteView) { var b = ByteBuffer.new(); defer { ByteBuffer.drop(&b); } - match ByteBuffer.append(&b, prefix) { .Ok => {}, .Err(e) => {} } - match ByteBuffer.append(&b, ByteView.as_slice(name)) { .Ok => {}, .Err(e) => {} } + ByteBuffer.append(&b, prefix); + ByteBuffer.append(&b, ByteView.as_slice(name)); Diag.err(self.diag, span, code, ByteBuffer.as_slice(b)); } fn diag_ty(self: *Sema, span: Span, code: Code, prefix: []u8, tid: usize) { var b = ByteBuffer.new(); defer { ByteBuffer.drop(&b); } - match ByteBuffer.append(&b, prefix) { .Ok => {}, .Err(e) => {} } + ByteBuffer.append(&b, prefix); LangType.dump(&self.types, tid, &b); Diag.err(self.diag, span, code, ByteBuffer.as_slice(b)); } @@ -188,14 +176,13 @@ fn diag_ty(self: *Sema, span: Span, code: Code, prefix: []u8, tid: usize) { fn diag_ty2(self: *Sema, span: Span, code: Code, prefix: []u8, a: usize, b: usize) { var buf = ByteBuffer.new(); defer { ByteBuffer.drop(&buf); } - match ByteBuffer.append(&buf, prefix) { .Ok => {}, .Err(e) => {} } + ByteBuffer.append(&buf, prefix); LangType.dump(&self.types, a, &buf); - match ByteBuffer.append(&buf, " vs ") { .Ok => {}, .Err(e) => {} } + ByteBuffer.append(&buf, " vs "); LangType.dump(&self.types, b, &buf); Diag.err(self.diag, span, code, ByteBuffer.as_slice(buf)); } -// ---- 生命周期 ---- fn new(ast: *Ast, diag: *Diag): SemaResult { var types: LangType = undefined; @@ -244,7 +231,6 @@ fn drop(self: *Sema) { LangType.drop(&self.types); } -// ---- 作用域 ---- fn push_scope(self: *Sema) { var id = Scope.alloc(&self.scope); @@ -258,7 +244,6 @@ fn pop_scope(self: *Sema) { } } -// ---- 属性 ---- fn node_attr_raw(self: *Sema, n: *Node, raw: Vec) { var i: usize = 0; @@ -312,17 +297,17 @@ fn resolve_attr_item(self: *Sema, a: *Node): usize { match arg.body { .ExprIdent(e) => { var av: AttrArg = .Str(e.name); - match Vec.push(&args, &av as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(&args, &av as *u8); }, .ExprStringLit(sl) => { var av: AttrArg = .Str(sl.data); - match Vec.push(&args, &av as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(&args, &av as *u8); }, .ExprIntLit(iv) => { var num: i64 = 0; - match BigInt.to_i64(&num, iv.value) { .Ok => {}, .Err(er) => {} } + BigInt.to_i64(&num, iv.value); var av: AttrArg = .Int(num); - match Vec.push(&args, &av as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(&args, &av as *u8); }, _ => { diag(self, arg.span, .UnknownAttr, "unsupported attribute arg"); @@ -348,7 +333,6 @@ fn resolve_attrs(self: *Sema, n: *Node) { } } -// ---- 聚合构建 ---- fn build_aggregate(self: *Sema, te: *Node, owner_def_id: usize): usize { var kind_name = ByteView.empty(); @@ -403,7 +387,7 @@ fn build_aggregate(self: *Sema, te: *Node, owner_def_id: usize): usize { if md.type_expr != 0 { mtid = infer(self, md.type_expr); } var mm = Member { .name = md.name, .type_id = ir_of(self, mtid), .ast_node_ref = mref }; - match Vec.push(&members, &mm as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(&members, &mm as *u8); }, .FnDecl(fd) => { var fn_def = mn.resolved_def_id; @@ -415,7 +399,7 @@ fn build_aggregate(self: *Sema, te: *Node, owner_def_id: usize): usize { var fn_d = def_node(self, fn_def); if fn_d != null { fn_d.owner_def = owner_def_id; } var meth = LangMethod { .name = fd.name, .def_id = fn_def }; - match Vec.push(&methods, &meth as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(&methods, &meth as *u8); }, .TypeDecl(td) => { var tpat = node(self, td.pattern); @@ -431,7 +415,7 @@ fn build_aggregate(self: *Sema, te: *Node, owner_def_id: usize): usize { mn.resolved_def_id = tdef; } var meth = LangMethod { .name = tname, .def_id = tdef }; - match Vec.push(&methods, &meth as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(&methods, &meth as *u8); } }, _ => {}, @@ -443,16 +427,21 @@ fn build_aggregate(self: *Sema, te: *Node, owner_def_id: usize): usize { self.current_aggregate_lang = saved; // IR 节点 - if @enum2int(lk) == @enum2int(LangKind.Enum) { - var tag_ir = TypeTable.make_int(&self.types.ir, 32, true); - tk = .Enum(.{ .mode = .Auto, .fixed_align_bits = 0, .tag_type = tag_ir, - .variants = members }); - } else if @enum2int(lk) == @enum2int(LangKind.Union) { - tk = .Union(.{ .mode = .Auto, .fixed_align_bits = 0, .tag_type = 0, .variants = members }); - } else if @enum2int(lk) == @enum2int(LangKind.Shape) { - tk = .Shape(.{ .mode = .Auto, .fixed_align_bits = 0, .tag_type = 0, .variants = members }); - } else { - tk = .Struct(.{ .mode = .Auto, .fixed_align_bits = 0, .tag_type = 0, .variants = members }); + match lk { + .Enum => { + var tag_ir = TypeTable.make_int(&self.types.ir, 32, true); + tk = .Enum(.{ .mode = .Auto, .fixed_align_bits = 0, .tag_type = tag_ir, + .variants = members }); + }, + .Union => { + tk = .Union(.{ .mode = .Auto, .fixed_align_bits = 0, .tag_type = 0, .variants = members }); + }, + .Shape => { + tk = .Shape(.{ .mode = .Auto, .fixed_align_bits = 0, .tag_type = 0, .variants = members }); + }, + _ => { + tk = .Struct(.{ .mode = .Auto, .fixed_align_bits = 0, .tag_type = 0, .variants = members }); + }, } TypeTable.define(&self.types.ir, agg_ir, &tk); @@ -501,7 +490,7 @@ fn build_container_aggregate(self: *Sema, n: *Node, owner_def_id: usize): usize if md.type_expr != 0 { mtid = infer(self, md.type_expr); } var mm = Member { .name = md.name, .type_id = ir_of(self, mtid), .ast_node_ref = dref }; - match Vec.push(&members, &mm as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(&members, &mm as *u8); }, .FnDecl(fd) => { var fn_def = d.resolved_def_id; @@ -509,7 +498,7 @@ fn build_container_aggregate(self: *Sema, n: *Node, owner_def_id: usize): usize var fn_d = def_node(self, fn_def); if fn_d != null { fn_d.owner_def = owner_def_id; } var meth = LangMethod { .name = fd.name, .def_id = fn_def }; - match Vec.push(&methods, &meth as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(&methods, &meth as *u8); } }, .TypeDecl(td) => { @@ -518,7 +507,7 @@ fn build_container_aggregate(self: *Sema, n: *Node, owner_def_id: usize): usize var tpat = node(self, td.pattern); if tpat != null && is_pattern_ident(tpat) { var meth = LangMethod { .name = pattern_name(tpat), .def_id = tdef }; - match Vec.push(&methods, &meth as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(&methods, &meth as *u8); } } }, @@ -550,7 +539,7 @@ fn container_var_method(self: *Sema, pat_ref: usize, methods: *Vec) { var vdef = pat.resolved_def_id; if vdef == 0 { ret; } var meth = LangMethod { .name = pattern_name(pat), .def_id = vdef }; - match Vec.push(methods, &meth as *u8) { .Ok => {}, .Err(er) => {} } + Vec.push(methods, &meth as *u8); } fn is_pattern_ident(n: *Node): bool { @@ -593,7 +582,6 @@ fn pattern_name(pat: *Node): ByteView { } } -// ---- @import ---- fn sema_import(self: *Sema, n: *Node, args: Vec): usize { if self.loader == null { @@ -666,7 +654,6 @@ fn sema_import(self: *Sema, n: *Node, args: Vec): usize { ret t; } -// ---- 声明求值 ---- fn eval_decl(self: *Sema, def_id: usize): usize { var d = def_node(self, def_id); @@ -809,7 +796,7 @@ fn collect_names(self: *Sema, ref: usize) { n.resolved_def_id = file_def; var file_sym = Symbol { .name = ByteView.from_slice("$file"), .kind = .Type, .node = file_def }; - ignore_bool(Scope.insert(&self.scope, mod_scope, file_sym)); + Scope.insert(&self.scope, mod_scope, file_sym); var i: usize = 0; while i < cm.declarations.len { @@ -887,7 +874,7 @@ fn collect_types(self: *Sema, ref: usize) { var pat = node(self, td.pattern); if pat != null && is_pattern_ident(pat) && d.resolved_def_id != 0 { - ignore_usize(eval_decl(self, d.resolved_def_id)); + eval_decl(self, d.resolved_def_id); } }, _ => {}, @@ -910,7 +897,7 @@ fn collect_signatures(self: *Sema) { if d != null && d.owner == (self.ast as *any) && @enum2int(d.kind) == @enum2int(DefKind.Fn) && def_state_is(d, .Unresolved) { - ignore_usize(eval_decl(self, i)); + eval_decl(self, i); } i = i + 1; } @@ -945,7 +932,6 @@ fn collect_type_unpacks(self: *Sema, ref: usize) { } } -// ---- 类型上下文(intrinsic 参数)---- fn infer_type_context(self: *Sema, ref: usize): usize { var n = node(self, ref); @@ -1024,7 +1010,6 @@ fn infer_type_context(self: *Sema, ref: usize): usize { ret 0; } -// ---- intrinsic 调用 ---- fn punct_is(op: Punct, want: Punct): bool { ret @enum2int(op) == @enum2int(want); @@ -1091,8 +1076,8 @@ fn intrin_call(self: *Sema, n: *Node, in: Intrin, args: Vec): usize { } if intrin_is(in, .Assert) { var bt = make_bool(self); - ignore_usize(coerce(self, list_at(args, 0), bt)); - if nargs == 2 { ignore_usize(infer(self, list_at(args, 1))); } + coerce(self, list_at(args, 0), bt); + if nargs == 2 { infer(self, list_at(args, 1)); } ret make_unit(self); } if intrin_is(in, .IntCast) || intrin_is(in, .Truncate) || intrin_is(in, .BitCast) || @@ -1113,7 +1098,7 @@ fn intrin_call(self: *Sema, n: *Node, in: Intrin, args: Vec): usize { ret dst; } if intrin_is(in, .Bool2Int) || intrin_is(in, .Ptr2Int) { - ignore_usize(infer(self, list_at(args, 0))); + infer(self, list_at(args, 0)); if nargs >= 2 { var dst = infer(self, list_at(args, 1)); if dst == 0 { ret 0; } @@ -1185,7 +1170,6 @@ fn intrin_field(self: *Sema, n: *Node, in: Intrin): usize { ret 0; } -// ---- 块 / 模式 / 解包 ---- fn block_body(self: *Sema, n: *Node, expected: usize): usize { var stmts = ref_vec(); @@ -1200,7 +1184,7 @@ fn block_body(self: *Sema, n: *Node, expected: usize): usize { push_scope(self); var i: usize = 0; while i < stmts.len { - ignore_usize(infer(self, list_at(stmts, i))); + infer(self, list_at(stmts, i)); i = i + 1; } var r: usize = 0; @@ -1243,7 +1227,7 @@ fn bind_pattern(self: *Sema, pat_ref: usize, matched_tid: usize) { if pattern_is_literal(pat) { var lt = infer(self, pat_ref); if lt != 0 && matched_tid != 0 { - ignore_usize(coerce(self, pat_ref, matched_tid)); + coerce(self, pat_ref, matched_tid); } ret; } @@ -1404,14 +1388,10 @@ fn type_unpack_one(self: *Sema, pat: *Node, name: ByteView, src_lang: usize) { var d = def_node(self, m.def_id); var k: SymbolKind = .Var; if d != null { - if @enum2int(d.kind) == @enum2int(DefKind.Fn) { - k = .Fn; - } else if @enum2int(d.kind) == @enum2int(DefKind.Agg) || - @enum2int(d.kind) == @enum2int(DefKind.Scalar) || - @enum2int(d.kind) == @enum2int(DefKind.Distinct) || - @enum2int(d.kind) == @enum2int(DefKind.Alias) || - @enum2int(d.kind) == @enum2int(DefKind.Builtin) { - k = .Type; + match d.kind { + .Fn => { k = .Fn; }, + .Agg, .Scalar, .Distinct, .Alias, .Builtin => { k = .Type; }, + _ => {}, } } var sym = Symbol { .name = name, .kind = k, .node = m.def_id }; @@ -1485,7 +1465,6 @@ fn do_type_unpack(self: *Sema, decl: *Node, pat: *Node, type_expr_ref: usize) { type_unpack_walk(self, pat, src_lang); } -// ---- var/const 推断 ---- fn var_body(self: *Sema, n: *Node): usize { var decl_tid: usize = 0; @@ -1531,7 +1510,6 @@ fn for_elem_type(self: *Sema, lang_tid: usize): usize { ret elem_of_lang(e.*); } -// ---- 驱动 ---- fn run_module(self: *Sema, module_ref: usize) { if self.ast == null || module_ref == 0 { ret; } @@ -1556,7 +1534,7 @@ fn run_module(self: *Sema, module_ref: usize) { collect_types(self, module_ref); collect_signatures(self); - ignore_usize(infer(self, module_ref)); + infer(self, module_ref); self.current_aggregate_lang = saved_agg; self.scope.current_scope = saved_scope; @@ -1582,8 +1560,6 @@ fn method_at(v: *Vec, i: usize): *LangMethod { ret null; } -fn ignore_usize(x: usize) {} -fn ignore_bool(x: bool) {} // ============================================================ // infer / coerce:下面两块是主体(step 2 填入)。 @@ -1652,7 +1628,13 @@ fn agg_variants_copy(self: *Sema, agg_ir: usize): Vec { ret out; } -// ---- coerce ---- + +// 二元运算两侧都 coerce 到 expected;成功返回 expected,失败返回 0。 +fn coerce_binop_same(self: *Sema, left: usize, right: usize, expected: usize): usize { + if coerce(self, left, expected) == 0 { ret 0; } + if coerce(self, right, expected) == 0 { ret 0; } + ret expected; +} fn coerce(self: *Sema, ref: usize, expected: usize): usize { if ref == 0 || expected == 0 { ret 0; } @@ -1709,8 +1691,8 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize { diag_ty2(self, n.span, .TypeMismatch, "comparison mismatch: ", lt2, rt2); ret 0; } - ignore_usize(coerce(self, x.left, common)); - ignore_usize(coerce(self, x.right, common)); + coerce(self, x.left, common); + coerce(self, x.right, common); result = make_bool(self); } else if is_addsub(op) { var en = lang_of(self, expected); @@ -1729,19 +1711,13 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize { } result = expected; } else { - if coerce(self, x.left, expected) == 0 { ret 0; } - if coerce(self, x.right, expected) == 0 { ret 0; } - result = expected; + result = coerce_binop_same(self, x.left, x.right, expected); } } else { - if coerce(self, x.left, expected) == 0 { ret 0; } - if coerce(self, x.right, expected) == 0 { ret 0; } - result = expected; + result = coerce_binop_same(self, x.left, x.right, expected); } } else { - if coerce(self, x.left, expected) == 0 { ret 0; } - if coerce(self, x.right, expected) == 0 { ret 0; } - result = expected; + result = coerce_binop_same(self, x.left, x.right, expected); } }, .ExprArrayLit(&x) => { @@ -1848,16 +1824,16 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize { .ExprIf(&x) => { handled = true; var bt = make_bool(self); - ignore_usize(coerce(self, x.cond, bt)); - if x.then_block != 0 { ignore_usize(coerce(self, x.then_block, expected)); } - if x.else_branch != 0 { ignore_usize(coerce(self, x.else_branch, expected)); } + coerce(self, x.cond, bt); + if x.then_block != 0 { coerce(self, x.then_block, expected); } + if x.else_branch != 0 { coerce(self, x.else_branch, expected); } result = expected; }, .ExprLoop(&x) => { handled = true; var saved = self.current_loop_break_tid; self.current_loop_break_tid = expected; - ignore_usize(infer(self, ref)); + infer(self, ref); self.current_loop_break_tid = saved; result = expected; }, @@ -1920,7 +1896,6 @@ fn kind_is_body_struct_init(n: *Node): bool { ret false; } -// ---- infer ---- fn infer(self: *Sema, ref: usize): usize { if ref == 0 { ret 0; } @@ -2004,7 +1979,7 @@ fn infer(self: *Sema, ref: usize): usize { } if punct_is(x.op, .Not) { var bt = make_bool(self); - ignore_usize(coerce(self, x.operand, bt)); + coerce(self, x.operand, bt); n.resolved_lang_tid = bt; ret bt; } @@ -2095,7 +2070,7 @@ fn infer(self: *Sema, ref: usize): usize { }, .ExprIf(&x) => { var bt = make_bool(self); - ignore_usize(coerce(self, x.cond, bt)); + coerce(self, x.cond, bt); var then_t = if x.then_block != 0 { infer(self, x.then_block) } else { 0 }; var else_t = if x.else_branch != 0 { infer(self, x.else_branch) } else { 0 }; var result: usize = 0; @@ -2114,24 +2089,24 @@ fn infer(self: *Sema, ref: usize): usize { var vd = node(self, x.var_decl); if vd == null { ret 0; } push_scope(self); - ignore_usize(var_body(self, vd)); - if x.then_block != 0 { ignore_usize(infer(self, x.then_block)); } + var_body(self, vd); + if x.then_block != 0 { infer(self, x.then_block); } pop_scope(self); - if x.else_branch != 0 { ignore_usize(infer(self, x.else_branch)); } + if x.else_branch != 0 { infer(self, x.else_branch); } ret 0; }, .ExprWhile(&x) => { push_view(&self.label_stack, label_name(self, x.label)); var bt = make_bool(self); - ignore_usize(coerce(self, x.cond, bt)); - if x.body != 0 { ignore_usize(infer(self, x.body)); } - if x.else_branch != 0 { ignore_usize(infer(self, x.else_branch)); } + coerce(self, x.cond, bt); + if x.body != 0 { infer(self, x.body); } + if x.else_branch != 0 { infer(self, x.else_branch); } pop_label(self); ret 0; }, .ExprLoop(&x) => { push_view(&self.label_stack, label_name(self, x.label)); - if x.body != 0 { ignore_usize(infer(self, x.body)); } + if x.body != 0 { infer(self, x.body); } pop_label(self); ret 0; }, @@ -2155,7 +2130,7 @@ fn infer(self: *Sema, ref: usize): usize { } push_scope(self); bind_pattern(self, pat, matched); - if body != 0 { ignore_usize(infer(self, body)); } + if body != 0 { infer(self, body); } pop_scope(self); } i = i + 1; @@ -2264,7 +2239,7 @@ fn infer(self: *Sema, ref: usize): usize { .ContainerMembers(&x) => { var i: usize = 0; while i < x.declarations.len { - ignore_usize(infer(self, list_at(x.declarations, i))); + infer(self, list_at(x.declarations, i)); i = i + 1; } ret 0; @@ -2295,23 +2270,23 @@ fn infer(self: *Sema, ref: usize): usize { ret infer_continue(self, n, x.label); }, .StatementDefer(&x) => { - if x.body != 0 { ignore_usize(infer(self, x.body)); } + if x.body != 0 { infer(self, x.body); } ret 0; }, .StatementComptime(&x) => { - if x.body != 0 { ignore_usize(infer(self, x.body)); } + if x.body != 0 { infer(self, x.body); } ret 0; }, .StatementDecl(&x) => { - if x.decl != 0 { ignore_usize(infer(self, x.decl)); } + if x.decl != 0 { infer(self, x.decl); } ret 0; }, .StatementExpr(&x) => { - if x.expr != 0 { ignore_usize(infer(self, x.expr)); } + if x.expr != 0 { infer(self, x.expr); } ret 0; }, .TopLevelBlock(&x) => { - if x.block != 0 { ignore_usize(infer(self, x.block)); } + if x.block != 0 { infer(self, x.block); } ret 0; }, _ => { ret 0; }, @@ -2326,24 +2301,21 @@ fn kind_is_body_ident(n: *Node): bool { fn pop_label(self: *Sema) { var out = ByteView.empty(); - match Vec.pop(&self.label_stack, &out as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.pop(&self.label_stack, &out as *u8); } fn infer_binary(self: *Sema, n: *Node, op: Punct, left: usize, right: usize): usize { if punct_is(op, .Assign) || is_assign_arith(op) { var lt = infer(self, left); if lt == 0 { ret 0; } - ignore_usize(coerce(self, right, lt)); + coerce(self, right, lt); n.resolved_lang_tid = lt; ret lt; } if punct_is(op, .OrOr) || punct_is(op, .AndAnd) { var bt = make_bool(self); - ignore_usize(coerce(self, left, bt)); - ignore_usize(coerce(self, right, bt)); + coerce(self, left, bt); + coerce(self, right, bt); n.resolved_lang_tid = bt; ret bt; } @@ -2356,15 +2328,15 @@ fn infer_binary(self: *Sema, n: *Node, op: Punct, left: usize, right: usize): us diag_ty2(self, n.span, .TypeMismatch, "comparison mismatch: ", lt, rt); ret 0; } - ignore_usize(coerce(self, left, common)); - ignore_usize(coerce(self, right, common)); + coerce(self, left, common); + coerce(self, right, common); var b = make_bool(self); n.resolved_lang_tid = b; ret b; } if punct_is(op, .Range) { - ignore_usize(infer(self, left)); - ignore_usize(infer(self, right)); + infer(self, left); + infer(self, right); var i64t = LangType.make_int(&self.types, 64, true); var r = LangType.make_range(&self.types, i64t); n.resolved_lang_tid = r; @@ -2377,7 +2349,7 @@ fn infer_binary(self: *Sema, n: *Node, op: Punct, left: usize, right: usize): us diag(self, n.span, .TypeMismatch, "shift requires integer operands"); ret 0; } - ignore_usize(infer(self, right)); + infer(self, right); n.resolved_lang_tid = lt; ret lt; } @@ -2387,7 +2359,7 @@ fn infer_binary(self: *Sema, n: *Node, op: Punct, left: usize, right: usize): us if kind_is(self, lt2, .Ptr) && kind_is(self, rt2, .Int) && is_addsub(op) { if int_bits(self, rt2) == 0 { var it = make_isize(self); - ignore_usize(coerce(self, right, it)); + coerce(self, right, it); } n.resolved_lang_tid = lt2; ret lt2; @@ -2397,8 +2369,8 @@ fn infer_binary(self: *Sema, n: *Node, op: Punct, left: usize, right: usize): us diag_ty2(self, n.span, .TypeMismatch, "operand types cannot be joined: ", lt2, rt2); ret 0; } - ignore_usize(coerce(self, left, common2)); - ignore_usize(coerce(self, right, common2)); + coerce(self, left, common2); + coerce(self, right, common2); n.resolved_lang_tid = common2; ret common2; } @@ -2530,7 +2502,7 @@ fn infer_field(self: *Sema, n: *Node, obj_ref: usize, field_name: ByteView): usi fn infer_index(self: *Sema, n: *Node, obj_ref: usize, index_ref: usize): usize { var obj_tid = infer(self, obj_ref); - ignore_usize(infer(self, index_ref)); + infer(self, index_ref); var obj = lang_of(self, obj_tid); if obj == null { ret 0; } var elem: usize = 0; @@ -2546,7 +2518,7 @@ fn infer_index(self: *Sema, n: *Node, obj_ref: usize, index_ref: usize): usize { var iv: i64 = -1; match idx_node.body { .ExprIntLit(lit) => { - match BigInt.to_i64(&iv, lit.value) { .Ok => {}, .Err(e) => {} } + BigInt.to_i64(&iv, lit.value); }, _ => {}, } @@ -2567,8 +2539,8 @@ fn infer_index(self: *Sema, n: *Node, obj_ref: usize, index_ref: usize): usize { fn infer_slice(self: *Sema, n: *Node, obj_ref: usize, begin_ref: usize, end_ref: usize): usize { var obj_tid = infer(self, obj_ref); - if begin_ref != 0 { ignore_usize(infer(self, begin_ref)); } - if end_ref != 0 { ignore_usize(infer(self, end_ref)); } + if begin_ref != 0 { infer(self, begin_ref); } + if end_ref != 0 { infer(self, end_ref); } var obj = lang_of(self, obj_tid); if obj == null { ret 0; } if !(kind_is(self, obj_tid, .Array) || kind_is(self, obj_tid, .Ptr) || @@ -2685,7 +2657,7 @@ fn infer_aggregate(self: *Sema, n: *Node, type_name: ByteView, fields: Vec): usi } if idx < field_irs.len { var ft = lang_from_ir(self, list_at(field_irs, idx)); - if ft != 0 && iexpr != 0 { ignore_usize(coerce(self, iexpr, ft)); } + if ft != 0 && iexpr != 0 { coerce(self, iexpr, ft); } } } i = i + 1; @@ -2726,8 +2698,8 @@ fn infer_for(self: *Sema, n: *Node, label_ref: usize, iter_exprs: Vec, pattern_r } } - if body_ref != 0 { ignore_usize(infer(self, body_ref)); } - if else_ref != 0 { ignore_usize(infer(self, else_ref)); } + if body_ref != 0 { infer(self, body_ref); } + if else_ref != 0 { infer(self, else_ref); } pop_scope(self); pop_label(self); @@ -2786,7 +2758,7 @@ fn infer_fn_decl(self: *Sema, n: *Node, params_ref: Vec, ret_ref: usize, body_re } var old_ret = self.current_fn_ret_tid; self.current_fn_ret_tid = ret_tid; - ignore_usize(infer(self, body_ref)); + infer(self, body_ref); self.current_fn_ret_tid = old_ret; pop_scope(self); self.current_aggregate_lang = saved_agg; @@ -2811,7 +2783,7 @@ fn infer_type_decl(self: *Sema, n: *Node, pattern_ref: usize, type_ref: usize): while i < members.len { var mref = list_at(members, i); var mn = node(self, mref); - if mn != null && kind_is_body_fn_decl(mn) { ignore_usize(infer(self, mref)); } + if mn != null && kind_is_body_fn_decl(mn) { infer(self, mref); } i = i + 1; } } @@ -2826,9 +2798,9 @@ fn kind_is_body_fn_decl(n: *Node): bool { fn infer_ret(self: *Sema, n: *Node, expr_ref: usize): usize { if expr_ref != 0 { if self.current_fn_ret_tid != 0 { - ignore_usize(coerce(self, expr_ref, self.current_fn_ret_tid)); + coerce(self, expr_ref, self.current_fn_ret_tid); } else { - ignore_usize(infer(self, expr_ref)); + infer(self, expr_ref); } } else if self.current_fn_ret_tid != 0 { var u = make_unit(self); @@ -2850,9 +2822,9 @@ fn infer_break(self: *Sema, n: *Node, label_ref: usize, expr_ref: usize): usize } if expr_ref != 0 { if self.current_loop_break_tid != 0 { - ignore_usize(coerce(self, expr_ref, self.current_loop_break_tid)); + coerce(self, expr_ref, self.current_loop_break_tid); } else { - ignore_usize(infer(self, expr_ref)); + infer(self, expr_ref); } } ret 0; @@ -2884,7 +2856,6 @@ fn label_in_stack(self: *Sema, lbl: ByteView): bool { ret false; } -// ---- dump(镜像 stage1 spl_sema_dump;供 splc1 --dump sema 人读)---- type SymPrint = struct { key: ByteView, @@ -2928,7 +2899,7 @@ fn dump(self: *Sema, out: *ByteBuffer): bool { if !out_u(out, sn.parent) { ret false; } if !out_str(out, "\n") { ret false; } - // 收集后按符号名排序输出(与 stage1 一致,顺序与哈希布局解耦)。 + // 收集后按符号名排序输出(顺序与哈希布局解耦)。 var entries = Vec.blank(@sizeof(SymPrint), @alignof(SymPrint)); var sc = Map.slot_count(sn.symbols); var j: usize = 0; @@ -2942,10 +2913,7 @@ fn dump(self: *Sema, out: *ByteBuffer): bool { .name = sym.name, .node = sym.node, }; - match Vec.push(&entries, &sp as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.push(&entries, &sp as *u8); } j = j + 1; } @@ -2959,11 +2927,11 @@ fn dump(self: *Sema, out: *ByteBuffer): bool { var prev = sym_at(&entries, b - 1).*; if ByteView.cmp(prev.key, cur.key) <= 0 { break; } var pv = prev; - match Vec.set(&entries, b, &pv as *u8) { .Ok => {}, .Err(error) => {} } + Vec.set(&entries, b, &pv as *u8); b = b - 1; } var cv = cur; - match Vec.set(&entries, b, &cv as *u8) { .Ok => {}, .Err(error) => {} } + Vec.set(&entries, b, &cv as *u8); a = a + 1; } @@ -3019,7 +2987,6 @@ fn dump(self: *Sema, out: *ByteBuffer): bool { ret Attr.dump(&self.attr, out); } -// ---- 测试 ---- // 走完整前端:lex -> parse -> sema;返回 0 表示无(新)诊断。 fn sema_source(text: []u8): i32 { diff --git a/stage2/splc1.spl b/stage2/splc1.spl index b9fce3c..0629b04 100644 --- a/stage2/splc1.spl +++ b/stage2/splc1.spl @@ -1,8 +1,7 @@ // Expect retcode = 0 -// splc1 (stage2 自举编译器入口)。 -// 当前实现 `--dump [out]`:读取源文件,按与 stage1 -// splc0 完全一致的格式打印各阶段产物,供 diff 测试逐字节比对。 +// splc1:自举编译器入口。`splc1 ` 编译;`--dump ` 打印各阶段 +// 产物,格式必须与 splc0 逐字节一致以通过 diff。 type .{ .ByteView } = @import("./utils/byte_view.spl"); type .{ .ByteBuffer } = @import("./utils/byte_buffer.spl"); @@ -13,8 +12,7 @@ type Ast = @import("./ast.spl"); type Parser = @import("./parser.spl"); type Sema = @import("./sema.spl"); type .{ .append_usize } = @import("./utils/fmt.spl"); -type .{ .read_all, .print, .eprint, .open_cstr, .write_all } = @import("./utils/io.spl"); -type File = @import("./sys/file.spl"); +type .{ .read_all, .print, .eprint, .open_cstr, .write_all, .File } = @import("./utils/io.spl"); type .{ .Sources, .Source, .set_new, .set_add, .set_at, .set_drop } = @import("./utils/source.spl"); type .{ .Diag, .Code, .span_none } = @import("./diag.spl"); type Logger = @import("./utils/log.spl"); @@ -27,7 +25,7 @@ type .{ .Layout } = @import("./layout.spl"); type Ir2VmM = @import("./ir2vm.spl"); type .{ .Ir2Vm } = @import("./ir2vm.spl"); type Ir2CM = @import("./ir2c.spl"); -type .{ .alloc, .free } = @import("./sys/mem.spl"); +type .{ .alloc, .free } = @import("./utils/memory.spl"); fn token_at(tokens: *Vec, index: usize): Token { match Vec.get(tokens, index) { @@ -131,14 +129,11 @@ fn dump_lex(log: *Logger, path: ByteView): i32 { } defer { Vec.drop(&tokens); } - // 非法输入:走诊断(stage1 在此处是宽容无视,stage2 显式报错)。 + // 非法输入:走诊断(显式报错,不静默)。 if Diag.has_error(diag) { var rendered = ByteBuffer.new(); defer { ByteBuffer.drop(&rendered); } - match Diag.render_human(&diag, &rendered) { - .Ok => {}, - .Err(error) => {}, - } + Diag.render_human(&diag, &rendered); eprint(ByteBuffer.as_slice(rendered)); ret 1; } @@ -200,10 +195,7 @@ fn dump_ast(log: *Logger, path: ByteView): i32 { if Diag.has_error(diag) || p.failed { var rendered = ByteBuffer.new(); defer { ByteBuffer.drop(&rendered); } - match Diag.render_human(&diag, &rendered) { - .Ok => {}, - .Err(error) => {}, - } + Diag.render_human(&diag, &rendered); eprint(ByteBuffer.as_slice(rendered)); ret 1; } @@ -221,7 +213,6 @@ fn dump_ast(log: *Logger, path: ByteView): i32 { ret 0; } -// ---- @import 模块加载器(driver 侧)---- type ModEntry = struct { path: ByteView, @@ -236,7 +227,6 @@ type LoaderCtx = struct { diag: *Diag, } -fn ignore_bool(b: bool) {} fn append_bytes(buf: *ByteBuffer, bytes: []u8): bool { match ByteBuffer.append(buf, bytes) { @@ -263,7 +253,7 @@ fn sub(p: ByteView, a: usize, b: usize): []u8 { fn normalize_pop(out: *ByteBuffer) { var cur = ByteBuffer.as_slice(out.*); if cur.len == 0 { - ignore_bool(append_bytes(out, "..")); + append_bytes(out, ".."); ret; } var end = cur.len; @@ -274,7 +264,7 @@ fn normalize_pop(out: *ByteBuffer) { var start = end; while start > 0 && cur.ptr[start - 1] != '/' { start = start - 1; } if end - start == 2 && cur.ptr[start] == '.' && cur.ptr[start + 1] == '.' { - ignore_bool(append_bytes(out, "..")); + append_bytes(out, ".."); ret; } var new_len: usize = 0; @@ -286,7 +276,7 @@ fn normalize_pop(out: *ByteBuffer) { // 折叠重复分隔符、解析 "." 与 ".."、'\' 统一成 '/'。 fn normalize_into(out: *ByteBuffer, p: ByteView) { if p.len > 0 && (p.ptr[0] == '/' || p.ptr[0] == '\\') { - ignore_bool(append_byte(out, '/')); + append_byte(out, '/'); } var i: usize = 0; while i < p.len { @@ -302,9 +292,9 @@ fn normalize_into(out: *ByteBuffer, p: ByteView) { } var cur = ByteBuffer.as_slice(out.*); if cur.len > 0 && cur.ptr[cur.len - 1] != '/' { - ignore_bool(append_byte(out, '/')); + append_byte(out, '/'); } - ignore_bool(append_bytes(out, seg)); + append_bytes(out, seg); } } @@ -325,9 +315,9 @@ fn resolve_path(from: ByteView, path: ByteView): ByteBuffer { i = i + 1; } if last >= 0 { - ignore_bool(append_bytes(&out, sub(from, 0, (last as usize) + 1))); + append_bytes(&out, sub(from, 0, (last as usize) + 1)); } - ignore_bool(append_bytes(&out, ByteView.as_slice(path))); + append_bytes(&out, ByteView.as_slice(path)); var norm = ByteBuffer.new(); normalize_into(&norm, ByteView.from_slice(ByteBuffer.as_slice(out))); ByteBuffer.drop(&out); @@ -504,10 +494,7 @@ fn dump_sema(log: *Logger, path: ByteView): i32 { if Diag.has_error(diag) || p.failed { var rendered = ByteBuffer.new(); defer { ByteBuffer.drop(&rendered); } - match Diag.render_human(&diag, &rendered) { - .Ok => {}, - .Err(error) => {}, - } + Diag.render_human(&diag, &rendered); eprint(ByteBuffer.as_slice(rendered)); ret 1; } @@ -538,10 +525,7 @@ fn dump_sema(log: *Logger, path: ByteView): i32 { if Diag.has_error(diag) { var rendered = ByteBuffer.new(); defer { ByteBuffer.drop(&rendered); } - match Diag.render_human(&diag, &rendered) { - .Ok => {}, - .Err(error) => {}, - } + Diag.render_human(&diag, &rendered); eprint(ByteBuffer.as_slice(rendered)); ret 1; } @@ -573,7 +557,7 @@ type PipeMode = enum { fn step(mode: PipeMode, s: []u8) { if @enum2int(mode) == @enum2int(PipeMode.State) { - match eprint(s) { .Ok => {}, .Err(error) => {} } + eprint(s); } } @@ -631,7 +615,7 @@ fn run_pipeline(log: *Logger, path: ByteView, mode: PipeMode, outpath: ByteView) if Diag.has_error(diag) || p.failed { var rendered = ByteBuffer.new(); defer { ByteBuffer.drop(&rendered); } - match Diag.render_human(&diag, &rendered) { .Ok => {}, .Err(error) => {} } + Diag.render_human(&diag, &rendered); eprint(ByteBuffer.as_slice(rendered)); ret 1; } @@ -662,7 +646,7 @@ fn run_pipeline(log: *Logger, path: ByteView, mode: PipeMode, outpath: ByteView) if Diag.has_error(diag) { var rendered = ByteBuffer.new(); defer { ByteBuffer.drop(&rendered); } - match Diag.render_human(&diag, &rendered) { .Ok => {}, .Err(error) => {} } + Diag.render_human(&diag, &rendered); eprint(ByteBuffer.as_slice(rendered)); ret 1; } @@ -677,13 +661,13 @@ fn run_pipeline(log: *Logger, path: ByteView, mode: PipeMode, outpath: ByteView) var asts = Vec.blank(@sizeof(usize), @alignof(usize)); defer { Vec.drop(&asts); } var ap: *Ast = * - match Vec.push(&asts, &ap as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&asts, &ap as *u8); var mi: usize = 0; while mi < ctx.mods.len { var m = mod_at(&ctx, mi); if m != null && m.ok && m.ast != null { var mp: *Ast = m.ast; - match Vec.push(&asts, &mp as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&asts, &mp as *u8); } mi = mi + 1; } @@ -692,7 +676,7 @@ fn run_pipeline(log: *Logger, path: ByteView, mode: PipeMode, outpath: ByteView) if Diag.has_error(diag) { var rendered = ByteBuffer.new(); defer { ByteBuffer.drop(&rendered); } - match Diag.render_human(&diag, &rendered) { .Ok => {}, .Err(error) => {} } + Diag.render_human(&diag, &rendered); eprint(ByteBuffer.as_slice(rendered)); ret 1; } @@ -736,8 +720,8 @@ fn run_pipeline(log: *Logger, path: ByteView, mode: PipeMode, outpath: ByteView) Logger.error(log, "cannot open C output file"); ret 1; } - match write_all(&f, ByteBuffer.as_slice(cout)) { .Ok => {}, .Err(error) => {} } - ignore_i32(File.close(&f)); + write_all(&f, ByteBuffer.as_slice(cout)); + File.close(&f); } else { match print(ByteBuffer.as_slice(cout)) { .Ok => {}, @@ -754,7 +738,7 @@ fn run_pipeline(log: *Logger, path: ByteView, mode: PipeMode, outpath: ByteView) var ir2vm: Ir2Vm = undefined; Ir2VmM.init(&ir2vm, &builder.ir, &sema.types.ir, &layout, &sema.attr); defer { Ir2VmM.drop(&ir2vm); } - ignore_i32(Ir2VmM.run(&ir2vm)); + Ir2VmM.run(&ir2vm); step(mode, "state: ir2vm ok\n"); if @enum2int(mode) == @enum2int(PipeMode.Vm) { @@ -782,7 +766,6 @@ fn run_pipeline(log: *Logger, path: ByteView, mode: PipeMode, outpath: ByteView) ret 0; } -fn ignore_i32(v: i32) {} fn main(argc: i32, argv: **u8): i32 { // 无参数:自测运行(`nob test stage2`)视为成功。 diff --git a/stage2/token.spl b/stage2/token.spl index 44b4ff3..6347133 100644 --- a/stage2/token.spl +++ b/stage2/token.spl @@ -1,7 +1,7 @@ // Expect retcode = 0 -// 词法单元:用带载荷 ADT 表达 TokenKind;关键词/算符各自独立 enum。 -// 整型与字符在词法期解码并随载荷携带;文本一律借用源切片(不复制)。 +// 词法单元:TokenKind 为带载荷 ADT,关键词/算符各自独立 enum;整型/字符在词法期 +// 解码,文本一律借用源切片。 type .{ .ByteView } = @import("utils/byte_view.spl"); @@ -128,7 +128,6 @@ fn keyword_of(text: ByteView): KeywordResult { ret .No; } -// ---- token 类型名(与 stage1 spl_tok_type_name 逐字一致,供 dump/diff 使用)---- fn keyword_name(kw: Keyword): []u8 { match kw { @@ -242,7 +241,6 @@ fn kind_name(kind: TokenKind): []u8 { ret "?"; } -// ---- 测试辅助 ---- fn view(text: []u8): ByteView { ret ByteView.from_slice(text); diff --git a/stage2/type_table.spl b/stage2/type_table.spl index d69ed79..62fcfef 100644 --- a/stage2/type_table.spl +++ b/stage2/type_table.spl @@ -1,11 +1,7 @@ // Expect retcode = 0 -// IR 类型表(移植自 stage1/spl_type.c)。类型按结构 hash-consing(intern), -// id 0 为保留哨兵(Error)。节点借用式持有:名称是 ByteView(指向源/AST), -// 不复制字符串;聚合成员与函数参数的 Vec 由本表拥有,drop 时统一释放。 -// -// hash 只用于选桶;相等永远由结构比较决定。桶以「完整 hash -> 链头 id」的 -// Map 存储,节点自带 hash_next 串链(对应 stage1 的 spl_fold)。 +// IR 类型表:按结构 hash-consing。id 0 为保留哨兵(Error)。成员/参数 Vec 由本表 +// 拥有;hash 仅用于选桶,相等始终由结构比较决定。 type .{ .Error } = @import("utils/error.spl"); type .{ .Vec } = @import("utils/vec.spl"); @@ -41,7 +37,7 @@ type AggKind = enum { Shape, } -// 与 stage1 spl_type_node_kind_t 一一对应;Forall/Exists 保留(暂打印 quant)。 +// 变体顺序即 kind 数值;Forall/Exists 暂按 quant 打印。 type TypeNode = enum { Error, Never, @@ -78,7 +74,6 @@ type TypeTableResult = enum { Err: Error, } -// ---- hash(FNV 风格;值不必与 stage1 相同,只要结构一致即可)---- fn seed(): usize { ret 14695981039346656037; @@ -290,7 +285,6 @@ fn free_payload(n: *TypeNode) { } } -// ---- 底层访问 ---- fn usize_at(v: Vec, i: usize): usize { match Vec.get(&v, i) { @@ -317,13 +311,12 @@ fn push_member(v: *Vec, name: []u8, type_id: usize) { } } -// id 0 与越界均返回 null(对应 stage1 spl_type_node)。 +// id 0 与越界均返回 null。 fn node(self: *TypeTable, id: usize): *TypeEntry { if id == 0 || id >= self.table.len { ret null; } ret (self.table.data as *TypeEntry) + id; } -// ---- 生命周期 ---- fn new(): TypeTableResult { var tt = TypeTable { @@ -376,7 +369,6 @@ fn define(self: *TypeTable, id: usize, src: *TypeNode) { src.* = .Error; } -// ---- intern ---- fn fold_find(self: *TypeTable, hash: usize, probe: *TypeNode): usize { var head: usize = 0; @@ -403,10 +395,7 @@ fn fold_insert(self: *TypeTable, hash: usize, id: usize) { var n = node(self, id); if n == null { ret; } n.hash_next = old; - match Map.put(&self.fold, &hash as *u8, &id as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Map.put(&self.fold, &hash as *u8, &id as *u8); } // intern 一个 probe:命中则释放 probe 载荷并返回已有 id;否则复制入表。 @@ -433,7 +422,6 @@ fn push(self: *TypeTable, probe: *TypeNode): usize { ret id; } -// ---- builders ---- fn make_error(self: *TypeTable): usize { var n: TypeNode = .Error; @@ -513,7 +501,6 @@ fn make_agg(self: *TypeTable, kind: AggKind, agg: Agg): usize { ret push(self, &n); } -// ---- 查询 ---- fn is_subtype(self: *TypeTable, sub: usize, super: usize): bool { if sub == 0 || super == 0 { ret false; } @@ -597,7 +584,6 @@ fn agg_member_idx(self: *TypeTable, tid: usize, name: ByteView, out_idx: *usize) ret false; } -// ---- dump(镜像 stage1 spl_type_pure_dump)---- fn push_out(buf: *ByteBuffer, bytes: []u8): bool { match ByteBuffer.append(buf, bytes) { @@ -637,10 +623,7 @@ fn dump_rec(self: *TypeTable, id: usize, out: *ByteBuffer, stack: *Vec): bool { if n == null { if !push_out(out, "none") { ret false; } var popped: usize = 0; - match Vec.pop(stack, &popped as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.pop(stack, &popped as *u8); ret true; } @@ -698,10 +681,7 @@ fn dump_rec(self: *TypeTable, id: usize, out: *ByteBuffer, stack: *Vec): bool { } var dropped: usize = 0; - match Vec.pop(stack, &dropped as *u8) { - .Ok => {}, - .Err(error) => {}, - } + Vec.pop(stack, &dropped as *u8); ret ok; } @@ -739,7 +719,6 @@ fn pure_dump_text(self: *TypeTable, id: usize): ByteBuffer { ret out; } -// ---- 测试 ---- fn test_intern_simple() { var tt: TypeTable = undefined; diff --git a/stage2/utils/algorithm.spl b/stage2/utils/algorithm.spl index d99b194..aab6dda 100644 --- a/stage2/utils/algorithm.spl +++ b/stage2/utils/algorithm.spl @@ -155,7 +155,6 @@ fn stable_sort(data: *u8, len: usize, elem_size: usize, ret .Ok; } -// ---- 测试 ---- type Item = struct { key: i32, diff --git a/stage2/utils/arena.spl b/stage2/utils/arena.spl index 32f4d0d..4019e67 100644 --- a/stage2/utils/arena.spl +++ b/stage2/utils/arena.spl @@ -127,7 +127,6 @@ fn drop(self: *Arena) { self.current = 0; } -// ---- 测试辅助 ---- fn is_aligned(p: *u8, align: usize): bool { ret ((p as usize) & (align - 1)) == 0; diff --git a/stage2/utils/byte_buffer.spl b/stage2/utils/byte_buffer.spl index 9691a3b..612c9e5 100644 --- a/stage2/utils/byte_buffer.spl +++ b/stage2/utils/byte_buffer.spl @@ -26,7 +26,7 @@ fn new(): ByteBuffer { fn with_capacity(cap: usize): ByteBuffer { var b = new(); - match reserve(&b, cap) { .Ok => {}, .Err(error) => {} } + reserve(&b, cap); ret b; } diff --git a/stage2/utils/fmt.spl b/stage2/utils/fmt.spl index aea9b00..3df12c0 100644 --- a/stage2/utils/fmt.spl +++ b/stage2/utils/fmt.spl @@ -9,8 +9,8 @@ type .{ .ByteView } = @import("byte_view.spl"); type .{ .Value, .int, .uint, .char, .str, .addr } = @import("value.spl"); type .{ .BigInt, .Bits } = @import("mp.spl"); -// 注意:radix 边界直接用字面量。stage1 刻意不做常量求值/折叠, -// 顶层 const 不应用于运行时表达式。 +// radix 边界直接用字面量:顶层 const 不参与运行时常量折叠。 + fn valid_radix(radix: u8): bool { ret radix >= 2 && radix <= 36; } @@ -71,7 +71,6 @@ fn append_bool(out: *ByteBuffer, value: bool): Status { ret ByteBuffer.append(out, "false"); } -// ---- 显式装箱值格式化 ---- // Int/Uint 落到整数;signed 仅对 Int 的十进制生效,其余按无符号位模式输出。 fn append_value_int(out: *ByteBuffer, value: Value, radix: u8, uppercase: bool, @@ -223,7 +222,6 @@ fn format(out: *ByteBuffer, fmt: []u8, args: []Value): Status { ret ByteBuffer.append(out, ByteBuffer.as_slice(temp)); } -// ---- 测试辅助 ---- fn expect_ok(result: Status) { match result { diff --git a/stage2/utils/hash.spl b/stage2/utils/hash.spl index 911371c..602a8ea 100644 --- a/stage2/utils/hash.spl +++ b/stage2/utils/hash.spl @@ -34,7 +34,6 @@ fn hash_usize_value(value: usize): usize { ret h; } -// ---- map 回调 ---- // 键按 usize 解释。 fn hash_usize(key: *u8): usize { @@ -55,7 +54,6 @@ fn eq_view(a: *u8, b: *u8): bool { ret ByteView.eq((a as *ByteView).*, (b as *ByteView).*); } -// ---- 测试辅助 ---- fn expect_hash(view: []u8, expected: usize) { var got = hash_bytes(view.ptr, view.len); diff --git a/stage2/utils/io.spl b/stage2/utils/io.spl index b8ac6a4..3e4740f 100644 --- a/stage2/utils/io.spl +++ b/stage2/utils/io.spl @@ -1,11 +1,7 @@ // Expect retcode = 0 -// I/O 便利层(构建在 sys/file 之上): -// - C 字符串路径/模式的 open 包装 -// - 精确读取、完整写入和普通文件整读 -// - stdout/stderr 打印 -// 说明:read_all 会按文件大小一次性读入 ByteBuffer;不处理增长中的文件。 -// 短读、短写后的零进展及关闭失败返回 Err(.Io);文件写入不承诺回滚。 +// sys/file 之上的 I/O 便利层:C 字符串路径 open、精确读取/完整写入、整读、stdout/stderr 打印。 +// 短读/短写零进展与关闭失败返回 Err(.Io);写入失败不承诺回滚。 type .{ .Error, .Status, .make } = @import("error.spl"); type .{ .ByteView } = @import("byte_view.spl"); @@ -130,7 +126,6 @@ fn read_all(path: ByteView, out: *ByteBuffer): Status { ret .Ok; } -// ---- 测试辅助 ---- fn view(text: []u8): ByteView { ret ByteView.from_slice(text); diff --git a/stage2/utils/json.spl b/stage2/utils/json.spl index 00eea34..bc80ba1 100644 --- a/stage2/utils/json.spl +++ b/stage2/utils/json.spl @@ -1,10 +1,6 @@ // Expect retcode = 0 -// 轻量 JSON 解析 / 输出器(递归下降 + 节点池),用于验证底层库的拼装,未来服务 LSP。 -// 设计: -// - 输入 ByteView,字符串/数字以“源切片”借用,不做解码,round-trip 保真; -// - 节点池 Vec[JsonNode];数组/对象子项存 Vec[JsonChild],保留插入顺序; -// - 错误带字节位置(error.spl);输出写 ByteBuffer;缩进/数字用 ByteBuffer/fmt。 -// 限制:不做字符串转义解码、数字不做数值化(原样保存);递归/输出深度上限见 max_depth()。 +// 轻量 JSON 解析/输出器:输入按源切片借用、不解码(round-trip 保真),数字不做数值化。 +// 节点/子项存 Vec 保留插入顺序;输出写 ByteBuffer。递归/输出深度上限见 max_depth()。 type .{ .Error, .Status, .make, .at } = @import("error.spl"); type .{ .ByteView, .ViewResult, .FindResult } = @import("byte_view.spl"); @@ -393,7 +389,7 @@ fn root_index(doc: *Json): usize { ret doc.root; } -// 枚举 tag 取整(stage1 枚举 == 有缺陷,用 @enum2int 比较更稳妥)。 +// 枚举 tag 取整:枚举 == 不可靠,用 @enum2int 比较。 fn kind_code(kind: JsonKind): usize { ret @enum2int(kind) as usize; } @@ -578,7 +574,6 @@ fn emit_pretty(out: *ByteBuffer, doc: *Json, indent: usize): Status { ret emit(out, doc, doc.root, indent, 0); } -// ---- 构造辅助(写 JSON 片段;字符串需由调用方保证已转义)---- fn write_int(out: *ByteBuffer, value: i64): Status { ret append_i64(out, value, 10, false); @@ -588,7 +583,6 @@ fn write_u64(out: *ByteBuffer, value: u64): Status { ret append_u64(out, value, 10, false); } -// ---- 测试辅助 ---- fn expect_ok(result: Status) { match result { diff --git a/stage2/utils/log.spl b/stage2/utils/log.spl index 5b418f0..378dc6a 100644 --- a/stage2/utils/log.spl +++ b/stage2/utils/log.spl @@ -89,7 +89,6 @@ fn fatal(self: *Logger, message: []u8) { Exit.fail(); } -// ---- 格式化入口(显式装箱,见 value.spl / fmt.format)---- // 先格式化到临时缓冲;格式错误在写出前返回 Err(.InvalidFormat)。 fn logf(self: *Logger, level: Level, fmt: []u8, args: []Value): Status { @@ -125,7 +124,6 @@ fn fatalf(self: *Logger, fmt: []u8, args: []Value) { Exit.fail(); } -// ---- 测试 ---- fn expect_name(level: Level, expected: []u8) { @assert(ByteView.eq(ByteView.from_slice(level_name(level)), diff --git a/stage2/utils/lsp_frame.spl b/stage2/utils/lsp_frame.spl index 088a29a..c4908e5 100644 --- a/stage2/utils/lsp_frame.spl +++ b/stage2/utils/lsp_frame.spl @@ -99,7 +99,6 @@ fn parse_frame(input: ByteView, body_out: *ByteBuffer): FrameResult { ret .Ok(body_start + content_len); } -// ---- 测试辅助 ---- fn expect_ok(result: Status) { match result { diff --git a/stage2/utils/map.spl b/stage2/utils/map.spl index 276f048..f41b0cd 100644 --- a/stage2/utils/map.spl +++ b/stage2/utils/map.spl @@ -155,7 +155,6 @@ fn take(source: *Map): Map { ret result; } -// ---- 测试辅助 ---- fn expect_ok(result: Status) { match result { diff --git a/stage2/utils/memory.spl b/stage2/utils/memory.spl index 4dc483f..4e16357 100644 --- a/stage2/utils/memory.spl +++ b/stage2/utils/memory.spl @@ -1,13 +1,23 @@ // Expect retcode = 0 -// 尺寸计算和字节移动;不分配、不释放内存,不改变任何资源的所有权。 +// 尺寸计算、字节移动与内存分配统一门面(分配/释放转发自 sys/mem)。 +// 本模块不改变任何资源的所有权。 type .{ .Error, .Status, .make } = @import("error.spl"); +type SysMem = @import("../sys/mem.spl"); + +// 分配/释放/字节操作转发(core 只经本模块使用内存,不直接依赖 sys)。 +fn alloc(sz: usize): *any { ret SysMem.alloc(sz); } +fn free(p: *any) { SysMem.free(p); } +fn realloc(p: *any, sz: usize): *any { ret SysMem.realloc(p, sz); } +fn copy(dst: *any, src: *any, n: usize): *any { ret SysMem.copy(dst, src, n); } +fn cmp(a: *any, b: *any, n: usize): isize { ret SysMem.cmp(a, b, n); } +fn set(dst: *any, byte: u8, n: usize): *any { ret SysMem.set(dst, byte, n); } +fn zero(dst: *any, n: usize): *any { ret SysMem.zero(dst, n); } #extern(vm) fn vm_memcpy(dst: *any, src: *any, n: usize): *any; #extern(vm) fn vm_memmove(dst: *any, src: *any, n: usize): *any; -fn ignore_ptr(p: *any) {} type SizeResult = enum { Ok: usize, @@ -75,7 +85,7 @@ fn move(dst: []u8, src: []u8): Status { if dst_addr == src_addr { ret .Ok; } // 重叠安全,统一走原生 memmove。 - ignore_ptr(vm_memmove(dst.ptr as *any, src.ptr as *any, count)); + vm_memmove(dst.ptr as *any, src.ptr as *any, count); ret .Ok; } diff --git a/stage2/utils/path.spl b/stage2/utils/path.spl index 6b17629..2e93086 100644 --- a/stage2/utils/path.spl +++ b/stage2/utils/path.spl @@ -297,7 +297,6 @@ fn normalize_into(out: *ByteBuffer, path: ByteView, style: PathStyle): Status { ret .Ok; } -// ---- 测试 ---- fn expect_ok(result: Status) { match result { .Ok => {}, .Err(error) => { @assert(false, "unexpected path error"); }, } } diff --git a/stage2/utils/profile.spl b/stage2/utils/profile.spl index 0413060..8216f8e 100644 --- a/stage2/utils/profile.spl +++ b/stage2/utils/profile.spl @@ -1,10 +1,7 @@ // Expect retcode = 0 -// 全量热点/耗时记录器(配合 @file_name()/@line()/@col() 与 sys/time.spl)。 -// 每个调用点聚合:count、独占(self)与包含(total)的 steps/ns。 -// - total_* 含被调用者(嵌套会重复,跨站点求和会超过墙钟) -// - self_* = total_* - 子区间之和,用于定位真正的热点 -// 用法(严格 LIFO,defer 正好满足): +// 采样热点记录器:每个调用点聚合 count 与 self/total 的 steps/ns(self = total 减子区间)。 +// 严格 LIFO,用 defer 配对: // var tok = Profile.begin(&prof, @file_name(), @line(), @col()); // defer { Profile.end(&prof, tok); } @@ -139,7 +136,7 @@ fn begin(self: *Profile, fname: []u8, line: usize, col: usize): usize { .Err(error) => { ret 0; }, } var token = self.spans.len - 1; - match Vec.push(&self.stack, &token as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&self.stack, &token as *u8); ret token; } @@ -164,7 +161,7 @@ fn end(self: *Profile, token: usize) { // 弹栈并把区间计入父 span(LIFO)。 var popped: usize = 0; - match Vec.pop(&self.stack, &popped as *u8) { .Ok => {}, .Err(error) => {} } + Vec.pop(&self.stack, &popped as *u8); var n = self.stack.len; if n > 0 { var p = span_at(self, usize_at(&self.stack, n - 1)); @@ -175,7 +172,6 @@ fn end(self: *Profile, token: usize) { } } -// ---- dump / save ---- fn out_s(out: *ByteBuffer, s: []u8): bool { match ByteBuffer.append(out, s) { .Ok => { ret true; }, .Err(error) => { ret false; } } @@ -202,7 +198,7 @@ fn dump(self: *Profile, out: *ByteBuffer): bool { defer { Vec.drop(&idx); } var i: usize = 0; while i < self.sites.len { - match Vec.push(&idx, &i as *u8) { .Ok => {}, .Err(error) => {} } + Vec.push(&idx, &i as *u8); i = i + 1; } @@ -271,7 +267,6 @@ fn save(self: *Profile, path: ByteView): bool { ret true; } -// ---- 测试 ---- fn spin(n: usize): usize { var i: usize = 0; @@ -293,10 +288,9 @@ fn test_profile() { @assert(s != null && s.count >= 1, "count"); @assert(s.total_steps > 0, "steps"); @assert(s.self_steps > 0, "self steps"); - if v == 0 { ignore_usize(v + 1); } + if v == 0 { v + 1; } } -fn ignore_usize(v: usize) {} fn main() { test_profile(); diff --git a/stage2/utils/set.spl b/stage2/utils/set.spl index 710a2d2..d1acad4 100644 --- a/stage2/utils/set.spl +++ b/stage2/utils/set.spl @@ -74,7 +74,6 @@ fn drop(self: *Set) { Map.drop(&self.map); } -// ---- 测试 ---- fn expect_ok(result: Status) { match result { diff --git a/stage2/utils/source.spl b/stage2/utils/source.spl index 400028e..947cfcd 100644 --- a/stage2/utils/source.spl +++ b/stage2/utils/source.spl @@ -123,7 +123,6 @@ fn drop(self: *Source) { Vec.drop(&self.line_starts); } -// ---- 多文件集合 ---- type Sources = struct { items: Vec, // Source @@ -191,7 +190,6 @@ fn set_drop(set: *Sources) { Map.drop(&set.by_name); } -// ---- 测试辅助 ---- fn view(text: []u8): ByteView { ret ByteView.from_slice(text); diff --git a/stage2/utils/str.spl b/stage2/utils/str.spl index be08213..7fcaca9 100644 --- a/stage2/utils/str.spl +++ b/stage2/utils/str.spl @@ -122,7 +122,6 @@ fn drop(self: *Str) { ByteBuffer.drop(&self.storage); } -// ---- 测试辅助 ---- fn expect_ok(result: Status) { match result { diff --git a/stage2/utils/utf8.spl b/stage2/utils/utf8.spl index 89732dc..2e21b9a 100644 --- a/stage2/utils/utf8.spl +++ b/stage2/utils/utf8.spl @@ -181,7 +181,6 @@ fn utf16_to_byte(data: *u8, len: usize, utf16_off: usize): usize { ret i; } -// ---- 测试辅助 ---- fn expect_ok(result: Status) { match result { diff --git a/stage2/utils/value.spl b/stage2/utils/value.spl index 7f781fa..68297c8 100644 --- a/stage2/utils/value.spl +++ b/stage2/utils/value.spl @@ -43,7 +43,6 @@ fn addr(value: *any): Value { ret .Ptr(value); } -// ---- 测试 ---- fn test_int_and_uint() { match int(-5) {