regex: fold 5b — parse_repetition leaf (ha:486-545)
Dead until the { arm lands (tranche-A precedent); 13-row direct
private-fn table, error texts byte-exact. Hare's verbatim
((void|size),(void|size),size) tuple return can't cross a union
boundary yet — cstage's (tuple|error) return store is cgen-unwired and
wwstage's variant-match rejects the tuple case arm (filed #47) — so it
respells as the private repparts struct per the scope-fold5 §3
pre-signed fallback; graduates back to the tuple when #47 closes.
Riders: call-result .N tuple read loud-rejects (filed #48, bind-first
local); strings.index's standing i32 convention (#8) stays internal,
widened at each size boundary; ha:494's same-name re-bind is rejected,
second local feb.
This commit is contained in:
@@ -30,6 +30,7 @@ package regex;
|
|||||||
import bufio;
|
import bufio;
|
||||||
import io;
|
import io;
|
||||||
import memio;
|
import memio;
|
||||||
|
import strconv;
|
||||||
import strings;
|
import strings;
|
||||||
import types;
|
import types;
|
||||||
import encoding.utf8;
|
import encoding.utf8;
|
||||||
@@ -628,6 +629,100 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// parse_repetition's Hare-verbatim return is the 3-tuple
|
||||||
|
// ((void | size), (void | size), size) (regex.ha:488); a tuple with
|
||||||
|
// tagged elements can't yet cross a union boundary in ww — cstage's
|
||||||
|
// return store into (tuple | error) is cgen-unwired
|
||||||
|
// (cg_widen_tagged_store) and wwstage's variant-match rejects the
|
||||||
|
// tuple case arm (filed, ww-core #47) — so the tuple respells as this
|
||||||
|
// private struct, positionally: .0 → min, .1 → max, .2 → replen.
|
||||||
|
// GRADUATION: when #47 closes, repparts reverts to the verbatim tuple
|
||||||
|
// with the test rows unchanged.
|
||||||
|
type repparts = struct {
|
||||||
|
min: (void | size),
|
||||||
|
max: (void | size),
|
||||||
|
replen: size,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ref/hare/regex/regex.ha:486-545, whole. strings.index returns
|
||||||
|
// (i32 | void) in ww — the standing lib-wide str-index-i32 convention
|
||||||
|
// (lib/strings/strings.ww:54, #8) vs Hare's (size | void)
|
||||||
|
// (ref/hare/strings/index.ha:10) — so the index results stay i32
|
||||||
|
// INTERNALLY (the ha:499 comparison is same-domain) and each value
|
||||||
|
// widens explicitly at the boundary Hare types as size (the repparts
|
||||||
|
// field stores). ha:494 re-binds `first_endbrace` over itself; ww
|
||||||
|
// rejects a same-scope re-decl ("let redeclared"), so the unwrapped
|
||||||
|
// value is `feb`.
|
||||||
|
fn parse_repetition(s: str) (repparts | error) = {
|
||||||
|
let first_comma: (i32 | void) = strings.index(s, ",");
|
||||||
|
let first_endbrace: (i32 | void) = strings.index(s, "}");
|
||||||
|
if (first_endbrace is void) {
|
||||||
|
return "Repetition expression syntax error '{n}'": error;
|
||||||
|
};
|
||||||
|
let feb: i32 = first_endbrace as i32;
|
||||||
|
|
||||||
|
let min_str: str = "";
|
||||||
|
let max_str: str = "";
|
||||||
|
let is_single_arg: bool = false;
|
||||||
|
if (first_comma is void || feb < first_comma as i32) {
|
||||||
|
let cut: (str, str) = strings.cut(s, "}");
|
||||||
|
min_str = cut.0;
|
||||||
|
max_str = cut.0;
|
||||||
|
is_single_arg = true;
|
||||||
|
} else {
|
||||||
|
let cut: (str, str) = strings.cut(s, ",");
|
||||||
|
min_str = cut.0;
|
||||||
|
// Hare reads .0 straight off the call (ha:507); a tuple-elem
|
||||||
|
// read on a CALL result is loud-unsupported (filed, ww-core
|
||||||
|
// #48) — bound local first.
|
||||||
|
let cut2: (str, str) = strings.cut(cut.1, "}");
|
||||||
|
max_str = cut2.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
let min: (void | size) = void;
|
||||||
|
let max: (void | size) = void;
|
||||||
|
|
||||||
|
if (min_str.len > 0) {
|
||||||
|
// Hare's match-EXPRESSION with if-yields (ha:514-525)
|
||||||
|
// spells as a statement match (no yield-expr; the search
|
||||||
|
// scanrune precedent, #51). stoi's base is explicit — ww
|
||||||
|
// has no default args (the newscanner precedent; cf
|
||||||
|
// lib/encoding/hex/hex.ww:131).
|
||||||
|
match (strconv.stoi(min_str, strconv.base.DEC)) {
|
||||||
|
case let res: int => {
|
||||||
|
if (res < 0) {
|
||||||
|
return "Negative repetition count '{-n}'": error;
|
||||||
|
};
|
||||||
|
min = (res: size);
|
||||||
|
};
|
||||||
|
case => return "Repetition expression syntax error '{n}'": error;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// `min = 0;` (ha:524): an untyped-int widen-store into
|
||||||
|
// (void | size) mis-tags (#33) — cast form pinned.
|
||||||
|
min = (0: size);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (max_str.len > 0) {
|
||||||
|
match (strconv.stoi(max_str, strconv.base.DEC)) {
|
||||||
|
case let res: int => {
|
||||||
|
if (res < 0) {
|
||||||
|
return "Negative repetition count '{-n}'": error;
|
||||||
|
};
|
||||||
|
max = (res: size);
|
||||||
|
};
|
||||||
|
case => return "Repetition expression syntax error '{n}'": error;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hare's if-EXPRESSION (ha:539-544) spells as a statement.
|
||||||
|
let rep_len: size = (min_str.len: size);
|
||||||
|
if (!is_single_arg) {
|
||||||
|
rep_len = (min_str.len: size) + 1 + (max_str.len: size);
|
||||||
|
};
|
||||||
|
return repparts { min = min, max = max, replen = rep_len };
|
||||||
|
};
|
||||||
|
|
||||||
// ref/hare/regex/regex.ha:547-551, verbatim — both free()s are the
|
// ref/hare/regex/regex.ha:547-551, verbatim — both free()s are the
|
||||||
// documented no-op (#27; see finish()), kept for source parity. ww
|
// documented no-op (#27; see finish()), kept for source parity. ww
|
||||||
// has no pointer auto-deref, so Hare's `threads[i]` spells
|
// has no pointer auto-deref, so Hare's `threads[i]` spells
|
||||||
|
|||||||
@@ -2137,6 +2137,90 @@ type smcase = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---- fold 5b: repetition ----------------------------------------------
|
||||||
|
|
||||||
|
// parse_repetition rows (regex.ha:486-545) — DIRECT private-fn table
|
||||||
|
// (the leaf fn lands ahead of its `{`-arm consumer; tranche-A
|
||||||
|
// precedent). Expectations hand-executed from Hare's own code paths:
|
||||||
|
// the input is everything AFTER `{` (compile passes iterstr's rest),
|
||||||
|
// single-arg `{n}` sets max = min and replen = len(n) (ha:500-503,
|
||||||
|
// 539-541); two-arg replen = len(min) + 1 + len(max) (ha:543); an
|
||||||
|
// empty min is 0 (ha:524) while an empty max stays void (ha:527 —
|
||||||
|
// the `{n,}` open bound); a `,` BEYOND the first `}` is not a
|
||||||
|
// two-arg form (ha:499). The two error texts are byte-exact
|
||||||
|
// (ha:492/521/531-536). max_void distinguishes "expect void" from
|
||||||
|
// "expect maxv"; err != "" rows expect that exact error.
|
||||||
|
type prrow = struct {
|
||||||
|
input: str,
|
||||||
|
minv: size,
|
||||||
|
maxv: size,
|
||||||
|
max_void: bool,
|
||||||
|
replen: size,
|
||||||
|
err: str,
|
||||||
|
};
|
||||||
|
|
||||||
|
@test fn parse_repetition_cases() void = {
|
||||||
|
let rows: [13]prrow = [
|
||||||
|
prrow { input = "2}", minv = 2, maxv = 2, max_void = false,
|
||||||
|
replen = 1, err = "" },
|
||||||
|
prrow { input = "2}$", minv = 2, maxv = 2, max_void = false,
|
||||||
|
replen = 1, err = "" },
|
||||||
|
// comma AFTER the endbrace — still single-arg (ha:499)
|
||||||
|
prrow { input = "2},5", minv = 2, maxv = 2, max_void = false,
|
||||||
|
replen = 1, err = "" },
|
||||||
|
prrow { input = "1,2}", minv = 1, maxv = 2, max_void = false,
|
||||||
|
replen = 3, err = "" },
|
||||||
|
prrow { input = ",2}", minv = 0, maxv = 2, max_void = false,
|
||||||
|
replen = 2, err = "" },
|
||||||
|
prrow { input = ",0}", minv = 0, maxv = 0, max_void = false,
|
||||||
|
replen = 2, err = "" },
|
||||||
|
prrow { input = "2,}", minv = 2, maxv = 0, max_void = true,
|
||||||
|
replen = 2, err = "" },
|
||||||
|
prrow { input = ",}", minv = 0, maxv = 0, max_void = true,
|
||||||
|
replen = 1, err = "" },
|
||||||
|
prrow { input = "12,34}xyz", minv = 12, maxv = 34,
|
||||||
|
max_void = false, replen = 5, err = "" },
|
||||||
|
prrow { input = "-1,2}", minv = 0, maxv = 0, max_void = false,
|
||||||
|
replen = 0, err = "Negative repetition count '{-n}'" },
|
||||||
|
prrow { input = "x,2}", minv = 0, maxv = 0, max_void = false,
|
||||||
|
replen = 0,
|
||||||
|
err = "Repetition expression syntax error '{n}'" },
|
||||||
|
prrow { input = "0,-2}", minv = 0, maxv = 0, max_void = false,
|
||||||
|
replen = 0, err = "Negative repetition count '{-n}'" },
|
||||||
|
// no endbrace at all (ha:491-493)
|
||||||
|
prrow { input = "2", minv = 0, maxv = 0, max_void = false,
|
||||||
|
replen = 0,
|
||||||
|
err = "Repetition expression syntax error '{n}'" },
|
||||||
|
];
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < len(rows)) {
|
||||||
|
let r: (repparts | error) = parse_repetition(rows[i].input);
|
||||||
|
match (r) {
|
||||||
|
case let t: repparts => {
|
||||||
|
if (rows[i].err.len > 0) { fail(); };
|
||||||
|
// .min is always size after a successful parse
|
||||||
|
// (ha:523-525 — empty min defaults to 0)
|
||||||
|
if (!(t.min is size)) { fail(); };
|
||||||
|
if (t.min as size != rows[i].minv) { fail(); };
|
||||||
|
if (rows[i].max_void) {
|
||||||
|
if (!(t.max is void)) { fail(); };
|
||||||
|
} else {
|
||||||
|
if (!(t.max is size)) { fail(); };
|
||||||
|
if (t.max as size != rows[i].maxv) { fail(); };
|
||||||
|
};
|
||||||
|
if (t.replen != rows[i].replen) { fail(); };
|
||||||
|
};
|
||||||
|
case let e: regex.error => {
|
||||||
|
if (rows[i].err.len == 0) { fail(); };
|
||||||
|
if (strings.compare((e: str), rows[i].err) != 0) {
|
||||||
|
fail();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export fn main() i32 = {
|
export fn main() i32 = {
|
||||||
signalled = 1; lit_and_match();
|
signalled = 1; lit_and_match();
|
||||||
signalled = 2; size_aliases_distinct();
|
signalled = 2; size_aliases_distinct();
|
||||||
@@ -2180,5 +2264,6 @@ export fn main() i32 = {
|
|||||||
signalled = 40; fold5_find_cases();
|
signalled = 40; fold5_find_cases();
|
||||||
signalled = 41; fold5_optional_group();
|
signalled = 41; fold5_optional_group();
|
||||||
signalled = 42; fold5_submatches();
|
signalled = 42; fold5_submatches();
|
||||||
|
signalled = 43; parse_repetition_cases();
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user