ERR/E4.1: trace.print_interpreter_frames() — Phase E4 complete

The last E4 item: a comptime call-frame dump.

- New nullary `interp_print_frames` IR op (inst/print). The interpreter
  maintains a `call_chain` side-stack (push/pop a FuncId around each sx-bodied
  `call`, freed in deinit) and `printInterpFrames` appends the chain to its
  output — most-recent-last, with the dump frame itself skipped. emit_llvm
  makes the op a no-op: compiled code has no interpreter stack, and the only
  caller is `process.exit`'s dead `is_comptime()` branch.
- Lowered from a name-recognized `__interp_print_frames()` builtin
  (tryLowerReflectionCall + inferExprType → void).
- `trace.print_interpreter_frames()` wraps the builtin; wired into
  `process.exit`'s comptime branch (process.sx now imports trace.sx).
- Frame source locations await IR-offset resolution (the comptime analog of
  DWARF), so only function names print today.

examples/252-interp-frames.sx (top-level `#run` drives the dump; exit 0).
Phase E4 (entry-point + stdlib error story) is now 100% complete.
This commit is contained in:
agra
2026-06-01 12:22:23 +03:00
parent e04bec488b
commit d67fb7b9b3
10 changed files with 88 additions and 0 deletions

View File

@@ -10327,6 +10327,11 @@ pub const Lowering = struct {
// serves both). Lets stdlib gate a comptime-only diagnostic branch.
return self.builder.emit(.{ .is_comptime = {} }, .bool);
}
if (std.mem.eql(u8, name, "__interp_print_frames")) {
// Backs `trace.print_interpreter_frames()`: dumps the interp call
// chain at comptime, no-op in compiled code (ERR E4.1).
return self.builder.emit(.{ .interp_print_frames = {} }, .void);
}
if (std.mem.eql(u8, name, "error_tag_name")) {
// error_tag_name(e) → look the error-set value's runtime tag id up
// in the always-linked tag-name table. The value IS its u32 tag id.
@@ -13962,6 +13967,7 @@ pub const Lowering = struct {
if (std.mem.eql(u8, bare_name, "field_name")) return .string;
if (std.mem.eql(u8, bare_name, "error_tag_name")) return .string;
if (std.mem.eql(u8, bare_name, "is_comptime")) return .bool;
if (std.mem.eql(u8, bare_name, "__interp_print_frames")) return .void;
if (std.mem.eql(u8, bare_name, "is_flags")) return .bool;
if (std.mem.eql(u8, bare_name, "type_of")) return .any;
if (std.mem.eql(u8, bare_name, "field_value")) return .any;