lib/regex: type model + finish() (regex port fold 1, partial)
Port of ref/hare/regex/regex.ha fold 1 (the data model). Lands the
full type model — error, the inst_* variants + 10-variant inst union
(the nominally-distinct same-underlying size/void aliases included),
result/capture, charset + items, the regex struct — plus finish().
Test 989_regex_run pins variant discrimination, payload extraction,
struct shapes, and finish() on cstage; w6c == w6c_ww byte-identical.
Two fold-1 constructs are held back behind filed compiler/fidelity
gaps, documented at their sites (regex tasks A–D):
- charclass_map (regex.ha:74-87): const [](str, *fn(rune) bool)
table — blocked on the array-literal->slice element-coercion
checker gap (type.c:402-404 #258 borrow uses exact type_eq,
no element decay). It needs `import ascii;`, so both land with
the consuming fold (compile) once the gap is fixed.
- finish() free()s; ww is a no-free runtime (rt/alloc.s:30), so the
faithful body drops the frees, as the port drops every Hare
free(). Kept as a no-op for API parity.
DEFERRED to later folds: compile()/exec/find/replace.
This commit is contained in:
98
lib/regex/regex.ww
Normal file
98
lib/regex/regex.ww
Normal file
@@ -0,0 +1,98 @@
|
||||
// regex — POSIX extended regular expressions. Port of
|
||||
// ref/hare/regex/regex.ha. Fold 1 = the data model only; compile() /
|
||||
// exec / find / replace are DEFERRED to later folds.
|
||||
//
|
||||
// Two fold-1 constructs are held back behind filed compiler/fidelity
|
||||
// gaps (see the charclass_map and finish() sites below):
|
||||
// - charclass_map (regex.ha:74-87) — a module-level const slice of
|
||||
// (str, *fn(rune) bool) tuples. Blocked on the array-literal→slice
|
||||
// element-coercion checker gap (#25; type.c:402-404 #258 borrow
|
||||
// uses exact type_eq, no element decay).
|
||||
// - finish() (regex.ha:96-102) — frees; ww is a no-free runtime (#27).
|
||||
package regex;
|
||||
|
||||
// ref/hare/regex/regex.ha:14 — an error string describing a compilation
|
||||
// error.
|
||||
export type error = !str;
|
||||
|
||||
// ref/hare/regex/regex.ha:16-30.
|
||||
export type inst_lit = rune;
|
||||
export type inst_charset = struct { idx: size, is_positive: bool };
|
||||
export type inst_any = void;
|
||||
export type inst_split = size;
|
||||
export type inst_jump = size;
|
||||
export type inst_skip = void;
|
||||
export type inst_match = bool;
|
||||
export type inst_groupstart = size;
|
||||
export type inst_groupend = void;
|
||||
export type inst_repeat = struct {
|
||||
id: size,
|
||||
origin: size,
|
||||
min: (void | size),
|
||||
max: (void | size),
|
||||
};
|
||||
|
||||
// ref/hare/regex/regex.ha:32-35.
|
||||
export type inst = (inst_lit | inst_any | inst_split | inst_jump |
|
||||
inst_skip | inst_match | inst_charset |
|
||||
inst_groupstart | inst_groupend |
|
||||
inst_repeat);
|
||||
|
||||
// The resulting match of a [[regex]] applied to a string.
|
||||
//
|
||||
// The first [[capture]] corresponds to the implicit zeroth capture
|
||||
// group, i.e. the whole expression.
|
||||
//
|
||||
// The rest of the [[capture]]s correspond to the rest of the capture
|
||||
// groups, i.e. the sub-expressions.
|
||||
// ref/hare/regex/regex.ha:44.
|
||||
export type result = []capture;
|
||||
|
||||
// A (sub)match corresponding to a regular expression's capture group.
|
||||
// ref/hare/regex/regex.ha:47-53.
|
||||
export type capture = struct {
|
||||
content: str,
|
||||
start: size,
|
||||
start_bytesize: size,
|
||||
end: size,
|
||||
end_bytesize: size,
|
||||
};
|
||||
|
||||
// ref/hare/regex/regex.ha:68-72.
|
||||
export type charset = [](charset_lit_item | charset_range_item |
|
||||
charset_class_item);
|
||||
export type charset_lit_item = rune;
|
||||
export type charset_range_item = (u32, u32);
|
||||
export type charset_class_item = (str, *fn(c: rune) bool);
|
||||
|
||||
// ref/hare/regex/regex.ha:74-87 — charclass_map: the const
|
||||
// [](str, *fn(rune) bool) table mapping POSIX class tokens to the
|
||||
// matching ascii predicate. DEFERRED: the array-literal→slice
|
||||
// assignability check (type.c:402-404, the #258 borrow) compares
|
||||
// element types with exact type_eq and applies NO element coercion, so
|
||||
// the literal `[(":alnum:]", &ascii.isalnum), ...]` (typed
|
||||
// `[N](untyped_str, *fn(rune) bool)`) is rejected against the declared
|
||||
// `[](str, *fn(rune) bool)`. Minimal repro: `let xs: [](size, size) =
|
||||
// [(1, 2)];`. Reshaping to a fixed `[12](...)` array would compile but
|
||||
// is an unfaithful workaround (CLAUDE.md rule-7), so the table — and
|
||||
// the `import ascii;` it needs — land with the consuming fold (compile)
|
||||
// once the checker gap is fixed.
|
||||
|
||||
// ref/hare/regex/regex.ha:89-93.
|
||||
export type regex = struct {
|
||||
insts: []inst,
|
||||
charsets: []charset,
|
||||
n_reps: size,
|
||||
};
|
||||
|
||||
// Frees resources associated with a [[regex]].
|
||||
//
|
||||
// ref/hare/regex/regex.ha:96-102 frees re.insts / each charset /
|
||||
// re.charsets. ww is a no-free runtime (rt/alloc.s:30 — rt_free is a
|
||||
// no-op; the bump allocator can't reclaim, process-exit does), so the
|
||||
// faithful ww body drops the frees, matching how the port drops every
|
||||
// Hare free(). Kept for API parity with the Hare surface. Temporary
|
||||
// empty body: #27 makes the free() builtin compile to a documented
|
||||
// no-op, after which this ports the Hare frees VERBATIM (the no-op
|
||||
// builtin reclaims nothing, same end state).
|
||||
export fn finish(re: *regex) void = { };
|
||||
Reference in New Issue
Block a user