Vector :: ($N: int, $T: Type) -> Type #builtin; out :: (str: string) -> void #builtin; size_of :: ($T: Type) -> s64 #builtin; malloc :: (size: s64) -> *void #builtin; memcpy :: (dst: *void, src: *void, size: s64) -> *void #builtin; memset :: (dst: *void, val: s64, size: s64) -> void #builtin; free :: (ptr: *void) -> void #builtin; type_of :: (val: $T) -> Type #builtin; type_name :: ($T: Type) -> string #builtin; field_count :: ($T: Type) -> s64 #builtin; field_name :: ($T: Type, idx: s64) -> string #builtin; field_value :: (s: $T, idx: s64) -> Any #builtin; is_flags :: ($T: Type) -> bool #builtin; field_value_int :: ($T: Type, idx: s64) -> s64 #builtin; field_index :: ($T: Type, val: T) -> s64 #builtin; string :: []u8 #builtin; #import "allocators.sx"; // --- Context --- Context :: struct { allocator: Allocator; data: *void; } context : Context = ---; // --- Slice & string allocation --- context_alloc :: (size: s64) -> *void { if context.allocator.ctx != null then context.allocator.alloc(size) else malloc(size); } cstring :: (size: s64) -> string { raw := context_alloc(size + 1); memset(raw, 0, size + 1); s : string = ---; s.ptr = xx raw; s.len = size; s; } alloc_slice :: ($T: Type, count: s64) -> []T { raw := context_alloc(count * size_of(T)); memset(raw, 0, count * size_of(T)); s : []T = ---; s.ptr = xx raw; s.len = count; s; } int_to_string :: (n: s64) -> string { if n == 0 { return "0"; } neg := n < 0; v := if neg then 0 - n else n; // Single pass: fill digits backwards into temp string, then substr tmp := cstring(20); i := 19; while v > 0 { tmp[i] = (v % 10) + 48; v = v / 10; i -= 1; } if neg { tmp[i] = 45; i -= 1; } substr(tmp, i + 1, 20 - i - 1); } bool_to_string :: (b: bool) -> string { if b then "true" else "false"; } float_to_string :: (f: f64) -> string { neg := f < 0.0; v := if neg then 0.0 - f else f; int_part := cast(s64) v; frac := cast(s64) ((v - cast(f64) int_part) * 1000000.0); if frac < 0 { frac = 0 - frac; } istr := int_to_string(int_part); fstr := int_to_string(frac); il := istr.len; fl := fstr.len; prefix := if neg then 1 else 0; total := prefix + il + 1 + 6; buf := cstring(total); pos := 0; if neg { buf[0] = 45; pos = 1; } memcpy(@buf[pos], istr.ptr, il); pos = pos + il; buf[pos] = 46; pos += 1; pad := 6 - fl; memset(@buf[pos], 48, pad); pos = pos + pad; memcpy(@buf[pos], fstr.ptr, fl); buf; } hex_group :: (buf: string, offset: s64, val: s64) { i := offset + 3; v := val; while i >= offset { d := v % 16; buf[i] = if d < 10 then d + 48 else d - 10 + 97; v = v / 16; i -= 1; } } int_to_hex_string :: (n: s64) -> string { if n == 0 { return "0"; } // Split into four 16-bit groups for correct unsigned treatment g0 := n % 65536; if g0 < 0 { g0 = g0 + 65536; } r1 := (n - g0) / 65536; g1 := r1 % 65536; if g1 < 0 { g1 = g1 + 65536; } r2 := (r1 - g1) / 65536; g2 := r2 % 65536; if g2 < 0 { g2 = g2 + 65536; } r3 := (r2 - g2) / 65536; g3 := r3 % 65536; if g3 < 0 { g3 = g3 + 65536; } buf := cstring(16); hex_group(buf, 0, g3); hex_group(buf, 4, g2); hex_group(buf, 8, g1); hex_group(buf, 12, g0); // Skip leading zeros (keep at least 1 digit) start := 0; while start < 15 { if buf[start] != 48 { break; } start += 1; } substr(buf, start, 16 - start); } concat :: (a: string, b: string) -> string { al := a.len; bl := b.len; buf := cstring(al + bl); memcpy(buf.ptr, a.ptr, al); memcpy(@buf[al], b.ptr, bl); buf; } substr :: (s: string, start: s64, len: s64) -> string { buf := cstring(len); memcpy(buf.ptr, @s[start], len); buf; } struct_to_string :: (s: $T) -> string { result := concat(type_name(T), "{"); i := 0; while i < field_count(T) { if i > 0 { result = concat(result, ", "); } result = concat(result, field_name(T, i)); result = concat(result, ": "); result = concat(result, any_to_string(field_value(s, i))); i += 1; } concat(result, "}"); } vector_to_string :: (v: $T) -> string { result := "["; i := 0; while i < field_count(T) { if i > 0 { result = concat(result, ", "); } result = concat(result, any_to_string(field_value(v, i))); i += 1; } concat(result, "]"); } array_to_string :: (a: $T) -> string { result := "["; i := 0; while i < field_count(T) { if i > 0 { result = concat(result, ", "); } result = concat(result, any_to_string(field_value(a, i))); i += 1; } concat(result, "]"); } slice_to_string :: (items: []$T) -> string { result := "["; i := 0; while i < items.len { if i > 0 { result = concat(result, ", "); } result = concat(result, any_to_string(field_value(items, i))); i += 1; } concat(result, "]"); } pointer_to_string :: (p: $T) -> string { addr : s64 = xx p; if addr == 0 { "null"; } else { concat(type_name(T), concat("@0x", int_to_hex_string(addr))); } } flags_to_string :: (val: $T) -> string { v := cast(s64) val; result := ""; i := 0; while i < field_count(T) { fv := field_value_int(T, i); if v & fv { if result.len > 0 { result = concat(result, " | "); } result = concat(result, concat(".", field_name(T, i))); } i += 1; } if result.len == 0 { result = "0"; } result; } enum_to_string :: (u: $T) -> string { if is_flags(T) { return flags_to_string(u); } idx := field_index(T, u); result := concat(".", field_name(T, idx)); payload := field_value(u, idx); pstr := any_to_string(payload); if pstr.len > 0 { result = concat(result, concat("(", concat(pstr, ")"))); } result; } any_to_string :: (val: Any) -> string { result := ""; type := type_of(val); if type == { case void: result = ""; case int: result = int_to_string(xx val); case string: { s : string = xx val; result = s; } case bool: result = bool_to_string(xx val); case float: result = float_to_string(xx val); case struct: result = struct_to_string(cast(type) val); case enum: result = enum_to_string(cast(type) val); case vector: result = vector_to_string(cast(type) val); case array: result = array_to_string(cast(type) val); case slice: result = slice_to_string(cast(type) val); case pointer: result = pointer_to_string(cast(type) val); case type: { s : string = xx val; result = s; } } result; } build_format :: (fmt: string) -> string { code := "result := \"\"; "; seg_start := 0; i := 0; arg_idx := 0; while i < fmt.len { if fmt[i] == 123 { if i + 1 < fmt.len { if fmt[i + 1] == 125 { if i > seg_start { code = concat(code, "result = concat(result, substr(fmt, "); code = concat(code, int_to_string(seg_start)); code = concat(code, ", "); code = concat(code, int_to_string(i - seg_start)); code = concat(code, ")); "); } code = concat(code, "result = concat(result, any_to_string(args["); code = concat(code, int_to_string(arg_idx)); code = concat(code, "])); "); arg_idx += 1; i += 2; seg_start = i; } else if fmt[i + 1] == 123 { code = concat(code, "result = concat(result, substr(fmt, "); code = concat(code, int_to_string(seg_start)); code = concat(code, ", "); code = concat(code, int_to_string(i - seg_start + 1)); code = concat(code, ")); "); i += 2; seg_start = i; } else { i += 1; } } else { i += 1; } } else if fmt[i] == 125 { if i + 1 < fmt.len { if fmt[i + 1] == 125 { code = concat(code, "result = concat(result, substr(fmt, "); code = concat(code, int_to_string(seg_start)); code = concat(code, ", "); code = concat(code, int_to_string(i - seg_start + 1)); code = concat(code, ")); "); i += 2; seg_start = i; } else { i += 1; } } else { i += 1; } } else { i += 1; } } if seg_start < fmt.len { code = concat(code, "result = concat(result, substr(fmt, "); code = concat(code, int_to_string(seg_start)); code = concat(code, ", "); code = concat(code, int_to_string(fmt.len - seg_start)); code = concat(code, ")); "); } code; } format :: ($fmt: string, args: ..Any) -> string { #insert build_format(fmt); #insert "result;"; } print :: ($fmt: string, args: ..Any) { #insert build_format(fmt); #insert "out(result);"; } List :: struct ($T: Type) { items: [*]T = null; len: s64 = 0; cap: s64 = 0; } append ::(list: *List($T), item: T) { if list.len >= list.cap { new_cap := if list.cap == 0 then 4 else list.cap * 2; new_items : [*]T = xx malloc(new_cap * size_of(T)); if list.len > 0 { memcpy(new_items, list.items, list.len * size_of(T)); free(list.items); } list.items = new_items; list.cap = new_cap; } list.items[list.len] = item; list.len += 1; }