Continue fold-2 (after 374e97b): migrate the remaining Family-1 str/slice
global + literal + index + call-arg group from bespoke build+run C twins to
test/lang @test, retiring each twin in the same commit. Runtime coverage MOVES
from $(TESTS) to test-lang (T1 runs+asserts via `ww test`) + test-lang-byteid
(T2 keeps cs==ww .s byte-id); coverage is preserved, the $(TESTS) headline
drops 9 (434->425). All asserts are primitive int/u8/bool comparisons (no
fmt/strconv in the assert path); the slice-store/index rows reset the global
each fn and sum ADJACENT elements so a dropped/mis-strided/over-wide word FAILS.
989_globslicefield_run.c -> glob_slice_field_test.ww (slice field of a global struct: g.f=<slice> stores full 24B header; len/cap/non-zero-offset + str/scalar controls)
989_globstrslice_run.c -> glob_str_slice_arg_test.ww (global str sliced with default hi passed as call arg loads its len word; explicit-hi control)
989_trystr_run.c -> try_str_unwrap_test.ww (`!` unwrap of str-success tagged union shuffles the str header for ident-source/error-first/success-first)
797_len_strglobal_run.c -> len_str_global_test.ww (len(str-global) loads .len via name(SB); local-str control)
801_litstr_pseudo_run.c -> lit_str_pseudo_test.ww (string-literal .len/.ptr pseudo-field; empty/multibyte + arg-passthrough)
803_globalidx_run.c -> global_index_test.ww (global str/slice index read/addr-of/store/compound, esz 1/4; local regression pins)
903_tuple_elem_slice_len.c -> tuple_elem_slice_len_test.ww (len(t.N) of a slice/str tuple element loads .len at +8; 2/3-slice, str-slice both orders)
927_composite_call_arg_run.c-> composite_call_arg_test.ww (slice-returning CALL passed inline as a composite arg; canonical/letslice/two-call/middle/nested/scalar/tagged)
952_slicecopy_assign_run.c -> slice_copy_assign_test.ww (bulk slice-copy-assign `arr[lo:hi]=bs`, esz 1/4, field/via-ptr/local bases; reslice-read companion)
rd_reslice asserts the TRUE value 360 (the .c twin's want=104 was 360 & 0xFF,
an exit-code truncation). 723_composite_call_arg.c's comment repointed to the
new test/lang location. 802_lenidx_run.c is DEFERRED (it carries //ww:error
reject rows — needs a value-rows-only split + a slim reject carrier, a fold-3
pass). Bump LANGBYTEID_EXPECTED_MIN 22->31 to ratchet the new corpus floor.
144 lines
4.2 KiB
Plaintext
144 lines
4.2 KiB
Plaintext
// global_index_test — the GLOBAL `str` / GLOBAL slice index family (s/g are
|
|
// module-level lets): the READ `s[i]`/`g[i]` (#10), the ADDR-OF `&s[i]`/`&g[i]`
|
|
// and the STORE `g[i] = v` (#11), migrated from test/wcc/803_globalidx_run.c.
|
|
// wwstage's cgindex dispatched the element size + base off the base's tnode KIND
|
|
// (only N_TARRAY / N_TPTR), so a global str (N_TNAME "str") and a global slice
|
|
// (N_TSLICE) matched neither arm: esz stayed 8 and the base fell to the
|
|
// wide-header fallback — an 8-byte stride + full-word MOVQ, reading 8 bytes at
|
|
// ptr+8 instead of the single byte at ptr+1. The store was an 8-byte
|
|
// OUT-OF-BOUNDS MOVQ instead of MOVB. cstage dispatched esz off the RESOLVED
|
|
// base TYPE (uniform), so it was correct. The fix aligns cgindex/cgun/cgassign
|
|
// UP to that type-driven dispatch. The slice rows reset the global each fn and
|
|
// sum ADJACENT elements so a mis-strided / over-wide write FAILS; local rows are
|
|
// regression pins for the already-clean local path.
|
|
|
|
package global_index_test;
|
|
|
|
let s: str = "ABC";
|
|
let g: []u8;
|
|
let gi: []i32;
|
|
|
|
@test fn gstr_first() void = {
|
|
assert(s[0]: i32 == 65);
|
|
};
|
|
|
|
@test fn gstr_mid() void = {
|
|
// the exact #10 repro: s[1] == 'B' == 66 (pre-fix an 8-byte word at ptr+8).
|
|
assert(s[1]: i32 == 66);
|
|
};
|
|
|
|
@test fn gstr_last() void = {
|
|
assert(s[2]: i32 == 67);
|
|
};
|
|
|
|
@test fn gstr_sum() void = {
|
|
// two byte indices summed (65+66) pins the load width — a full-word load
|
|
// would carry the high bytes.
|
|
assert(s[0]: i32 + s[1]: i32 == 131);
|
|
};
|
|
|
|
@test fn gslice_mid() void = {
|
|
let a: [3]u8 = [10u8, 20u8, 30u8];
|
|
g = a;
|
|
assert(g[1]: i32 == 20);
|
|
};
|
|
|
|
@test fn gislice_mid() void = {
|
|
// WIDTH>1, SIGNED: g[1]-g[0] == 20-(-5) == 25 pins esz=4 + sign-extend.
|
|
let a: [3]i32 = [-5, 20, 30];
|
|
gi = a;
|
|
assert(gi[1] - gi[0] == 25);
|
|
};
|
|
|
|
@test fn gstr_addr() void = {
|
|
// #11 ADDR-OF, global str: &s[1] read back == 'B' == 66.
|
|
let p: *u8 = &s[1];
|
|
assert((*p): i32 == 66);
|
|
};
|
|
|
|
@test fn gslice_addr() void = {
|
|
// #11 ADDR-OF, global []u8: &g[1] read back == 20.
|
|
let a: [3]u8 = [10u8, 20u8, 30u8];
|
|
g = a;
|
|
let p: *u8 = &g[1];
|
|
assert((*p): i32 == 20);
|
|
};
|
|
|
|
@test fn gislice_addr() void = {
|
|
// #11 ADDR-OF, global []i32 WIDTH>1: &g[1] == 20 pins esz=4 stride.
|
|
let a: [3]i32 = [-5, 20, 30];
|
|
gi = a;
|
|
let p: *i32 = &gi[1];
|
|
assert(*p == 20);
|
|
};
|
|
|
|
@test fn gslice_store() void = {
|
|
// #11 STORE, global []u8: g[1]=99; g[1]+g[0]+g[2] == 99+10+30 == 139. The
|
|
// g[0]/g[2] addends are the OOB-WRITE GUARD (pre-fix a full-word MOVQ at an
|
|
// 8-byte stride wrote 99 at ptr+8 and left g[1]==20).
|
|
let a: [3]u8 = [10u8, 20u8, 30u8];
|
|
g = a;
|
|
g[1] = 99u8;
|
|
assert(g[1]: i32 + g[0]: i32 + g[2]: i32 == 139);
|
|
};
|
|
|
|
@test fn gislice_store() void = {
|
|
// #11 STORE, global []i32 SIGNED: g[1]=42; g[1]+g[0]+g[2] == 42+(-5)+30 == 67.
|
|
let a: [3]i32 = [-5, 20, 30];
|
|
gi = a;
|
|
gi[1] = 42;
|
|
assert(gi[1] + gi[0] + gi[2] == 67);
|
|
};
|
|
|
|
@test fn gslice_compound() void = {
|
|
// #11 COMPOUND STORE, global []u8: g[1] += 79 → 99; sum == 139. The third
|
|
// fixed arm (load-combine-store in place), pre-fix an 8-byte OOB RMW.
|
|
let a: [3]u8 = [10u8, 20u8, 30u8];
|
|
g = a;
|
|
g[1] += 79u8;
|
|
assert(g[1]: i32 + g[0]: i32 + g[2]: i32 == 139);
|
|
};
|
|
|
|
@test fn gislice_compound() void = {
|
|
// #11 COMPOUND STORE, global []i32 SIGNED: g[1] += 47 → 42; g[1]+g[0]+g[2]
|
|
// == 42+(-25)+30 == 47.
|
|
let a: [3]i32 = [-25, -5, 30];
|
|
gi = a;
|
|
gi[1] += 47;
|
|
assert(gi[1] + gi[0] + gi[2] == 47);
|
|
};
|
|
|
|
@test fn lstr_addr() void = {
|
|
// regression pin: local str ADDR-OF (already clean) — &s[1] == 66.
|
|
let s: str = "ABC";
|
|
let p: *u8 = &s[1];
|
|
assert((*p): i32 == 66);
|
|
};
|
|
|
|
@test fn lslice_store() void = {
|
|
// regression pin: local slice STORE (already clean) — g[1]=99; sum == 139.
|
|
let a: [3]u8 = [10u8, 20u8, 30u8];
|
|
let g: []u8 = a;
|
|
g[1] = 99u8;
|
|
assert(g[1]: i32 + g[0]: i32 + g[2]: i32 == 139);
|
|
};
|
|
|
|
@test fn lstr_mid() void = {
|
|
// regression pin: local str index (already clean) — s[1] == 66.
|
|
let s: str = "ABC";
|
|
assert(s[1]: i32 == 66);
|
|
};
|
|
|
|
@test fn lslice_last() void = {
|
|
// regression pin: local slice index, last elem (already clean) — g[2] == 30.
|
|
let a: [3]u8 = [10u8, 20u8, 30u8];
|
|
let g: []u8 = a;
|
|
assert(g[2]: i32 == 30);
|
|
};
|
|
|
|
@test fn larr_mid() void = {
|
|
// regression pin: direct local array index (already clean) — a[1] == 20.
|
|
let a: [3]u8 = [10u8, 20u8, 30u8];
|
|
assert(a[1]: i32 == 20);
|
|
};
|