Port four of the five c3 strings functions per ref/hare/strings/iter.ha;
strings.slice deferred behind task #34 (wwstage fnretlookup same-name
cross-module phantom return-ABI fixup, sub-bug of #4e).
- prev ref/hare/strings/iter.ha:49
- riter ref/hare/strings/iter.ha:32
- iterstr ref/hare/strings/iter.ha:63
- position ref/hare/strings/iter.ha:82
Also adds a private move() helper (ref/hare/strings/iter.ha:51) shared
by next/prev. Hare's move picks the utf8 function via a fn-pointer
(`let fun = if (forward) &utf8::next else &utf8::prev`); ww has no
fn-pointers in scope yet, so move branches on `forward` and calls
utf8.next or utf8.prev directly at each site.
strings.next is updated to dispatch via move(!it.reverse, it) — c2's
implementation always called utf8.next regardless of iter.reverse,
which was correct for forward iter() but would walk forward on
riter()-produced iterators too. With riter landed in this commit,
next() now correctly walks backward on reverse iterators per Hare's
ref/hare/strings/iter.ha:45. No in-tree consumer regression: only
stringstest constructs iterators today.
strings.iterstr uses ww's `[lo:hi]` slice syntax instead of Hare's
`[lo..hi]`; same semantics (borrowed []u8 view).
strings.slice deferred — Hare's body is
`fromutf8_unsafe(utf8::slice(begin, end))` (ref/hare/strings/iter.ha:76).
That delegation form triggers a wwstage fnretlookup miscompile when
the caller module has a function of the same name as the callee
(here: both strings::slice and utf8::slice exist), causing wwstage
to emit the wrong return-ABI fixup (MOVQ DX, BX, str's AX/DX→AX/BX
shim) after the cross-module CALL. Cstage handles the collision
correctly; wwstage routes through the same-module function's
return type and the byte-id checks (993_ww_ww + 995_self_rebuild)
trip. Filed as task #34 with minimal repro; will land strings.slice
when the fnretlookup graduate-by-module sub-bug in #34 is fixed.
Top-of-file divergence note lists slice in the deferred set; the
landing site keeps a comment-only stub. The public strings c3
surface ships 4-of-5 in this commit; slice + #34 land together in
a follow-up.
Tests: 5 new @test fns in stringstest.ww (signalled 22-26):
iter_prev_at_start_cases (prev at offs=0 → done),
iter_prev_ascii_cases (round-trip on forward iter),
iter_full_cases (mirror of ref/hare/strings/iter.ha:84-108 — iter
"こんにちは" with mid-walk iterstr + prev + next, then s = riter(...)
sret-into-existing-slot for the reverse iterator pass),
iter_position_cases (position tracks offs through a multibyte walk),
iter_iterstr_reverse_cases (riter iterstr is bytes BEFORE the cursor,
dual to forward iter's bytes-AFTER).
The Hare @test fn iter body uses `s = riter("にちは")` mid-test to
swap the iterator's direction (ref/hare/strings/iter.ha:101); ww's
sret-into-existing-slot path handles that fine (probed pre-port).
struct-copy let-from-ident (task #32) is sidestepped because no
test creates a duplicate iterator via `let dup = it;`.
117/117 ok. 995_self_rebuild stays green (ww2==ww3==ww4 byte-id).
993_ww_ww + 994_w6c_ww also green (cstage/wwstage byte-identical
on every corpus input including selfhost/cmd/wwdump/main.combined.ww).