lang: rename signed integer types sN -> iN

Surface rename of the signed integer family: s1..s64 become i1..i64
(u1..u64, usize, isize unchanged). 'string' keeps the s-prefix arm in
name classification; width parsing moves to the i-prefix arm next to
isize.

Internal TypeId tags follow the surface (.s8/.s16/.s32/.s64 ->
.i8/.i16/.i32/.i64), as do mono-key mangle fragments (ptr_i64,
tu_i64_bool) and all display/diagnostic formatting (i{d}).

Migrated in the same sweep: stdlib + examples + issue repros + FFI C
companions (shared symbol names like ffi_id_i64), expected
stdout/stderr/ir snapshots, specs.md, readme.md, CLAUDE.md/AGENTS.md,
implementation_plan.md, docs/, issue writeups. Vendored stb_image and
historical flow state left untouched.

zig build test: 426/426; examples suite: 595/595.
This commit is contained in:
agra
2026-06-12 09:31:53 +03:00
parent 515ecebea7
commit d8076b9333
1054 changed files with 6836 additions and 6839 deletions

View File

@@ -38,11 +38,11 @@ libc :: #library "c";
// macOS C-runtime argv/argc accessors (crt_externs.h):
// extern char ***_NSGetArgv(void); extern int *_NSGetArgc(void);
// Each returns a pointer to the runtime's slot; dereference once for the
// `char**` / `int` the process was launched with. Declared as `*s64` /
// `*s32` since on 64-bit a `char***` is just a pointer to a pointer-sized
// `char**` / `int` the process was launched with. Declared as `*i64` /
// `*i32` since on 64-bit a `char***` is just a pointer to a pointer-sized
// slot.
ns_get_argv :: () -> *s64 #foreign libc "_NSGetArgv";
ns_get_argc :: () -> *s32 #foreign libc "_NSGetArgc";
ns_get_argv :: () -> *i64 #foreign libc "_NSGetArgv";
ns_get_argc :: () -> *i32 #foreign libc "_NSGetArgc";
// =====================================================================
// EXIT-CODE & `--json` CONTRACT (F3.3) — the minimal surface `dist` (and
@@ -80,9 +80,9 @@ exit_usage :: () -> noreturn { proc.exit(EX_USAGE); }
// Number of process arguments (argc). >= 1 for any normally-launched
// process, since argv[0] is the executable path.
os_argc :: () -> s64 {
os_argc :: () -> i64 {
inline if OS == {
case .macos: { return cast(s64) ns_get_argc().*; }
case .macos: { return cast(i64) ns_get_argc().*; }
else: {
out("std.cli: unsupported platform — only macOS is implemented (needs _NSGetArgv/_NSGetArgc).\n");
proc.exit(EX_UNAVAILABLE);
@@ -102,8 +102,8 @@ os_argc :: () -> s64 {
os_args :: (buf: []string) -> []string {
inline if OS == {
case .macos: {
argc := cast(s64) ns_get_argc().*;
argv : [*]s64 = xx ns_get_argv().*;
argc := cast(i64) ns_get_argc().*;
argv : [*]i64 = xx ns_get_argv().*;
n := if argc > buf.len then buf.len else argc;
i := 0;
while i < n {
@@ -216,7 +216,7 @@ FlagValue :: struct {
// the failure names a flag rather than an input token (a missing required
// flag sets `token` to the flag name).
Diag :: struct {
index: s64 = -1;
index: i64 = -1;
token: string = "";
}
@@ -225,7 +225,7 @@ Diag :: struct {
Parsed :: struct {
group: string;
command: string;
cmd_index: s64;
cmd_index: i64;
json: bool; // `--json` mode: true iff `--json` is in argv
rest: []string;
spec: []FlagSpec; // view of the matched command's flag specs

View File

@@ -8,27 +8,27 @@ out :: (str: string) -> void #builtin;
// sqrt :: (x: $T) -> T #builtin;
// sin :: (x: $T) -> T #builtin;
// cos :: (x: $T) -> T #builtin;
size_of :: ($T: Type) -> s64 #builtin;
align_of :: ($T: Type) -> s64 #builtin;
size_of :: ($T: Type) -> i64 #builtin;
align_of :: ($T: Type) -> i64 #builtin;
// Low-level libc bindings, used by allocator implementations to avoid
// recursing through `context.allocator`. The bare `malloc`/`free`
// spellings are NOT declared: the Allocator protocol + the std/mem.sx
// helpers are the allocation surface (`free` is the typed slice helper
// there). Raw libc escape hatch: `libc_malloc` / `libc_free`.
libc_malloc :: (size: s64) -> *void #foreign libc "malloc";
libc_malloc :: (size: i64) -> *void #foreign libc "malloc";
libc_free :: (ptr: *void) -> void #foreign libc "free";
memcpy :: (dst: *void, src: *void, size: s64) -> *void #foreign libc "memcpy";
memset :: (dst: *void, val: s64, size: s64) -> void #foreign libc "memset";
memcpy :: (dst: *void, src: *void, size: i64) -> *void #foreign libc "memcpy";
memset :: (dst: *void, val: i64, size: i64) -> void #foreign libc "memset";
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;
field_count :: ($T: Type) -> i64 #builtin;
field_name :: ($T: Type, idx: i64) -> string #builtin;
field_value :: (s: $T, idx: i64) -> Any #builtin;
is_flags :: ($T: Type) -> bool #builtin;
type_is_unsigned :: ($T: Type) -> bool #builtin;
field_value_int :: ($T: Type, idx: s64) -> s64 #builtin;
field_index :: ($T: Type, val: T) -> s64 #builtin;
field_value_int :: ($T: Type, idx: i64) -> i64 #builtin;
field_index :: ($T: Type, val: T) -> i64 #builtin;
error_tag_name :: (e: $T) -> string #builtin;
// Call-site location, synthesized by the `#caller_location` directive when it
@@ -36,8 +36,8 @@ error_tag_name :: (e: $T) -> string #builtin;
// to report where they were invoked.
Source_Location :: struct {
file: string;
line: s32;
col: s32;
line: i32;
col: i32;
func: string;
}
string :: []u8 #builtin;
@@ -47,7 +47,7 @@ string :: []u8 #builtin;
// Bytes-level primitives carry the `_bytes` suffix so the typed
// helpers in std/mem.sx own the bare names (`alloc(T, n)`, `free(s)`).
Allocator :: protocol #inline {
alloc_bytes :: (size: s64) -> *void;
alloc_bytes :: (size: i64) -> *void;
dealloc_bytes :: (ptr: *void);
}

View File

@@ -6,7 +6,7 @@
// --- Slice & string allocation ---
cstring :: (size: s64) -> string {
cstring :: (size: i64) -> string {
raw := context.allocator.alloc_bytes(size + 1);
memset(raw, 0, size + 1);
s : string = ---;
@@ -15,7 +15,7 @@ cstring :: (size: s64) -> string {
s
}
alloc_slice :: ($T: Type, count: s64) -> []T {
alloc_slice :: ($T: Type, count: i64) -> []T {
raw := context.allocator.alloc_bytes(count * size_of(T));
memset(raw, 0, count * size_of(T));
s : []T = ---;
@@ -24,12 +24,12 @@ alloc_slice :: ($T: Type, count: s64) -> []T {
s
}
int_to_string :: (n: s64) -> string {
int_to_string :: (n: i64) -> string {
if n == 0 { return "0"; }
neg := n < 0;
// Extract digits straight from `n` without ever negating it: `0 - n`
// overflows for s64::MIN (its magnitude is unrepresentable as a
// positive s64). sx `%` truncates toward zero, so `n % 10` keeps n's
// overflows for i64::MIN (its magnitude is unrepresentable as a
// positive i64). sx `%` truncates toward zero, so `n % 10` keeps n's
// sign; take each remainder's absolute value for the digit.
tmp := cstring(20);
i := 19;
@@ -47,13 +47,13 @@ int_to_string :: (n: s64) -> string {
// Unsigned decimal of `n`'s 64 bits — renders the full u64 range
// (0 .. 18446744073709551615). Used by `any_to_string` for unsigned
// integer values, which an s64-based formatter would misread (e.g. a
// integer values, which an i64-based formatter would misread (e.g. a
// u64 all-ones value as -1).
uint_to_string :: (n: s64) -> string {
uint_to_string :: (n: i64) -> string {
if n == 0 { return "0"; }
// Long division by 10 across the four unsigned 16-bit limbs, most
// significant first. Each step folds the running remainder into the
// next limb; the per-step accumulator stays well within s64
// next limb; the per-step accumulator stays well within i64
// (max 9*65536 + 65535), so signed `/` and `%` are exact.
g := decompose_u16x4(n);
tmp := cstring(20);
@@ -80,8 +80,8 @@ bool_to_string :: (b: bool) -> string {
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);
int_part := cast(i64) v;
frac := cast(i64) ((v - cast(f64) int_part) * 1000000.0);
if frac < 0 { frac = 0 - frac; }
istr := int_to_string(int_part);
fstr := int_to_string(frac);
@@ -103,7 +103,7 @@ float_to_string :: (f: f64) -> string {
buf
}
hex_group :: (buf: string, offset: s64, val: s64) {
hex_group :: (buf: string, offset: i64, val: i64) {
i := offset + 3;
v := val;
while i >= offset {
@@ -120,7 +120,7 @@ hex_group :: (buf: string, offset: s64, val: s64) {
// back into 0..65535 — so callers get correct unsigned arithmetic out
// of a signed-only integer type. Shared by the hex and unsigned-decimal
// formatters.
decompose_u16x4 :: (n: s64) -> [4]s64 {
decompose_u16x4 :: (n: i64) -> [4]i64 {
g0 := n % 65536;
if g0 < 0 { g0 = g0 + 65536; }
r1 := (n - g0) / 65536;
@@ -132,7 +132,7 @@ decompose_u16x4 :: (n: s64) -> [4]s64 {
r3 := (r2 - g2) / 65536;
g3 := r3 % 65536;
if g3 < 0 { g3 = g3 + 65536; }
limbs : [4]s64 = ---;
limbs : [4]i64 = ---;
limbs[0] = g3;
limbs[1] = g2;
limbs[2] = g1;
@@ -140,7 +140,7 @@ decompose_u16x4 :: (n: s64) -> [4]s64 {
limbs
}
int_to_hex_string :: (n: s64) -> string {
int_to_hex_string :: (n: i64) -> string {
if n == 0 { return "0"; }
g := decompose_u16x4(n);
@@ -168,7 +168,7 @@ concat :: (a: string, b: string) -> string {
buf
}
substr :: (s: string, start: s64, len: s64) -> string {
substr :: (s: string, start: i64, len: i64) -> string {
buf := cstring(len);
memcpy(buf.ptr, @s[start], len);
buf
@@ -251,14 +251,14 @@ slice_to_string :: (items: []$T) -> string {
}
pointer_to_string :: (p: $T) -> string {
addr : s64 = xx p;
addr : i64 = 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;
v := cast(i64) val;
result := "";
i := 0;
while i < field_count(T) {

View File

@@ -24,36 +24,36 @@ libc :: #library "c";
// API below wraps them. Users should not call these directly.
//
// macOS `open` is variadic in C (`int open(const char*, int, ...)`);
// declared with `..args: []s32` so the mode is passed via the C
// declared with `..args: []i32` so the mode is passed via the C
// variadic tail. Without that, the mode arg goes to the wrong
// register on arm64 and the file ends up with mode 0.
open :: (path: [:0]u8, flags: s32, ..args: []s32) -> s32 #foreign libc;
close :: (fd: s32) -> s32 #foreign libc;
read :: (fd: s32, buf: [*]u8, count: usize) -> isize #foreign libc;
write :: (fd: s32, buf: [*]u8, count: usize) -> isize #foreign libc;
lseek :: (fd: s32, offset: s64, whence: s32) -> s64 #foreign libc;
unlink :: (path: [:0]u8) -> s32 #foreign libc;
rmdir :: (path: [:0]u8) -> s32 #foreign libc;
mkdir :: (path: [:0]u8, mode: u32) -> s32 #foreign libc;
access :: (path: [:0]u8, mode: s32) -> s32 #foreign libc;
chmod :: (path: [:0]u8, mode: u32) -> s32 #foreign libc;
rename :: (oldp: [:0]u8, newp: [:0]u8) -> s32 #foreign libc;
open :: (path: [:0]u8, flags: i32, ..args: []i32) -> i32 #foreign libc;
close :: (fd: i32) -> i32 #foreign libc;
read :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc;
write :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc;
lseek :: (fd: i32, offset: i64, whence: i32) -> i64 #foreign libc;
unlink :: (path: [:0]u8) -> i32 #foreign libc;
rmdir :: (path: [:0]u8) -> i32 #foreign libc;
mkdir :: (path: [:0]u8, mode: u32) -> i32 #foreign libc;
access :: (path: [:0]u8, mode: i32) -> i32 #foreign libc;
chmod :: (path: [:0]u8, mode: u32) -> i32 #foreign libc;
rename :: (oldp: [:0]u8, newp: [:0]u8) -> i32 #foreign libc;
// macOS POSIX constants. Linux values differ; split into platform-
// conditional includes when we gain a Linux host.
O_RDONLY :s32: 0x0000;
O_WRONLY :s32: 0x0001;
O_RDWR :s32: 0x0002;
O_APPEND :s32: 0x0008;
O_CREAT :s32: 0x0200;
O_TRUNC :s32: 0x0400;
O_RDONLY :i32: 0x0000;
O_WRONLY :i32: 0x0001;
O_RDWR :i32: 0x0002;
O_APPEND :i32: 0x0008;
O_CREAT :i32: 0x0200;
O_TRUNC :i32: 0x0400;
SEEK_SET :s32: 0;
SEEK_CUR :s32: 1;
SEEK_END :s32: 2;
SEEK_SET :i32: 0;
SEEK_CUR :i32: 1;
SEEK_END :i32: 2;
F_OK :s32: 0;
F_OK :i32: 0;
// ── Public types ─────────────────────────────────────────────────────
@@ -67,7 +67,7 @@ OpenMode :: enum {
SeekFrom :: enum { set; current; end; }
File :: struct {
fd: s32 = -1;
fd: i32 = -1;
is_valid :: (self: *File) -> bool { self.fd >= 0 }
@@ -78,19 +78,19 @@ File :: struct {
rc == 0
}
read :: (self: *File, buf: string) -> s64 {
read :: (self: *File, buf: string) -> i64 {
if self.fd < 0 { return -1; }
n := read(self.fd, buf.ptr, xx buf.len);
cast(s64) n
cast(i64) n
}
write :: (self: *File, data: string) -> s64 {
write :: (self: *File, data: string) -> i64 {
if self.fd < 0 { return -1; }
n := write(self.fd, data.ptr, xx data.len);
cast(s64) n
cast(i64) n
}
seek :: (self: *File, offset: s64, whence: SeekFrom) -> s64 {
seek :: (self: *File, offset: i64, whence: SeekFrom) -> i64 {
if self.fd < 0 { return -1; }
w := SEEK_SET;
if whence == .current { w = SEEK_CUR; }
@@ -105,7 +105,7 @@ File :: struct {
// idea for `delete_file`/`delete_dir` vs libc's `unlink`/`rmdir`,
// `set_mode` vs libc's `chmod`, etc.
mode_to_flags :: (m: OpenMode) -> s32 {
mode_to_flags :: (m: OpenMode) -> i32 {
if m == .read { return O_RDONLY; }
if m == .write { return O_WRONLY | O_CREAT | O_TRUNC; }
if m == .append { return O_WRONLY | O_CREAT | O_APPEND; }
@@ -133,7 +133,7 @@ read_file :: (path: [:0]u8) -> ?string {
buf := cstring(size);
n := read(fd, buf.ptr, xx size);
close(fd);
if cast(s64) n != size { return null; }
if cast(i64) n != size { return null; }
buf
}
@@ -143,7 +143,7 @@ write_file :: (path: [:0]u8, data: string) -> bool {
if fd < 0 { return false; }
n := write(fd, data.ptr, xx data.len);
close(fd);
cast(s64) n == cast(s64) data.len
cast(i64) n == cast(i64) data.len
}
append_file :: (path: [:0]u8, data: string) -> bool {
@@ -151,7 +151,7 @@ append_file :: (path: [:0]u8, data: string) -> bool {
if fd < 0 { return false; }
n := write(fd, data.ptr, xx data.len);
close(fd);
cast(s64) n == cast(s64) data.len
cast(i64) n == cast(i64) data.len
}
// ── Single-syscall ops ───────────────────────────────────────────────

View File

@@ -3,7 +3,7 @@
//
// Content addressing is security-critical, so the digest is computed
// in-process: no shelling out, no platform crypto library. All 32-bit
// word arithmetic is done in s64 and masked back to 32 bits with
// word arithmetic is done in i64 and masked back to 32 bits with
// `& MASK32`, so the result is identical regardless of the host's
// native integer width or overflow behaviour.
//
@@ -39,7 +39,7 @@ MASK32 :: 0xFFFFFFFF;
// Round constants K[0..63] — the first 32 bits of the fractional parts
// of the cube roots of the first 64 primes (FIPS 180-4 §4.2.2).
K : [64]s64 = .[
K : [64]i64 = .[
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
@@ -51,31 +51,31 @@ K : [64]s64 = .[
];
// 32-bit right rotate. `word` must already be masked to 32 bits.
rotr :: (word: s64, n: s64) -> s64 {
rotr :: (word: i64, n: i64) -> i64 {
((word >> n) | (word << (32 - n))) & MASK32
}
big_sigma0 :: (x: s64) -> s64 { rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22) }
big_sigma1 :: (x: s64) -> s64 { rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25) }
small_sigma0 :: (x: s64) -> s64 { rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3) }
small_sigma1 :: (x: s64) -> s64 { rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10) }
big_sigma0 :: (x: i64) -> i64 { rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22) }
big_sigma1 :: (x: i64) -> i64 { rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25) }
small_sigma0 :: (x: i64) -> i64 { rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3) }
small_sigma1 :: (x: i64) -> i64 { rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10) }
Sha256 :: struct {
h: [8]s64; // running hash state (each entry masked to 32 bits)
h: [8]i64; // running hash state (each entry masked to 32 bits)
buf: [64]u8; // partial-block buffer
buf_len: s64; // bytes currently in `buf` (0..63)
total_len: s64; // total bytes absorbed so far
buf_len: i64; // bytes currently in `buf` (0..63)
total_len: i64; // total bytes absorbed so far
// Crunch the 64-byte block currently in `buf` into the state.
process_block :: (self: *Sha256) {
w : [64]s64 = ---;
w : [64]i64 = ---;
t := 0;
while t < 16 {
base := t * 4;
w[t] = ((cast(s64) self.buf[base]) << 24)
| ((cast(s64) self.buf[base + 1]) << 16)
| ((cast(s64) self.buf[base + 2]) << 8)
| (cast(s64) self.buf[base + 3]);
w[t] = ((cast(i64) self.buf[base]) << 24)
| ((cast(i64) self.buf[base + 1]) << 16)
| ((cast(i64) self.buf[base + 2]) << 8)
| (cast(i64) self.buf[base + 3]);
t += 1;
}
t = 16;
@@ -186,7 +186,7 @@ Sha256 :: struct {
}
// Lowercase-hex ASCII byte for a 0..15 nibble. 48='0', 97='a'.
nibble_hex :: (n: s64) -> u8 {
nibble_hex :: (n: i64) -> u8 {
if n < 10 then xx (n + 48) else xx (n - 10 + 97)
}

View File

@@ -4,7 +4,7 @@
// This module delivers the JSON VALUE MODEL, the WRITER, and the READER
// (parser). The model is built once and shared by both directions.
//
// NUMBERS ARE INTEGERS ONLY (s64) for this milestone — there is no
// NUMBERS ARE INTEGERS ONLY (i64) for this milestone — there is no
// fraction or exponent. A JSON value is one of: null, bool, integer,
// string, array, object. The reader REJECTS a fraction or exponent
// (`error.BadNumber`) rather than silently truncating it.
@@ -82,7 +82,7 @@ JsonError :: error { Overflow, Io }
Value :: enum {
null_;
bool_: bool;
int_: s64;
int_: i64;
str: string; // view into caller-owned bytes; not copied
array: Array;
object: Object;
@@ -100,8 +100,8 @@ Member :: struct {
// allocator explicitly.
Array :: struct {
items: [*]Value = null;
len: s64 = 0;
cap: s64 = 0;
len: i64 = 0;
cap: i64 = 0;
// Append `v`, preserving order. Grows the backing store through the
// explicit `alloc` when full (doubling), freeing the old buffer.
@@ -133,8 +133,8 @@ Array :: struct {
// explicit `alloc`.
Object :: struct {
items: [*]Member = null;
len: s64 = 0;
cap: s64 = 0;
len: i64 = 0;
cap: i64 = 0;
// Append a (key, val) pair at the end. Does not check for or merge a
// duplicate key — insertion order is the contract; a repeated key is
@@ -177,7 +177,7 @@ Object :: struct {
Sink :: struct {
dst: []u8; // caller-owned destination (buffer mode) or staging (file mode)
pos: s64 = 0; // bytes currently in `dst`
pos: i64 = 0; // bytes currently in `dst`
file: *File = null; // null => buffer mode
put_byte :: (self: *Sink, b: u8) -> !JsonError {
@@ -213,7 +213,7 @@ Sink :: struct {
// ── Writer ───────────────────────────────────────────────────────────
// Lowercase-hex ASCII byte for a 0..15 nibble. 48='0', 97='a'.
hex_digit :: (n: s64) -> u8 {
hex_digit :: (n: i64) -> u8 {
if n < 10 then xx (n + 48) else xx (n - 10 + 97)
}
@@ -224,8 +224,8 @@ write_u_escape :: (c: u8, sink: *Sink) -> !JsonError {
try sink.put_byte(117); // 'u'
try sink.put_byte(48); // '0'
try sink.put_byte(48); // '0'
try sink.put_byte(hex_digit((cast(s64) c >> 4) & 0xF));
try sink.put_byte(hex_digit(cast(s64) c & 0xF));
try sink.put_byte(hex_digit((cast(i64) c >> 4) & 0xF));
try sink.put_byte(hex_digit(cast(i64) c & 0xF));
return;
}
@@ -254,12 +254,12 @@ write_string :: (s: string, sink: *Sink) -> !JsonError {
}
// Emit a signed integer in decimal, no allocation. Digits are formed in a
// stack buffer working in NEGATIVE space so s64 MIN
// stack buffer working in NEGATIVE space so i64 MIN
// (-9223372036854775808) — whose magnitude is not representable as a
// positive s64 — serializes correctly.
write_int :: (n: s64, sink: *Sink) -> !JsonError {
// positive i64 — serializes correctly.
write_int :: (n: i64, sink: *Sink) -> !JsonError {
if n == 0 { try sink.put_byte(48); return; }
tmp : [20]u8 = ---; // 19 digits + sign is the s64 worst case
tmp : [20]u8 = ---; // 19 digits + sign is the i64 worst case
neg := n < 0;
v := n;
if !neg { v = 0 - n; } // fold positives into negative space
@@ -321,7 +321,7 @@ write_object :: (obj: Object, sink: *Sink) -> !JsonError {
// bytes written. Raises `error.Overflow` if `dst` is too small (the
// partial contents of `dst` are then undefined — nothing is truncated
// silently). No allocation.
write_to_buffer :: (v: Value, dst: []u8) -> (s64, !JsonError) {
write_to_buffer :: (v: Value, dst: []u8) -> (i64, !JsonError) {
sink := Sink.{ dst = dst };
try write_value(v, @sink);
return sink.pos;
@@ -343,7 +343,7 @@ write_to_file :: (v: Value, file: *File, staging: []u8) -> !JsonError {
// `parse(src, alloc)` turns a JSON document in `src` into the value model
// above. It is the inverse of the writer for the v0 scope: objects (in
// INSERTION ORDER), arrays, strings (with full unescaping incl. \uXXXX
// and surrogate pairs), s64 integers, bool, null.
// and surrogate pairs), i64 integers, bool, null.
//
// FAILURE SURFACING (hard contract): every malformed input raises on the
// error channel (`!JsonParseError`) — never a bogus or default value.
@@ -351,7 +351,7 @@ write_to_file :: (v: Value, file: *File, staging: []u8) -> !JsonError {
// `pos` (the parser cursor) marks where the failure was detected.
//
// NOT SUPPORTED (rejected, not silently accepted): a fraction or exponent
// in a number (`1.5`, `1e9`) → `BadNumber`; a number outside s64 →
// in a number (`1.5`, `1e9`) → `BadNumber`; a number outside i64 →
// `BadNumber`; a leading-zero integer (`01`) → `BadNumber`. An UNESCAPED
// raw control byte (U+0000..U+001F) inside a string → `BadControlChar`
// (RFC 8259 §7 requires those bytes to be escaped); the escaped forms
@@ -386,17 +386,17 @@ JsonParseError :: error { UnexpectedToken, UnexpectedEnd, BadEscape, BadNumber,
// Lowercase/uppercase hex nibble value (0..15) of an ASCII byte; a non-hex
// byte in a `\uXXXX` escape is a `BadEscape`.
hex_value :: (c: u8) -> (s64, !JsonParseError) {
if c >= 48 and c <= 57 { return (cast(s64) c) - 48; } // '0'..'9'
if c >= 97 and c <= 102 { return (cast(s64) c) - 97 + 10; } // 'a'..'f'
if c >= 65 and c <= 70 { return (cast(s64) c) - 65 + 10; } // 'A'..'F'
hex_value :: (c: u8) -> (i64, !JsonParseError) {
if c >= 48 and c <= 57 { return (cast(i64) c) - 48; } // '0'..'9'
if c >= 97 and c <= 102 { return (cast(i64) c) - 97 + 10; } // 'a'..'f'
if c >= 65 and c <= 70 { return (cast(i64) c) - 65 + 10; } // 'A'..'F'
raise error.BadEscape;
}
// Encode code point `cp` (already validated 0..0x10FFFF, non-surrogate) as
// UTF-8 into `out`, returning the byte count (1..4). No bounds check: the
// decode buffer is sized to the raw escaped span, which always dominates.
encode_utf8 :: (cp: s64, out: [*]u8) -> s64 {
encode_utf8 :: (cp: i64, out: [*]u8) -> i64 {
if cp < 0x80 {
out[0] = xx cp;
return 1;
@@ -424,7 +424,7 @@ encode_utf8 :: (cp: s64, out: [*]u8) -> s64 {
// EXPLICIT allocator for composites + decoded strings.
Parser :: struct {
src: string;
pos: s64 = 0;
pos: i64 = 0;
alloc: Allocator;
// Advance past JSON whitespace (space / tab / LF / CR).
@@ -450,7 +450,7 @@ Parser :: struct {
// Read 4 hex digits at `i` (which must lie within [.., end)); returns
// the 16-bit value. Fewer than 4 digits before `end` is a BadEscape.
read_hex4 :: (self: *Parser, i: s64, end: s64) -> (s64, !JsonParseError) {
read_hex4 :: (self: *Parser, i: i64, end: i64) -> (i64, !JsonParseError) {
if i + 4 > end { raise error.BadEscape; }
v := 0;
k := 0;
@@ -464,7 +464,7 @@ Parser :: struct {
// Decode the escaped string body in [start, end) into `out`, returning
// the decoded byte length. Pass 1 (in parse_string) guarantees there is
// no dangling backslash, so the byte after every `\` is in range.
decode_into :: (self: *Parser, start: s64, end: s64, out: [*]u8) -> (s64, !JsonParseError) {
decode_into :: (self: *Parser, start: i64, end: i64, out: [*]u8) -> (i64, !JsonParseError) {
di := 0;
i := start;
while i < end {
@@ -544,15 +544,15 @@ Parser :: struct {
return string.{ ptr = out, len = dlen };
}
// Parse an s64 integer (optional '-', then digits). Rejects leading
// zeros, a fraction/exponent tail, and any value outside s64 — all
// `BadNumber`. Accumulates in NEGATIVE space so s64 MIN parses exactly.
parse_number :: (self: *Parser) -> (s64, !JsonParseError) {
// s64 bounds, built positionally because |MIN| is not a
// representable positive s64 literal. `min_div10` is `MIN / 10`
// Parse an i64 integer (optional '-', then digits). Rejects leading
// zeros, a fraction/exponent tail, and any value outside i64 — all
// `BadNumber`. Accumulates in NEGATIVE space so i64 MIN parses exactly.
parse_number :: (self: *Parser) -> (i64, !JsonParseError) {
// i64 bounds, built positionally because |MIN| is not a
// representable positive i64 literal. `min_div10` is `MIN / 10`
// truncated toward zero (remainder -8) — the digit loop's overflow
// threshold. Accumulation runs in NEGATIVE space so MIN is exact.
s64_min := 0 - 9223372036854775807 - 1;
i64_min := 0 - 9223372036854775807 - 1;
min_div10 := 0 - 922337203685477580;
neg := false;
if self.src[self.pos] == 45 { neg = true; self.pos += 1; } // '-'
@@ -560,12 +560,12 @@ Parser :: struct {
dstart := self.pos;
c0 := self.src[self.pos];
if c0 < 48 or c0 > 57 { raise error.BadNumber; }
val : s64 = 0;
val : i64 = 0;
digits := 0;
while self.pos < self.src.len {
c := self.src[self.pos];
if c < 48 or c > 57 { break; }
d := (cast(s64) c) - 48;
d := (cast(i64) c) - 48;
if val < min_div10 { raise error.BadNumber; }
if val == min_div10 and d > 8 { raise error.BadNumber; }
val = val * 10 - d;
@@ -578,7 +578,7 @@ Parser :: struct {
if nc == 46 or nc == 101 or nc == 69 { raise error.BadNumber; } // '.' / 'e' / 'E' — ints only
}
if !neg {
if val == s64_min { raise error.BadNumber; } // |MIN| not representable as +s64
if val == i64_min { raise error.BadNumber; } // |MIN| not representable as +i64
val = 0 - val;
}
return val;

View File

@@ -4,8 +4,8 @@
List :: struct ($T: Type) {
items: [*]T = null;
len: s64 = 0;
cap: s64 = 0;
len: i64 = 0;
cap: i64 = 0;
append :: (list: *List(T), item: T, alloc: Allocator = context.allocator) {
if list.len >= list.cap {
@@ -22,7 +22,7 @@ List :: struct ($T: Type) {
list.len += 1;
}
ensure_capacity :: (list: *List(T), n: s64, alloc: Allocator = context.allocator) {
ensure_capacity :: (list: *List(T), n: i64, alloc: Allocator = context.allocator) {
if list.cap >= n { return; }
new_cap := if list.cap == 0 then 4 else list.cap;
while new_cap < n { new_cap = new_cap * 2; }

View File

@@ -15,7 +15,7 @@
libc :: #library "c";
write :: (fd: s32, buf: [*]u8, count: usize) -> isize #foreign libc;
write :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc;
// Prefix the level, append a newline, write the whole line to stderr.
log_emit :: (level: string, msg: string) {

View File

@@ -31,7 +31,7 @@ destroy :: ufcs (a: Allocator, ptr: *$T) {
}
// Allocate a []T of `count` elements. Contents are UNINITIALISED.
alloc :: ufcs (a: Allocator, $T: Type, count: s64) -> []T {
alloc :: ufcs (a: Allocator, $T: Type, count: i64) -> []T {
raw := a.alloc_bytes(count * size_of(T));
s : []T = ---;
s.ptr = xx raw;
@@ -57,7 +57,7 @@ clone :: ufcs (src: []$T, a: Allocator) -> []T {
// Reallocate a slice to `new_count` elements: fresh storage, contents
// copied up to min(len, new_count), old backing freed. The returned
// slice replaces the operand — the old slice is dangling after this.
resize :: ufcs (slice: []$T, a: Allocator, new_count: s64) -> []T {
resize :: ufcs (slice: []$T, a: Allocator, new_count: i64) -> []T {
raw := a.alloc_bytes(new_count * size_of(T));
n := if slice.len < new_count then slice.len else new_count;
memcpy(raw, xx slice.ptr, n * size_of(T));
@@ -72,7 +72,7 @@ resize :: ufcs (slice: []$T, a: Allocator, new_count: s64) -> []T {
// dealloc — there is no in-place grow primitive to try yet, and
// `align` beyond the heap's natural 8 is not honored until the
// protocol carries alignment.
mem_realloc :: ufcs (a: Allocator, ptr: *void, old: s64, new: s64, align: s64) -> *void {
mem_realloc :: ufcs (a: Allocator, ptr: *void, old: i64, new: i64, align: i64) -> *void {
raw := a.alloc_bytes(new);
n := if old < new then old else new;
memcpy(raw, ptr, n);
@@ -91,7 +91,7 @@ mem_realloc :: ufcs (a: Allocator, ptr: *void, old: s64, new: s64, align: s64) -
CAllocator :: struct {}
impl Allocator for CAllocator {
alloc_bytes :: (self: *CAllocator, size: s64) -> *void {
alloc_bytes :: (self: *CAllocator, size: i64) -> *void {
return libc_malloc(size);
}
dealloc_bytes :: (self: *CAllocator, ptr: *void) {
@@ -112,7 +112,7 @@ impl Allocator for CAllocator {
// print("alloc count: {}\n", gpa.alloc_count);
GPA :: struct {
alloc_count: s64;
alloc_count: i64;
init :: () -> GPA {
GPA.{ alloc_count = 0 }
@@ -120,7 +120,7 @@ GPA :: struct {
}
impl Allocator for GPA {
alloc_bytes :: (self: *GPA, size: s64) -> *void {
alloc_bytes :: (self: *GPA, size: i64) -> *void {
self.alloc_count += 1;
return libc_malloc(size);
}
@@ -146,15 +146,15 @@ impl Allocator for GPA {
ArenaChunk :: struct {
next: *ArenaChunk;
cap: s64;
cap: i64;
}
Arena :: struct {
first: *ArenaChunk;
end_index: s64;
end_index: i64;
parent: Allocator;
add_chunk :: (a: *Arena, min_size: s64) {
add_chunk :: (a: *Arena, min_size: i64) {
prev_cap := if a.first != null then a.first.cap else 0;
needed := min_size + 16 + 16;
len := (prev_cap + needed) * 3 / 2;
@@ -166,7 +166,7 @@ Arena :: struct {
a.end_index = 0;
}
init :: (parent_alloc: Allocator, size: s64) -> Arena {
init :: (parent_alloc: Allocator, size: i64) -> Arena {
self : Arena = .{ first = null, end_index = 0, parent = parent_alloc };
self.add_chunk(size);
self
@@ -198,7 +198,7 @@ Arena :: struct {
}
impl Allocator for Arena {
alloc_bytes :: (self: *Arena, size: s64) -> *void {
alloc_bytes :: (self: *Arena, size: i64) -> *void {
aligned := (size + 7) & (0 - 8);
if self.first != null {
usable := self.first.cap - 16;
@@ -232,10 +232,10 @@ impl Allocator for Arena {
BufAlloc :: struct {
buf: [*]u8;
len: s64;
pos: s64;
len: i64;
pos: i64;
init :: (buf: [*]u8, len: s64) -> BufAlloc {
init :: (buf: [*]u8, len: i64) -> BufAlloc {
BufAlloc.{ buf = buf, len = len, pos = 0 }
}
@@ -245,7 +245,7 @@ BufAlloc :: struct {
}
impl Allocator for BufAlloc {
alloc_bytes :: (self: *BufAlloc, size: s64) -> *void {
alloc_bytes :: (self: *BufAlloc, size: i64) -> *void {
aligned := (size + 7) & (0 - 8);
if self.pos + aligned > self.len {
return null;
@@ -282,9 +282,9 @@ impl Allocator for BufAlloc {
TrackingAllocator :: struct {
parent: Allocator;
alloc_count: s64;
dealloc_count: s64;
total_alloc_bytes: s64;
alloc_count: i64;
dealloc_count: i64;
total_alloc_bytes: i64;
init :: (parent_alloc: Allocator) -> TrackingAllocator {
TrackingAllocator.{
@@ -295,7 +295,7 @@ TrackingAllocator :: struct {
}
}
leak_count :: (t: *TrackingAllocator) -> s64 {
leak_count :: (t: *TrackingAllocator) -> i64 {
t.alloc_count - t.dealloc_count
}
@@ -306,7 +306,7 @@ TrackingAllocator :: struct {
}
impl Allocator for TrackingAllocator {
alloc_bytes :: (self: *TrackingAllocator, size: s64) -> *void {
alloc_bytes :: (self: *TrackingAllocator, size: i64) -> *void {
ptr := self.parent.alloc_bytes(size);
if ptr != null {
self.alloc_count += 1;

View File

@@ -21,12 +21,12 @@ libc :: #library "c";
// ── Low-level libc bindings ─────────────────────────────────────────
popen :: (cmd: [:0]u8, mode: [:0]u8) -> *void #foreign libc;
pclose :: (stream: *void) -> s32 #foreign libc;
pclose :: (stream: *void) -> i32 #foreign libc;
fread :: (ptr: [*]u8, size: usize, nmemb: usize, stream: *void) -> usize #foreign libc;
feof :: (stream: *void) -> s32 #foreign libc;
feof :: (stream: *void) -> i32 #foreign libc;
getenv :: (name: [:0]u8) -> *u8 #foreign libc;
strlen :: (s: *u8) -> usize #foreign libc;
system :: (cmd: [:0]u8) -> s32 #foreign libc;
system :: (cmd: [:0]u8) -> i32 #foreign libc;
// ── Public types ─────────────────────────────────────────────────────
@@ -34,7 +34,7 @@ ProcessResult :: struct {
/// Exit code as reported by `WEXITSTATUS(status)`. 0 = success.
/// Note: doesn't distinguish "killed by signal" from "exited
/// non-zero"; phase 1B will return a tagged union.
exit_code: s32;
exit_code: i32;
stdout: string;
}
@@ -50,7 +50,7 @@ ProcessResult :: struct {
// with stdout, append " 2>&1" to the command.
run :: (cmd: [:0]u8) -> ?ProcessResult {
f := popen(cmd, "r");
if cast(s64) f == 0 { return null; }
if cast(i64) f == 0 { return null; }
out := "";
buf := cstring(4096);
@@ -61,7 +61,7 @@ run :: (cmd: [:0]u8) -> ?ProcessResult {
if n > 0 {
chunk : string = ---;
chunk.ptr = buf.ptr;
chunk.len = cast(s64) n;
chunk.len = cast(i64) n;
out = concat(out, chunk);
}
}
@@ -85,12 +85,12 @@ run :: (cmd: [:0]u8) -> ?ProcessResult {
// string if set to "".
env :: (name: [:0]u8) -> ?string {
p := getenv(name);
addr : s64 = xx p;
addr : i64 = xx p;
if addr == 0 { return null; }
n := strlen(p);
if n == 0 { return ""; }
buf := cstring(cast(s64) n);
memcpy(buf.ptr, xx p, cast(s64) n);
buf := cstring(cast(i64) n);
memcpy(buf.ptr, xx p, cast(i64) n);
buf
}
@@ -126,7 +126,7 @@ find_executable :: (name: [:0]u8) -> ?string {
// via `write(2)`, so skipping the stdio flush loses nothing. Binding the
// symbol `"exit"` would also collide with this module's own `exit` function
// at the link level.
clib_exit :: (code: s32) -> noreturn #foreign libc "_exit";
clib_exit :: (code: i32) -> noreturn #foreign libc "_exit";
// Stop the process immediately with exit code `code`. Does NOT unwind:
// no `defer` / `onfail` cleanup runs, no error-trace frames are pushed —

View File

@@ -4,20 +4,20 @@
libc :: #library "c";
// POSIX socket API
socket :: (domain: s32, kind: s32, protocol: s32) -> s32 #foreign libc;
setsockopt :: (fd: s32, level: s32, optname: s32, optval: *s32, optlen: u32) -> s32 #foreign libc;
bind :: (fd: s32, addr: *SockAddr, addrlen: u32) -> s32 #foreign libc;
listen :: (fd: s32, backlog: s32) -> s32 #foreign libc;
accept :: (fd: s32, addr: *SockAddr, addrlen: *u32) -> s32 #foreign libc;
read :: (fd: s32, buf: [*]u8, count: usize) -> isize #foreign libc;
write :: (fd: s32, buf: [*]u8, count: usize) -> isize #foreign libc;
close :: (fd: s32) -> s32 #foreign libc;
socket :: (domain: i32, kind: i32, protocol: i32) -> i32 #foreign libc;
setsockopt :: (fd: i32, level: i32, optname: i32, optval: *i32, optlen: u32) -> i32 #foreign libc;
bind :: (fd: i32, addr: *SockAddr, addrlen: u32) -> i32 #foreign libc;
listen :: (fd: i32, backlog: i32) -> i32 #foreign libc;
accept :: (fd: i32, addr: *SockAddr, addrlen: *u32) -> i32 #foreign libc;
read :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc;
write :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc;
close :: (fd: i32) -> i32 #foreign libc;
// Constants (macOS)
AF_INET :s32: 2;
SOCK_STREAM :s32: 1;
SOL_SOCKET :s32: 0xFFFF;
SO_REUSEADDR :s32: 0x4;
AF_INET :i32: 2;
SOCK_STREAM :i32: 1;
SOL_SOCKET :i32: 0xFFFF;
SO_REUSEADDR :i32: 0x4;
// macOS sockaddr_in (16 bytes, has sin_len field)
SockAddr :: struct {
@@ -28,6 +28,6 @@ SockAddr :: struct {
sin_zero: u64 = 0;
}
htons :: (port: s64) -> u16 {
htons :: (port: i64) -> u16 {
cast(u16) (((port & 0xFF) << 8) | ((port >> 8) & 0xFF))
}

View File

@@ -28,16 +28,16 @@ libc :: #library "c";
// library/vendors/sx_trace_runtime/sx_trace.c.
TraceFrame :: struct {
file: string;
line: s32;
col: s32;
line: i32;
col: i32;
func: string;
line_text: string; // the source line, for the snippet + caret
}
// `n` spaces — used to position the `^` caret under a column.
spaces :: (n: s32) -> string {
spaces :: (n: i32) -> string {
s := "";
i : s32 = 0;
i : i32 = 0;
while i < n {
s = concat(s, " ");
i = i + 1;
@@ -54,7 +54,7 @@ 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;
write :: (fd: i32, 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.