#import "std.sx"; // ===================================================================== // trace.sx — error return-trace formatting (ERR step E3.3). // // Reads the thread-local return-trace buffer (ERR E3.1, populated by the // push/clear wiring in E3.2) and renders it. A `raise` / propagating `try` // pushes a frame; an absorbing site (`catch` / `or value` / destructure) // clears the buffer. So at format time the buffer holds exactly the frames // of failures that escaped to where you're formatting — typically inside a // `catch` handler (the clear fires when the handler completes, so the body // still sees the chain) or the (future) failable-`main` wrapper. // // Frame resolution: a frame is an opaque u64. Resolving it to `file:line:col` // needs DWARF line-info (ERR E3.0), which sx does not emit yet — so for now // each frame prints as "". The frame COUNT, ordering, // and overflow note are already meaningful; once E3.0 lands, only the // per-frame location string changes. (The comptime path — resolving a packed // `(func_id, ir_offset)` via the interpreter's IR tables — also lands with the // resolver in E3.0/E3.3-full.) // ===================================================================== libc :: #library "c"; // The error-trace buffer C API (library/vendors/sx_trace_runtime/sx_trace.c), // linked in for the JIT and auto-injected for AOT when traces are used. sx_trace_len :: () -> u32 #foreign; sx_trace_truncated :: () -> u32 #foreign; sx_trace_frame_at :: (i: u32) -> u64 #foreign; write :: (fd: s32, buf: [*]u8, count: usize) -> isize #foreign libc; // Render the current trace buffer to a string (allocated from // context.allocator). Empty buffer → "" so callers can cheaply skip output. to_string :: () -> string { n := sx_trace_len(); if n == 0 { return ""; } result := "error return trace (most recent call last):\n"; if sx_trace_truncated() != 0 { result = concat(result, " ... older frames omitted (buffer full)\n"); } i : u32 = 0; while i < n { frame := sx_trace_frame_at(i); // DWARF (E3.0) will resolve `frame` to file:line:col + function name. // Until then the raw frame value is shown (a placeholder, not a PC yet). line := format(" frame {}: (raw {})\n", i, xx frame); result = concat(result, line); i = i + 1; } result; } // Write the current trace to stderr (fd 2). No-op when the buffer is empty. print_current :: () { s := to_string(); if s.len > 0 { write(2, s.ptr, xx s.len); } } // Dump the comptime (`#run`) interpreter call-frame chain (ERR E4.1). At // comptime the interpreter walks its active sx frames and appends them to the // build output; in compiled code this folds to nothing (there is no // interpreter stack — the only caller is a dead `is_comptime()` branch). // Frame source locations await IR-offset resolution, so only names print today. print_interpreter_frames :: () { __interp_print_frames(); }