regex: fold 5a — add_thread dups parent captures/rep_counters (ha:568-573)
The loud bound (capture dup not yet portable, #35/#34/#7) flips to the real dup now that #35's spread place-chain sources landed: fresh slice header + spread-append, the D3 spelling of Hare's alloc-dup. The ok/defer-if frees drop (free() is the documented no-op, #27). Dup-independence rows drive add_thread directly: values carried, backing independent both directions, empty parent → empty dup.
This commit is contained in:
@@ -504,9 +504,9 @@ fn ic_one(v: regex.inst, want: bool) void = {
|
||||
// add_thread (regex.ha:557-587): same-pc dedup suppression fires only
|
||||
// when the existing thread is unmatched AND started strictly earlier
|
||||
// than the parent (ha:561-565); otherwise the child appends,
|
||||
// inheriting the parent's start/matched/failed with fresh empty
|
||||
// capture/rep_counter headers and a zeroed root_capture. The
|
||||
// capture-dup loud bound must NOT fire on these empty-caps parents.
|
||||
// inheriting the parent's start/matched/failed with DUPLICATED
|
||||
// capture/rep_counter slices (empty parent → empty dup, ha:569/572)
|
||||
// and a zeroed root_capture.
|
||||
@test fn add_thread_dedup_inherit() void = {
|
||||
let ts: []thread = [];
|
||||
append(ts, thread { pc = 0, start_idx = 5, start_bytesize = 4,
|
||||
@@ -546,6 +546,59 @@ fn ic_one(v: regex.inst, want: bool) void = {
|
||||
if (ts3[2].start_idx != (5: size)) { fail(); };
|
||||
};
|
||||
|
||||
// add_thread dup (regex.ha:568-573): the child carries a COPY of the
|
||||
// parent's captures/rep_counters — values equal, backing independent
|
||||
// in both directions (mutate parent → child unchanged, mutate child →
|
||||
// parent unchanged). Empty parent → empty dup (the pre-flip rows above
|
||||
// stay byte-for-byte). Driven directly, the dedup-test precedent.
|
||||
@test fn add_thread_dup_independence() void = {
|
||||
let caps: []capture = [];
|
||||
append(caps, capture {
|
||||
content = "ab", start = 1, start_bytesize = 1,
|
||||
end = 2, end_bytesize = 2,
|
||||
});
|
||||
append(caps, capture {
|
||||
content = "c", start = 3, start_bytesize = 3,
|
||||
end = 4, end_bytesize = 4,
|
||||
});
|
||||
let reps: []size = [];
|
||||
append(reps, (5: size));
|
||||
append(reps, (6: size));
|
||||
let ts: []thread = [];
|
||||
append(ts, thread { pc = 0, start_idx = 1, captures = caps,
|
||||
rep_counters = reps, ... });
|
||||
let r: (void | nomem) = add_thread(&ts, 0, 9);
|
||||
if (!(r is void)) { fail(); };
|
||||
if (len(ts) != 2) { fail(); };
|
||||
// dup carried the parent's values
|
||||
if (ts[1].captures.len != 2) { fail(); };
|
||||
if (strings.compare(ts[1].captures[0].content, "ab") != 0) { fail(); };
|
||||
if (ts[1].captures[0].start != (1: size)) { fail(); };
|
||||
if (ts[1].captures[1].end != (4: size)) { fail(); };
|
||||
if (ts[1].rep_counters.len != 2) { fail(); };
|
||||
if (ts[1].rep_counters[0] != (5: size)) { fail(); };
|
||||
if (ts[1].rep_counters[1] != (6: size)) { fail(); };
|
||||
// independence, parent → child: mutate the parent post-add
|
||||
ts[0].captures[0].start = 100;
|
||||
ts[0].captures[0].content = "zz";
|
||||
ts[0].rep_counters[0] = 77;
|
||||
if (ts[1].captures[0].start != (1: size)) { fail(); };
|
||||
if (strings.compare(ts[1].captures[0].content, "ab") != 0) { fail(); };
|
||||
if (ts[1].rep_counters[0] != (5: size)) { fail(); };
|
||||
// independence, child → parent
|
||||
ts[1].captures[1].end = 200;
|
||||
ts[1].rep_counters[1] = 88;
|
||||
if (ts[0].captures[1].end != (4: size)) { fail(); };
|
||||
if (ts[0].rep_counters[1] != (6: size)) { fail(); };
|
||||
// empty parent → empty dup
|
||||
let ts2: []thread = [];
|
||||
append(ts2, thread { pc = 0, ... });
|
||||
let r2: (void | nomem) = add_thread(&ts2, 0, 3);
|
||||
if (!(r2 is void)) { fail(); };
|
||||
if (ts2[1].captures.len != 0) { fail(); };
|
||||
if (ts2[1].rep_counters.len != 0) { fail(); };
|
||||
};
|
||||
|
||||
// run_thread (regex.ha:589-742) driven directly over compile("ab")'s
|
||||
// real program [skip, lit 'a', lit 'b', match(false)] — the arms
|
||||
// fold-2a can emit. Phases: parked-skip spawn (len 1→2, parent pc
|
||||
@@ -1744,5 +1797,6 @@ export fn main() i32 = {
|
||||
signalled = 34; fold4_compile_errors();
|
||||
signalled = 35; fold4_find_cases();
|
||||
signalled = 36; fold4_findall();
|
||||
signalled = 37; add_thread_dup_independence();
|
||||
return 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user