lib/regex: fold-2b tranche B1-B3 — thread-machine leaf fns (run_thread held on #40)
Port is_consuming_inst (regex.ha:553-555), delete_thread (ha:547-551) and add_thread (ha:557-587) per the tranche-B scope (drew §9b). D12 chained-|| spells the multi-type is (parity task #13); D9 index loops replace the &.. ranges (#11); the dedup-scan bound reads .len, not the len() builtin (FB1, #41 — len(*p) loads the data pointer as the length). add_thread's capture/rep_counter dup is loud-bounded per the rob-ratified ruling: every ww route into the dup is blocked at HEAD (#35 spread source, #34 element source, #7 element let-copy), and fold-2a compile() cannot emit inst_groupstart/inst_repeat, so both parent slices are provably empty in every reachable program; the verbatim dup lands with the group/repeat fold (#3). run_thread (B4) stays out: its loop condition passes the 56B inst by value from a slice-element source, gated on the #38b extension (#40, in flight). Fixture cases 15-17 drive the three fns directly (package regex): all-10-kind consuming table, delete at middle/last/0-to-empty, dedup suppress/strict-</matched-guard + inheritance + zeroed headers. Byte-cmp on the regenerated combined holds the FC0-only baseline; both drivers run the fixture green.
This commit is contained in:
@@ -1,16 +1,15 @@
|
||||
// regex — POSIX extended regular expressions. Port of
|
||||
// ref/hare/regex/regex.ha. Fold 1 = the data model; fold 2a = the
|
||||
// compile() literal core (lit/any/match + the leading skip); fold 2b
|
||||
// tranche A = the thread-machine scaffolding that compiles cleanly
|
||||
// today (thread/newmatch types, result_free, strerror —
|
||||
// dead-imported until the engine lands, fold-1 precedent). Every
|
||||
// other metacharacter arm, the engine itself (delete_thread/
|
||||
// add_thread/is_consuming_inst/run_thread/search) and the exec
|
||||
// surface (test/find/replace) are DEFERRED behind compiler fixes:
|
||||
// every *[]thread-mediated shape the engine needs miscompiles today
|
||||
// (append-through-ptr #15, deref-spine element reads #17), and the
|
||||
// 56B-slot inst by-value arg ABI is unwired both sides (#19) —
|
||||
// probed pre-port, pA*/pB*/pC* probes. They land with those fixes.
|
||||
// tranche A = the thread-machine scaffolding (thread/newmatch types,
|
||||
// result_free, strerror); fold 2b tranche B = the engine leaf fns
|
||||
// (delete_thread/is_consuming_inst/add_thread — dead until search
|
||||
// lands, fold-1 precedent). Every other metacharacter arm, the rest
|
||||
// of the engine (run_thread, see its deferral note below; search on
|
||||
// F5 element-copy + F2 len-builtin, tranche C) and the exec surface
|
||||
// (test/find on the C6 multi-success `?` gate, tranche D; replace)
|
||||
// are DEFERRED behind compiler fixes — probed pre-port, pA*/pB*/PB*
|
||||
// probes. They land with those fixes.
|
||||
//
|
||||
// One fold-1 construct is held back behind a filed compiler/fidelity
|
||||
// gap (see the charclass_map site below):
|
||||
@@ -206,14 +205,86 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
||||
};
|
||||
};
|
||||
|
||||
// delete_thread (regex.ha:547-551), is_consuming_inst (regex.ha:
|
||||
// 553-555) and add_thread (regex.ha:557-587) belong here in Hare
|
||||
// order but are deferred behind compiler fixes: delete_thread/
|
||||
// add_thread on append-through-ptr (#15) / deref-spine reads (#17);
|
||||
// is_consuming_inst on the >48B tagged by-value ABI (#19 — inst is a
|
||||
// 56B slot; the call side is a loud unwired boundary and the callee
|
||||
// receive diverges cs≠ww, so even landing it dead would break rule
|
||||
// 10). See the module header.
|
||||
// ref/hare/regex/regex.ha:547-551, verbatim — both free()s are the
|
||||
// documented no-op (#27; see finish()), kept for source parity. ww
|
||||
// has no pointer auto-deref, so Hare's `threads[i]` spells
|
||||
// `(*threads)[i]` (the test-804-pinned delete shape).
|
||||
fn delete_thread(i: size, threads: *[]thread) void = {
|
||||
free((*threads)[i].captures);
|
||||
free((*threads)[i].rep_counters);
|
||||
delete((*threads)[i]);
|
||||
};
|
||||
|
||||
// ref/hare/regex/regex.ha:553-555. Hare's multi-type membership test
|
||||
// `a is (inst_lit | inst_any | inst_charset)` is loud-rejected by
|
||||
// design (filed as a Hare-parity task, ww-core #13); the ruled
|
||||
// spelling is the chained ||.
|
||||
fn is_consuming_inst(a: inst) bool = {
|
||||
return a is inst_lit || a is inst_any || a is inst_charset;
|
||||
};
|
||||
|
||||
// ref/hare/regex/regex.ha:557-587. The dedup scan (ha:560-566) is an
|
||||
// index loop: ww has no by-ref `&..` range and a by-value range over
|
||||
// `*threads` miscompiles (F1, ww-core #11). Its bound reads the
|
||||
// `.len` pseudo-field, not the len() builtin — len(*threads)
|
||||
// mis-reads the data pointer as the length (FB1, ww-core #41; the
|
||||
// F2/#10 deref sibling). Hare's `append(...)?` nomem propagation and the
|
||||
// ok/defer-if unwind (ha:568/573/586) drop together: ww append
|
||||
// returns void (#36 filed) and free() reclaims nothing (#27), so
|
||||
// there is nothing to propagate or unwind.
|
||||
fn add_thread(threads: *[]thread, parent_idx: size, new_pc: size) (void | nomem) = {
|
||||
// Do not add this thread if there is already another thread with
|
||||
// the same PC
|
||||
for (let k: size = 0; k < ((*threads).len: size); k += 1) {
|
||||
if ((*threads)[k].pc == new_pc
|
||||
&& !(*threads)[k].matched
|
||||
&& (*threads)[k].start_idx
|
||||
< (*threads)[parent_idx].start_idx) {
|
||||
return;
|
||||
};
|
||||
};
|
||||
|
||||
// Hare dups the parent's captures/rep_counters here
|
||||
// (`alloc(threads[parent_idx].captures...)?`, ha:569/572). Every
|
||||
// ww route into that dup is blocked today (re-probed post-C3,
|
||||
// PB7): the deref-spine spread SOURCE is loud-rejected (#35),
|
||||
// the per-element append is loud-rejected (#34 struct element
|
||||
// source), and the whole-element let-copy drops bytes (#7/F5).
|
||||
// The abort is sound, not a semantic hole: fold-2a's compile()
|
||||
// cannot emit inst_groupstart/inst_repeat, so both slices are
|
||||
// provably empty in every program this fold can run; the empty
|
||||
// case appends honest zeroed headers below. The verbatim dup
|
||||
// lands with the group/repeat fold (ww-core #3).
|
||||
if ((*threads)[parent_idx].captures.len != 0
|
||||
|| (*threads)[parent_idx].rep_counters.len != 0) {
|
||||
abort("regex: capture dup not yet portable (#35/#34/#7)");
|
||||
};
|
||||
let captures: []capture;
|
||||
let rep_counters: []size;
|
||||
|
||||
append(*threads, thread {
|
||||
pc = new_pc,
|
||||
start_idx = (*threads)[parent_idx].start_idx,
|
||||
start_bytesize = (*threads)[parent_idx].start_bytesize,
|
||||
matched = (*threads)[parent_idx].matched,
|
||||
failed = (*threads)[parent_idx].failed,
|
||||
captures = captures,
|
||||
rep_counters = rep_counters,
|
||||
...
|
||||
});
|
||||
return;
|
||||
};
|
||||
|
||||
// run_thread (regex.ha:589-742) is deferred behind ONE remaining
|
||||
// compiler boundary: its loop condition
|
||||
// `is_consuming_inst(re.insts[threads[i].pc])` passes the 56B inst
|
||||
// BY VALUE from a slice-element source, which the #38b arg wiring
|
||||
// loud-rejects ("unsupported source kind 12" — ident sources landed
|
||||
// with #19; the slice-element extension is task #40, in flight).
|
||||
// Probed pre-port (PB6c); ruled: run_thread lands Hare-VERBATIM once
|
||||
// #40 wires the source. Every other run_thread shape is probe-proven
|
||||
// at HEAD (PB6b match-arm store + composed frombytes bound, P7
|
||||
// composed scrutinee + compound pc step, P8 newmatch return).
|
||||
|
||||
// Frees a [[result]].
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user