// mir_builder_min.nyash — Minimal MIR(JSON v0) builder for selfhost tests // Scope: selfhost only (apps/selfhost/...); no core/runtime changes. using selfhost.shared.common.string_helpers as StringHelpers using selfhost.shared.common.box_helpers as BoxHelpers using lang.compiler.emit.common.json_emit as JsonEmitBox using lang.compiler.emit.common.mir_emit as MirEmitBox using lang.compiler.emit.common.call_emit as CallEmitBox using lang.compiler.emit.common.newbox_emit as NewBoxEmitBox using selfhost.shared.json.json_inst_encode_box as JsonInstEncodeBox box MirJsonBuilderMin { buf: StringBox phase: IntegerBox first_inst: IntegerBox blocks: ArrayBox cur_block_index: IntegerBox fn_name: StringBox trace: IntegerBox verify: IntegerBox birth() { me.buf = "" me.phase = 0 me.first_inst = 1 me.blocks = new ArrayBox() me.cur_block_index = -1 me.fn_name = "" me.trace = 0 me.verify = 0 } // Internal helpers _get_buf() { return me.buf } _set_buf(s) { me.buf = s return me } _append(s) { me.buf = me.buf + s return me } _int_to_str(n) { return StringHelpers.int_to_str(n) } _to_i64(x) { return StringHelpers.to_i64(x) } _quote(s) { return StringHelpers.json_quote(s) } _ids_range_json(start, count) { local i = 0 local out = "[" loop (i < count) { if i > 0 { out = out + "," } out = out + me._int_to_str(start + i) i = i + 1 } out = out + "]" return out } _ids_array_from_json_text(arr_text) { local out = new ArrayBox() if arr_text == null { return out } local s = "" + arr_text local i = 0 loop (i < s.length()) { local ch = s.substring(i, i+1) if ch >= "0" && ch <= "9" { local j = i loop (j < s.length()) { local cj = s.substring(j, j+1) if !(cj >= "0" && cj <= "9") { break } j = j + 1 } local num = me._to_i64(s.substring(i, j)) out.push(num) i = j } else { i = i + 1 } } return out } _ensure_phase(want) { if me.phase + 1 < want { return me } return me } // Public builder steps start_module() { if me.trace == 1 { print("[DEBUG start_module] starting") } me.phase = 1 return me._append("{\"functions\":[") } start_function(name) { if me.trace == 1 { print("[DEBUG start_function] name=" + name) } me.phase = 2 me.fn_name = name me.blocks = new ArrayBox() me.cur_block_index = -1 if me.trace == 1 { print("[DEBUG start_function] after set, fn_name=" + me.fn_name) } local b = "{\"name\":" + me._quote(name) + ",\"params\":[],\"blocks\":[" return me._append(b) } start_block(id) { me.phase = 3 me.first_inst = 1 local blk = { id: id, instructions: new ArrayBox() } me.blocks.push(blk) me.cur_block_index = me.blocks.length() - 1 local b = "{\"id\":" + me._int_to_str(id) + ",\"instructions\":[" return me._append(b) } end_block_continue() { return me._append("]},") } _comma_if_needed() { if me.first_inst == 1 { me.first_inst = 0 return me } return me._append(",") } add_const(dst, val) { me._comma_if_needed() local node = MirEmitBox.make_const(dst, val) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_compare(kind, lhs, rhs, dst) { me._comma_if_needed() local node = MirEmitBox.make_compare(kind, lhs, rhs, dst) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_binop(kind, lhs, rhs, dst) { me._comma_if_needed() local node = { op:"binop", op_kind:kind, lhs:lhs, rhs:rhs, dst:dst } me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_ret(val) { me._comma_if_needed() local node = MirEmitBox.make_ret(val) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_call_ids(name, args_json_text, dst) { me._comma_if_needed() local args = me._ids_array_from_json_text(args_json_text) local node = CallEmitBox.make_call(name, args, dst) node.set("args_text", args_json_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_call_range(name, start, count, dst) { me._comma_if_needed() local args = new ArrayBox() local i = 0 loop(i < count) { args.push(start + i) i = i + 1 } local args_text = me._ids_range_json(start, count) local node = CallEmitBox.make_call(name, args, dst) node.set("args_text", args_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_boxcall_range(method, recv_id, args_start, count, dst) { me._comma_if_needed() local args = new ArrayBox() local i = 0 loop(i < count) { args.push(args_start + i) i = i + 1 } local args_text = me._ids_range_json(args_start, count) local node = CallEmitBox.make_boxcall(method, recv_id, args, dst) node.set("args_text", args_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_newbox_range(box_type, args_start, count, dst) { me._comma_if_needed() local args = new ArrayBox() local i = 0 loop(i < count) { args.push(args_start + i) i = i + 1 } local node = NewBoxEmitBox.with_args_array(NewBoxEmitBox.make_new(box_type, args, dst), args) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_newbox_ids(box_type, args_json_text, dst) { me._comma_if_needed() local args = me._ids_array_from_json_text(args_json_text) local node = NewBoxEmitBox.make_new(box_type, args, dst) node = NewBoxEmitBox.with_args_text(node, args_json_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } _args_array_json_from_ids(ids_start, count) { return me._ids_range_json(ids_start, count) } add_mir_call_global_ids(name, args_json_text, dst) { me._comma_if_needed() local args = me._ids_array_from_json_text(args_json_text) local node = CallEmitBox.make_mir_call_global(name, args, dst) node.set("args_text", args_json_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_mir_call_extern_ids(name, args_json_text, dst) { me._comma_if_needed() local args = me._ids_array_from_json_text(args_json_text) local node = CallEmitBox.make_mir_call_extern(name, args, dst) node.set("args_text", args_json_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_mir_call_method_ids(method, recv_id, args_json_text, dst) { me._comma_if_needed() local args = me._ids_array_from_json_text(args_json_text) local node = CallEmitBox.make_mir_call_method(method, recv_id, args, dst) node.set("args_text", args_json_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_mir_call_constructor_ids(box_type, args_json_text, dst) { me._comma_if_needed() local args = me._ids_array_from_json_text(args_json_text) local node = CallEmitBox.make_mir_call_constructor(box_type, args, dst) node.set("args_text", args_json_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_mir_call_global_range(name, start, count, dst) { me._comma_if_needed() local args = new ArrayBox() local i = 0 loop(i < count) { args.push(start + i) i = i + 1 } local args_text = me._ids_range_json(start, count) local node = CallEmitBox.make_mir_call_global(name, args, dst) node.set("args_text", args_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_mir_call_extern_range(name, start, count, dst) { me._comma_if_needed() local args = new ArrayBox() local i = 0 loop(i < count) { args.push(start + i) i = i + 1 } local args_text = me._ids_range_json(start, count) local node = CallEmitBox.make_mir_call_extern(name, args, dst) node.set("args_text", args_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_mir_call_method_range(method, recv_id, args_start, count, dst) { me._comma_if_needed() local args = new ArrayBox() local i = 0 loop(i < count) { args.push(args_start + i) i = i + 1 } local args_text = me._ids_range_json(args_start, count) local node = CallEmitBox.make_mir_call_method(method, recv_id, args, dst) node.set("args_text", args_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_mir_call_constructor_range(box_type, args_start, count, dst) { me._comma_if_needed() local args = new ArrayBox() local i = 0 loop(i < count) { args.push(args_start + i) i = i + 1 } local args_text = me._ids_range_json(args_start, count) local node = CallEmitBox.make_mir_call_constructor(box_type, args, dst) node.set("args_text", args_text) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_branch(cond, then_id, else_id) { me._comma_if_needed() local node = MirEmitBox.make_branch(cond, then_id, else_id) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_jump(target) { me._comma_if_needed() local node = MirEmitBox.make_jump(target) me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } add_copy(dst, src) { me._comma_if_needed() local node = { op:"copy", dst:dst, src:src } me._push_inst_map(node) return me._append(JsonEmitBox.to_json(node)) } end_all() { me.phase = 5 return me._append("]}]}]}") } to_string() { return me._get_buf() } _cur_insts() { local blks = me.blocks if blks == null { return null } local n = 0 n = BoxHelpers.array_len(blks) if n <= 0 { return null } local idx = me.cur_block_index if idx == null { idx = -1 } if idx < 0 || idx >= n { idx = n - 1 } local blk = BoxHelpers.array_get(blks, idx) if blk == null { return null } return BoxHelpers.map_get(blk, "instructions") } verify_builder_state() { return 0 } _verify_enabled() { return me.verify } _trace_enabled() { return me.trace } _push_inst(node) { local before = 0 local insts0 = me._cur_insts() before = BoxHelpers.array_len(insts0) if insts0 == null || insts0.push == null { return } insts0.push(node) if me._verify_enabled() == 1 { local insts1 = me._cur_insts() local after = BoxHelpers.array_len(insts1) local op_str = BoxHelpers.map_get(node, "op") if after != before + 1 { print("[builder-verify] size mismatch before=" + before + " after=" + after + " op=" + op_str) } } if me._trace_enabled() == 1 { local op_str_trace = BoxHelpers.map_get(node, "op") print("[builder-trace] push op=" + op_str_trace) } } _push_inst_map(node) { return me._push_inst(node) } enable_trace(on) { if on == null { on = 1 } me.trace = on return me } enable_verify(on) { if on == null { on = 1 } me.verify = on return me } get_current_instructions() { return me._cur_insts() } get_blocks_array() { return me.blocks } get_function_structure() { local blks = me.get_blocks_array() return { name: me.fn_name, params: new ArrayBox(), blocks: blks } } emit_to_string() { return me.to_string() } _inst_json(node) { return JsonInstEncodeBox.encode(node) } to_string_rebuild() { local name = me.fn_name local blks = me.get_blocks_array() local blks_size_str = "null" local blks_len = BoxHelpers.array_len(blks) if blks_len >= 0 { blks_size_str = me._int_to_str(blks_len) } print("[DEBUG rebuild] fn_name=" + name + " blks.length()=" + blks_size_str) local out = "{\"functions\":[{\"name\":" + me._quote(name) + ",\"params\":[],\"blocks\":[" local n = blks_len print("[DEBUG rebuild] n=" + me._int_to_str(n)) local i = 0 loop (i < n) { if i > 0 { out = out + "," } local blk = BoxHelpers.array_get(blks, i) local bid = BoxHelpers.map_get(blk, "id") out = out + "{\"id\":" + me._int_to_str(bid) + ",\"instructions\":[" local insts = BoxHelpers.map_get(blk, "instructions") local m = BoxHelpers.array_len(insts) local j = 0 loop (j < m) { if j > 0 { out = out + "," } out = out + me._inst_json(BoxHelpers.array_get(insts, j)) j = j + 1 } out = out + "]}" i = i + 1 } out = out + "]}]}" return out } }