Rename all example tests/companions to the XXXX-category-test-name scheme (per-category 100-blocks: basic 0010, types 0100, ... errors 1000, diagnostics 1100, ffi 1200, ffi-objc 1300, ffi-jni 1400, vectors 1500, platform 1600). Companions and dir/C fixtures move in lockstep with their parent test; #import/#source/#include paths rewritten to match. Expected output now lives in examples/expected/ (a sibling dir of the tests) split into three streams per the new convention: <name>.exit / <name>.stdout / <name>.stderr (+ optional <name>.ir) run_examples.sh rewritten: scans examples/ and issues/ for an expected/<name>.exit marker, captures stdout and stderr separately (no more 2>&1), compares each stream + exit + optional IR snapshot. Behavior validated unchanged: every renamed test reproduces its prior merged output + exit (diffs limited to file paths/basenames embedded in diagnostics + traces, which correctly reflect the new names). Suite: 292 passed, 0 failed. 50-smoke.sx split + issue relocation + docs follow in subsequent commits.
191 lines
5.1 KiB
Plaintext
191 lines
5.1 KiB
Plaintext
// Lock down the interp's raw-pointer store width per primitive type.
|
|
//
|
|
// Each helper allocates a 32-byte buffer through `context.allocator`,
|
|
// fills it with a sentinel byte (0xAA), writes ONE typed value at
|
|
// offset 8, then sums every byte back. A correctly-sized store touches
|
|
// exactly `sizeof(T)` bytes, so the sum equals
|
|
// 31 * 0xAA + sum-of-bytes-in-the-written-value.
|
|
// A wrong width (e.g. an 8-byte store at a 1-byte slot) clobbers
|
|
// neighbors with zeros and the sum drops.
|
|
//
|
|
// Each test computes its expected sum at COMPTIME (the value is baked
|
|
// into a `#run` constant — the interp's `storeAtRawPtr` runs). The
|
|
// runtime program prints the same checksum computed by codegen
|
|
// (LLVM-emitted typed stores). The two MUST match — that's the
|
|
// regression assertion.
|
|
//
|
|
// To pin the test: every helper returns its checksum; main prints
|
|
// "ok" iff every comptime-baked checksum equals the runtime-recomputed
|
|
// one. Failure prints which width diverged.
|
|
|
|
#import "modules/std.sx";
|
|
|
|
SENTINEL :u8: 0xAA; // 170 — neighbor pattern
|
|
BUF_SIZE :s64: 32;
|
|
TARGET :s64: 8; // offset where the typed store lands
|
|
|
|
// ── per-width helpers ───────────────────────────────────────────────
|
|
|
|
fill :: (buf: [*]u8) {
|
|
i : s64 = 0;
|
|
while i < BUF_SIZE { buf[i] = SENTINEL; i += 1; }
|
|
}
|
|
|
|
sum_bytes :: (buf: [*]u8) -> s64 {
|
|
s : s64 = 0;
|
|
i : s64 = 0;
|
|
while i < BUF_SIZE { s += xx buf[i]; i += 1; }
|
|
s;
|
|
}
|
|
|
|
run_u8 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *u8 = xx @buf[TARGET];
|
|
p.* = 0x42;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_u16 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *u16 = xx @buf[TARGET];
|
|
p.* = 0x0102;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_u32 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *u32 = xx @buf[TARGET];
|
|
p.* = 0x01020304;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_u64 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *u64 = xx @buf[TARGET];
|
|
p.* = 0x0102030405060708;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_s8 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *s8 = xx @buf[TARGET];
|
|
p.* = 0x42;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_s16 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *s16 = xx @buf[TARGET];
|
|
p.* = 0x0102;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_s32 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *s32 = xx @buf[TARGET];
|
|
p.* = 0x01020304;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_s64 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *s64 = xx @buf[TARGET];
|
|
p.* = 0x0102030405060708;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_bool :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *bool = xx @buf[TARGET];
|
|
p.* = true;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_f32 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *f32 = xx @buf[TARGET];
|
|
p.* = 1.0;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
run_f64 :: () -> s64 {
|
|
buf : [*]u8 = xx malloc(BUF_SIZE);
|
|
fill(buf);
|
|
p : *f64 = xx @buf[TARGET];
|
|
p.* = 1.0;
|
|
s := sum_bytes(buf);
|
|
free(xx buf);
|
|
s;
|
|
}
|
|
|
|
// ── comptime-baked expected checksums ───────────────────────────────
|
|
// `#run` evaluates each helper via the interp, so its
|
|
// `storeAtRawPtr(addr, val, val_ty)` honors the declared width.
|
|
|
|
EXP_U8 :: #run run_u8();
|
|
EXP_U16 :: #run run_u16();
|
|
EXP_U32 :: #run run_u32();
|
|
EXP_U64 :: #run run_u64();
|
|
EXP_S8 :: #run run_s8();
|
|
EXP_S16 :: #run run_s16();
|
|
EXP_S32 :: #run run_s32();
|
|
EXP_S64 :: #run run_s64();
|
|
EXP_BOOL :: #run run_bool();
|
|
EXP_F32 :: #run run_f32();
|
|
EXP_F64 :: #run run_f64();
|
|
|
|
// ── runtime comparison ──────────────────────────────────────────────
|
|
|
|
check :: (label: string, got: s64, want: s64) -> bool {
|
|
if got == want { return true; }
|
|
print("FAIL {}: comptime={} runtime={}\n", label, want, got);
|
|
false;
|
|
}
|
|
|
|
main :: () -> s32 {
|
|
ok := true;
|
|
if !check("u8", run_u8(), EXP_U8) { ok = false; }
|
|
if !check("u16", run_u16(), EXP_U16) { ok = false; }
|
|
if !check("u32", run_u32(), EXP_U32) { ok = false; }
|
|
if !check("u64", run_u64(), EXP_U64) { ok = false; }
|
|
if !check("s8", run_s8(), EXP_S8) { ok = false; }
|
|
if !check("s16", run_s16(), EXP_S16) { ok = false; }
|
|
if !check("s32", run_s32(), EXP_S32) { ok = false; }
|
|
if !check("s64", run_s64(), EXP_S64) { ok = false; }
|
|
if !check("bool", run_bool(), EXP_BOOL) { ok = false; }
|
|
if !check("f32", run_f32(), EXP_F32) { ok = false; }
|
|
if !check("f64", run_f64(), EXP_F64) { ok = false; }
|
|
if ok { print("ok\n"); return 0; }
|
|
return 1;
|
|
}
|