lib/regex: fold-2b tranche A — thread/newmatch types + leaf fns

thread (regex.ha:55-64) and newmatch (ha:66) land verbatim ahead of
their engine consumers; result_free (ha:1113-1116) and strerror
(ha:1126-1127) complete the exported error/result surface.

delete_thread/add_thread deferred behind #15 (append-through-ptr)
and #17 (deref-spine element reads); is_consuming_inst deferred
behind #19 (>48B tagged by-value call boundary unwired + divergent
callee receive) — noted at the Hare-order site.

Tests are row-table driven: thread_shape reads back both appended
threads against a [2]texp want table (root_capture rows deferred —
every read route is compiler-blocked, #6/#7, probed at HEAD);
newmatch_discriminates drives one row per (void|newmatch|nomem)
member, incl. a nomem-vs-newmatch row; result_free also covers the
zero-header empty result (find()'s ha:915-916 no-match shape).
Byte-id re-verified on the regenerated combined: the pre-existing
FC0 regex.finish hunk is the only divergence.
This commit is contained in:
2026-06-04 08:54:17 +09:00
parent b7a4eda40a
commit c801aa7954
3 changed files with 216 additions and 6 deletions

View File

@@ -1,8 +1,16 @@
// 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); every
// other metacharacter arm, exec / find / replace are DEFERRED to
// later folds.
// 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.
//
// One fold-1 construct is held back behind a filed compiler/fidelity
// gap (see the charclass_map site below):
@@ -62,6 +70,22 @@ export type capture = struct {
end_bytesize: size,
};
// ref/hare/regex/regex.ha:55-64.
type thread = struct {
pc: size,
start_idx: size,
start_bytesize: size,
root_capture: capture,
captures: []capture,
rep_counters: []size,
matched: bool,
failed: bool,
};
// Discriminates a fresh match from plain void at run_thread's return
// boundary. ref/hare/regex/regex.ha:66.
type newmatch = void;
// ref/hare/regex/regex.ha:68-72.
export type charset = [](charset_lit_item | charset_range_item |
charset_class_item);
@@ -181,3 +205,28 @@ export fn compile(expr: str) (regex | error | nomem) = {
n_reps = n_reps,
};
};
// 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.
// Frees a [[result]].
//
// ref/hare/regex/regex.ha:1113-1116, verbatim — the free() builtin is
// the documented no-op (#27; see finish()).
export fn result_free(s: result) void = {
free(s);
};
// Converts an [[error]] into a user-friendly string.
//
// ref/hare/regex/regex.ha:1126-1127 (expression-bodied in Hare; ww
// fns take block bodies).
export fn strerror(err: error) str = {
return err;
};