regex: fold 5b — repetition {m,n} (the { arm + run_thread inst_repeat + rep prefill)
All three loud bounds flip: the { metachar (ha:368-402, inclusive
advance bound), the run_thread inst_repeat arm (ha:669-684, is/as
verbatim per the #42 fence), and the search rep_counters prefill
(ha:763-765, count-loop respell of the sized-fill alloc). The
deferred-metachar table EMPTIES — every metacharacter compiles; the
POSIX class body is the only loud surface left in lib/regex.
Two silent compiler finds surfaced and filed, respells drew-signed:
#49 (whole-struct assign from a match binding w/ tagged fields
corrupts them context-dependently — the parse_repetition unwrap goes
field-wise in-arm) and #50 (insert() grows the dst before evaluating
its value arg, +1 split mis-target on Hare's len(insts)+2 payload —
pre-bound, the '?'/'|' arm convention).
Activation table: the {m,n} matrix (+test.ha:443-460) incl. the
open-ended (0,7) and {,0}de rows, the \{ \} escape pair, the :635
5a carve-out, the {0,}/{1,}/{0,1} twins (cross-spelling agreement
with their 5a */+/? siblings), the Various composed rows minus the
[[:class:]] row (POSIX abort, fold-4 ruling), findall fo{2,}, plus
ww-added multibyte {2} and long-input {1,} stress rows.
This commit is contained in:
@@ -15,9 +15,10 @@
|
||||
// the POSIX `[[:class:]]` BODY stays loud behind charclass_map);
|
||||
// fold 5a = capture groups `(`/`)` (compile arms + run_thread
|
||||
// groupstart/groupend + the add_thread capture dup + the search
|
||||
// capture spread). Remaining arms (`{` repetition — and replace) are
|
||||
// DEFERRED — probed pre-port, pA*/pB*/PB*/PC*/PD*/PE*/PF*/PG* probes.
|
||||
// They land with their folds.
|
||||
// capture spread); fold 5b = repetition `{m,n}` (parse_repetition +
|
||||
// the `{` arm + the run_thread inst_repeat arm + the search
|
||||
// rep_counters prefill). Remaining: the POSIX `[:class:]` BODY (the
|
||||
// last loud surface) — and replace. They land with their folds.
|
||||
//
|
||||
// One fold-1 construct is held back behind a filed compiler/fidelity
|
||||
// gap (see the charclass_map site below):
|
||||
@@ -294,13 +295,14 @@ fn handle_bracket(
|
||||
// whole-expression fixup (470-473), postfix `?` (403-420) / `*`
|
||||
// (421-443) / `+` (444-459) — the fold-4 bracket surface: the
|
||||
// in_bracket dispatch (265-275), the `[` flip (313-314) and the
|
||||
// handle_bracket state quad (249-252) — and the fold-5a group arms:
|
||||
// handle_bracket state quad (249-252) — the fold-5a group arms:
|
||||
// `(` (317-323), `)` (324-334), capture_idx (256) and the loop-exit
|
||||
// `done` Unmatched-'(' check (277-282); the anchors' group_level
|
||||
// arms and the postfix inst_groupend/groupstart arms went live with
|
||||
// them. The remaining metacharacter arm (`{` repetition) is one loud
|
||||
// not-yet-ported error — the explicit fold boundary; falling to
|
||||
// literal would be a silent semantic lie.
|
||||
// them — and the fold-5b repetition arm `{` (368-402) over
|
||||
// parse_repetition + n_reps (255). Every metacharacter is ported;
|
||||
// the only remaining loud surface is the POSIX class BODY inside
|
||||
// handle_bracket.
|
||||
//
|
||||
// Hare's `defer if (!ok) free(...)` cleanup (ha:231-237) is omitted:
|
||||
// ww has no `defer if` (cf lib/strings/strings.ww:85), and the free()
|
||||
@@ -593,10 +595,78 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
||||
delete(jump_idxs[group_level][:]);
|
||||
group_level -= 1;
|
||||
};
|
||||
case '{':
|
||||
// fold-5a boundary: the repetition arm (ha:368-401)
|
||||
// rides fold 5b.
|
||||
return "regex: metacharacter not yet ported": error;
|
||||
case '{': { // regex.ha:368-402
|
||||
let origin: size = (insts.len: size) - 1;
|
||||
if (insts[origin] is inst_groupend) {
|
||||
// D13 match, cf '?' — `?` into compile's >32B
|
||||
// tagged return is loud-stopped (#38b).
|
||||
match (find_last_groupstart(insts[0:origin])) {
|
||||
case let e: error => return e;
|
||||
case let sz: size => { origin = sz; };
|
||||
};
|
||||
};
|
||||
let rest: str = strings.iterstr(&iter);
|
||||
// Hare's `parse_repetition(rest)?` (ha:374) — the D13
|
||||
// match; the binding unwraps FIELD-WISE: a whole-struct
|
||||
// assign from a match binding with tagged fields
|
||||
// silently corrupts them (filed, ww-core #49). The
|
||||
// rp_* locals are Hare's rep_parts.0/.1/.2 through the
|
||||
// repparts respell (#47; see parse_repetition).
|
||||
let rp_min: (void | size) = void;
|
||||
let rp_max: (void | size) = void;
|
||||
let rp_replen: size = 0;
|
||||
match (parse_repetition(rest)) {
|
||||
case let e: error => return e;
|
||||
case let rp: repparts => {
|
||||
rp_min = rp.min;
|
||||
rp_max = rp.max;
|
||||
rp_replen = rp.replen;
|
||||
};
|
||||
};
|
||||
// ha:375 compares the tagged elem to 0 directly
|
||||
// (`rep_parts.0 == 0`); no tagged==int compare in ww —
|
||||
// the is/as respell (ruled, scope §9b).
|
||||
let can_skip: bool = rp_min is size
|
||||
&& rp_min as size == 0;
|
||||
// ha:376-380's if-EXPRESSION min selection spells as a
|
||||
// widen-assign into the tagged let.
|
||||
let min: (void | size) = rp_min;
|
||||
if (can_skip) {
|
||||
min = (1: size);
|
||||
};
|
||||
if (can_skip) {
|
||||
// len(insts) - 1 is the current last instruction
|
||||
// len(insts) is the next instruction
|
||||
// advance to len(insts) + 1 to make space for the `inst_split`
|
||||
// advance to len(insts) + 2 to make space for the `inst_repeat`
|
||||
//
|
||||
// Hare evaluates the payload BEFORE the insert
|
||||
// (ha:386-387); ww's insert() grows the dst
|
||||
// before evaluating the value arg (filed,
|
||||
// ww-core #50) — payload pre-bound, the
|
||||
// '?'/'|' arm convention.
|
||||
let split_target: size = (insts.len: size) + 2;
|
||||
insert(insts[origin],
|
||||
(split_target: inst_split));
|
||||
shift(insts[origin + 1:]);
|
||||
origin += 1;
|
||||
};
|
||||
let newinst: inst = inst_repeat {
|
||||
id = n_reps,
|
||||
origin = origin,
|
||||
min = min,
|
||||
max = rp_max,
|
||||
};
|
||||
// ha:397-400 — the bound is INCLUSIVE (`<=`), exactly
|
||||
// as Hare; the discarded strings.next binds to a
|
||||
// throwaway let (the handle_bracket skip precedent).
|
||||
for (let i: size = 0; i <= rp_replen; i += 1) {
|
||||
let skip: (rune | utf8.done) = strings.next(&iter);
|
||||
r_idx += 1;
|
||||
};
|
||||
append(insts, newinst);
|
||||
n_reps += 1;
|
||||
};
|
||||
case: // regex.ha:462-463
|
||||
append(insts, (r: inst_lit));
|
||||
};
|
||||
@@ -782,13 +852,12 @@ fn add_thread(threads: *[]thread, parent_idx: size, new_pc: size) (void | nomem)
|
||||
return;
|
||||
};
|
||||
|
||||
// ref/hare/regex/regex.ha:589-742. Only the arms compile() can emit
|
||||
// execute (skip + split + jump + match + groupstart + groupend
|
||||
// non-consuming; lit + any + charset consuming — split/jump went live
|
||||
// with fold 3's `|`/`?`/`*` arms, charset with fold 4's brackets,
|
||||
// groupstart/groupend with fold 5a's `(`/`)`); the inst_repeat arm is
|
||||
// one loud not-yet-ported abort — the fold-5b boundary, the compile()
|
||||
// metachar discipline. The "unreachable" aborts on lit/any inside
|
||||
// ref/hare/regex/regex.ha:589-742. Every arm compile() can emit
|
||||
// executes (skip + split + jump + match + groupstart + groupend +
|
||||
// repeat non-consuming; lit + any + charset consuming — split/jump
|
||||
// went live with fold 3's `|`/`?`/`*` arms, charset with fold 4's
|
||||
// brackets, groupstart/groupend with fold 5a's `(`/`)`, repeat with
|
||||
// fold 5b's `{`). The "unreachable" aborts on lit/any inside
|
||||
// the non-consuming loop (ha:604-605) and the trailing default
|
||||
// (ha:738) are Hare's own unreachable arms; Hare spells them bare
|
||||
// `abort()`, ww carries a message — the zero-arg builtin form is
|
||||
@@ -901,8 +970,23 @@ fn run_thread(
|
||||
capture.start_bytesize:capture.end_bytesize]);
|
||||
(*threads)[i].pc += 1;
|
||||
};
|
||||
case inst_repeat =>
|
||||
abort("regex: inst_repeat not yet ported");
|
||||
case let ir: inst_repeat => { // regex.ha:669-684
|
||||
assert(ir.id < (len((*threads)[i].rep_counters): size));
|
||||
(*threads)[i].rep_counters[ir.id] += 1;
|
||||
if (ir.max is size
|
||||
&& (*threads)[i].rep_counters[ir.id]
|
||||
> ir.max as size) {
|
||||
(*threads)[i].failed = true;
|
||||
return;
|
||||
};
|
||||
let new_pc: size = (*threads)[i].pc + 1;
|
||||
(*threads)[i].pc = ir.origin;
|
||||
if (ir.min is void
|
||||
|| (*threads)[i].rep_counters[ir.id]
|
||||
>= ir.min as size) {
|
||||
add_thread(threads, i, new_pc)?;
|
||||
};
|
||||
};
|
||||
case => abort("regex: unreachable");
|
||||
};
|
||||
};
|
||||
@@ -1002,12 +1086,13 @@ fn search(
|
||||
// and every free in the block is the documented no-op (#27).
|
||||
|
||||
// ha:763-765 prefills threads[0].rep_counters via
|
||||
// `alloc([0...], re.n_reps)?`. No program this fold can compile
|
||||
// has n_reps > 0 (the inst_repeat arm is loud), and the sized
|
||||
// fill form has no ww spelling yet — loud, like the inst_repeat
|
||||
// arm; the real prefill lands with the repeat fold.
|
||||
// `alloc([0...], re.n_reps)?` — the sized-fill alloc has no ww
|
||||
// spelling (D3 family) and ww has no `z` size-literal suffix
|
||||
// (cf lib/strconv/decimal.ww:13) — count-loop append of (0: size).
|
||||
if (re.n_reps > 0) {
|
||||
abort("regex: repetitions not yet ported");
|
||||
for (let k: size = 0; k < re.n_reps; k += 1) {
|
||||
append(threads[0].rep_counters, (0: size));
|
||||
};
|
||||
};
|
||||
|
||||
let str_idx: size = 0;
|
||||
|
||||
@@ -257,27 +257,6 @@ fn fail() void = { os.exit(signalled + 10); };
|
||||
};
|
||||
};
|
||||
|
||||
// Every deferred metacharacter is a LOUD error carrying the exact
|
||||
// fold-boundary text — falling through to the literal default would
|
||||
// silently compile a wrong program, and any OTHER error text would
|
||||
// mean an arm was half-ported. One pattern per deferred arm so the
|
||||
// fold that ports an arm consciously deletes its row. Fold 3 flipped
|
||||
// \ ^ $ | ? * + positive (fold3_* below); fold 4 flipped `[`
|
||||
// (fold4_* below); fold 5a flipped `(`/`)` (fold5_* below — "a("/"a)"
|
||||
// graduated into fold5_compile_errors with their REAL texts);
|
||||
// repetition `{` remains.
|
||||
@test fn compile_metachar_loud() void = {
|
||||
match (regex.compile("a{")) {
|
||||
case let e: regex.error => {
|
||||
if (strings.compare((e: str),
|
||||
"regex: metacharacter not yet ported") != 0) {
|
||||
fail();
|
||||
};
|
||||
};
|
||||
case => fail();
|
||||
};
|
||||
};
|
||||
|
||||
// The thread struct (regex.ha:55-64) is in tree ahead of its engine
|
||||
// consumers so the pending #15/#17 fix probes exercise the real type.
|
||||
// Pin the field layout via the P6-proven wide-literal append + a
|
||||
@@ -2221,6 +2200,233 @@ type prrow = struct {
|
||||
};
|
||||
};
|
||||
|
||||
// 5b compile-error rows end-to-end through compile() — the two
|
||||
// parse_repetition texts surface verbatim (+test.ha:461-463 ERROR
|
||||
// rows). "a{" is the GRADUATED metachar-loud row: with `{` ported the
|
||||
// deferred-metachar table empties — every metacharacter compiles, and
|
||||
// the only loud surface left in lib/regex is the POSIX-class runtime
|
||||
// abort (a fold-4 pin, not an error row). "a{" has no `}` in the
|
||||
// rest, so it lands on the ha:491-493 syntax text.
|
||||
@test fn fold5b_compile_errors() void = {
|
||||
let rows: [4]cerow = [
|
||||
cerow { pat = "^x(abc){-1,2}$",
|
||||
want = "Negative repetition count '{-n}'" },
|
||||
cerow { pat = "^x(abc){x,2}$",
|
||||
want = "Repetition expression syntax error '{n}'" },
|
||||
cerow { pat = "^x(abc){0,-2}$",
|
||||
want = "Negative repetition count '{-n}'" },
|
||||
cerow { pat = "a{",
|
||||
want = "Repetition expression syntax error '{n}'" },
|
||||
];
|
||||
let i: i32 = 0;
|
||||
for (i < len(rows)) {
|
||||
let p: str = rows[i].pat;
|
||||
match (regex.compile(p)) {
|
||||
case let e: regex.error => {
|
||||
let w: str = rows[i].want;
|
||||
if (strings.compare((e: str), w) != 0) { fail(); };
|
||||
};
|
||||
case => fail();
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
// fold-5b find/test rows — Hare's own {m,n} matrix (+test.ha:443-460
|
||||
// incl. the open-ended (0,7) row and the `{,0}de` pair), the `\{`/`\}`
|
||||
// escape pair :437-438 (pins that ESCAPED braces never enter the `{`
|
||||
// arm), the 5a carve-out :635 `(a|(b?|c*){,1}|d+|e)` come home, the
|
||||
// `{0,}`/`{1,}`/`{0,1}` nested twins :649-665 (each must agree with
|
||||
// its 5a `*`/`+`/`?` sibling's result on the same input — the
|
||||
// cross-spelling invariant), and the "Various" composed rows :462-485
|
||||
// minus the [[:class:]] row (POSIX class is a runtime loud abort, the
|
||||
// fold-4 ruling — excluded until the POSIX fold). end == -1 resolves
|
||||
// to rune length (+test.ha:693-697). The multibyte `{2}` row and the
|
||||
// long-input `{1,}` thread/counter-explosion stress row are ww-added
|
||||
// (B4 lesson; rob's rider). Cross-pins test() == (find() matched);
|
||||
// the 5a/4/3 tables above re-run untouched in the same binary — the
|
||||
// dedup/trim/leftmost regression net under the new repeat spawns.
|
||||
@test fn fold5b_find_cases() void = {
|
||||
let rows: [30]f5case = [
|
||||
// {m,n} matrix (+test.ha:443-460)
|
||||
f5case { expr = "^x(abc){2}$", input = "xabcabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 7, eb = 7, content = "xabcabc" },
|
||||
f5case { expr = "^x(abc){3}$", input = "xabcabc",
|
||||
matches = false, ... },
|
||||
f5case { expr = "^x(abc){1,2}$", input = "xabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 4, eb = 4, content = "xabc" },
|
||||
f5case { expr = "^x(abc){1,2}$", input = "xabcabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 7, eb = 7, content = "xabcabc" },
|
||||
f5case { expr = "^x(abc){1,2}$", input = "xabcabcabc",
|
||||
matches = false, ... },
|
||||
f5case { expr = "^x(abc){,2}$", input = "xabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 4, eb = 4, content = "xabc" },
|
||||
f5case { expr = "^x(abc){,2}$", input = "xabcabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 7, eb = 7, content = "xabcabc" },
|
||||
// the open-ended (0,7) row :450
|
||||
f5case { expr = "^x(abc){,2}", input = "xabcabcabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 7, eb = 7, content = "xabcabc" },
|
||||
f5case { expr = "^x(abc){,0}de", input = "xde",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 3, eb = 3, content = "xde" },
|
||||
f5case { expr = "^x(abc){,0}de", input = "xe",
|
||||
matches = false, ... },
|
||||
f5case { expr = "^x(abc){,2}$", input = "xabcabcabc",
|
||||
matches = false, ... },
|
||||
f5case { expr = "^x(abc){1,}$", input = "xabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 4, eb = 4, content = "xabc" },
|
||||
f5case { expr = "^x(abc){1,}$", input = "xabcabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 7, eb = 7, content = "xabcabc" },
|
||||
f5case { expr = "^x(abc){3,}$", input = "xabcabc",
|
||||
matches = false, ... },
|
||||
f5case { expr = "^x(abc){3,}$", input = "xabcabcabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 10, eb = 10, content = "xabcabcabc" },
|
||||
f5case { expr = "^x(abc){2,2}$", input = "xabcabc",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 7, eb = 7, content = "xabcabc" },
|
||||
f5case { expr = "^x(abc){2,2}$", input = "xabc",
|
||||
matches = false, ... },
|
||||
f5case { expr = "^x(abc){2,2}$", input = "xabcabcabc",
|
||||
matches = false, ... },
|
||||
// escaped braces stay literal (+test.ha:437-438)
|
||||
f5case { expr = "^x(abc)\\{,2\\}$", input = "xabc{,2}",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 8, eb = 8, content = "xabc{,2}" },
|
||||
f5case { expr = "^x(abc)\\{,2\\}$", input = "xabcabc{,2}",
|
||||
matches = false, ... },
|
||||
// the 5a carve-out comes home (+test.ha:635)
|
||||
f5case { expr = "(a|(b?|c*){,1}|d+|e)", input = "e",
|
||||
matches = true, ncaps = 3, start = 0, sb = 0,
|
||||
end = 1, eb = 1, content = "e" },
|
||||
// nested twins: each agrees with its 5a sibling
|
||||
// (+test.ha:662-666: {0,} vs *, {1,} vs +, {0,1} vs ?)
|
||||
f5case { expr = "(a+|b){0,}", input = "ab", matches = true,
|
||||
ncaps = 2, start = 0, sb = 0, end = 2, eb = 2,
|
||||
content = "ab" },
|
||||
f5case { expr = "(a+|b){1,}", input = "ab", matches = true,
|
||||
ncaps = 2, start = 0, sb = 0, end = 2, eb = 2,
|
||||
content = "ab" },
|
||||
f5case { expr = "(a+|b){0,1}", input = "ab", matches = true,
|
||||
ncaps = 2, start = 0, sb = 0, end = 1, eb = 1,
|
||||
content = "a" },
|
||||
// "Various" composed rows (+test.ha:462-485; the M15 4QN
|
||||
// [[:class:]] row is excluded — POSIX class is a runtime
|
||||
// loud abort until the POSIX fold)
|
||||
f5case { expr = "^.(1024)?(face)*(1024)*ca*(f+e?cafe)(babe)+$",
|
||||
input = "X1024facefacecaaaaafffcafebabebabe",
|
||||
matches = true, ncaps = 6, start = 0, sb = 0,
|
||||
end = 34, eb = 34,
|
||||
content = "X1024facefacecaaaaafffcafebabebabe" },
|
||||
f5case { expr = ".(1024)?(face)*(1024)*ca*(f+e?cafe)(babe)+",
|
||||
input = "X1024facefacecaaaaafffcafebabebabe",
|
||||
matches = true, ncaps = 6, start = 0, sb = 0,
|
||||
end = 34, eb = 34,
|
||||
content = "X1024facefacecaaaaafffcafebabebabe" },
|
||||
f5case { expr = "^.(1024)?(face)*(1024)*ca*(f+e?cafe)(babe)+$",
|
||||
input = "1024facefacecaaaaafffcafebabebabe",
|
||||
matches = false, ... },
|
||||
f5case { expr = ".(1024)?(face)*(1024)*ca*(f+e?cafe)(babe)+",
|
||||
input = "1024facefacecaaaaafffcafebabebabe",
|
||||
matches = true, ncaps = 6, start = 3, sb = 3,
|
||||
end = 33, eb = 33,
|
||||
content = "4facefacecaaaaafffcafebabebabe" },
|
||||
// ww-added multibyte repeat row (B4)
|
||||
f5case { expr = "^(ä|b){2}x$", input = "äbx", matches = true,
|
||||
ncaps = 2, start = 0, sb = 0, end = 3, eb = 4,
|
||||
content = "äbx" },
|
||||
// ww-added (rob's rider): long-input {1,} — thread/counter
|
||||
// explosion stress under repeat spawns
|
||||
f5case { expr = "(a+|b){1,}", input = "aaaabbbbaaaabbbb",
|
||||
matches = true, ncaps = 2, start = 0, sb = 0,
|
||||
end = 16, eb = 16, content = "aaaabbbbaaaabbbb" },
|
||||
];
|
||||
let i: i32 = 0;
|
||||
for (i < len(rows)) {
|
||||
let ex: str = rows[i].expr;
|
||||
let inp: str = rows[i].input;
|
||||
let c: (regex.regex | regex.error | nomem) = regex.compile(ex);
|
||||
match (c) {
|
||||
case let re: regex.regex => {
|
||||
let fr: (regex.result | nomem) = regex.find(&re, inp);
|
||||
if (!(fr is regex.result)) { fail(); };
|
||||
let res: regex.result = fr as regex.result;
|
||||
if (rows[i].matches) {
|
||||
if ((len(res): i32) != rows[i].ncaps) { fail(); };
|
||||
if (res[0].start != rows[i].start) { fail(); };
|
||||
if (res[0].start_bytesize != rows[i].sb) {
|
||||
fail();
|
||||
};
|
||||
if (res[0].end != rows[i].end) { fail(); };
|
||||
if (res[0].end_bytesize != rows[i].eb) {
|
||||
fail();
|
||||
};
|
||||
let wc: str = rows[i].content;
|
||||
if (strings.compare(res[0].content, wc) != 0) {
|
||||
fail();
|
||||
};
|
||||
} else {
|
||||
if (len(res) != 0) { fail(); };
|
||||
};
|
||||
let tr: (bool | nomem) = regex.test(&re, inp);
|
||||
if (!(tr is bool)) { fail(); };
|
||||
if ((tr as bool) != (len(res) != 0)) { fail(); };
|
||||
regex.result_free(res);
|
||||
regex.finish(&re);
|
||||
};
|
||||
case => fail();
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
// findall × repeat composition (+test.ha:724 `fo{2,}`) — the greedy
|
||||
// per-position longest pick plus the non-overlap advance over a
|
||||
// repeat-counted program.
|
||||
@test fn fold5b_findall() void = {
|
||||
let targets: [4]str = ["foo", "fooo", "foo", "foo"];
|
||||
let rows: [1]facase = [
|
||||
facase { expr = "fo{2,}", input = "fo foo fooofoof oofoo",
|
||||
toff = 0, tcnt = 4 },
|
||||
];
|
||||
let i: i32 = 0;
|
||||
for (i < len(rows)) {
|
||||
let ex: str = rows[i].expr;
|
||||
let inp: str = rows[i].input;
|
||||
let c: (regex.regex | regex.error | nomem) = regex.compile(ex);
|
||||
match (c) {
|
||||
case let re: regex.regex => {
|
||||
let fr: ([]regex.result | nomem) =
|
||||
regex.findall(&re, inp);
|
||||
if (!(fr is []regex.result)) { fail(); };
|
||||
let results: []regex.result = fr as []regex.result;
|
||||
if (len(results) != rows[i].tcnt) { fail(); };
|
||||
let k: i32 = 0;
|
||||
for (k < rows[i].tcnt) {
|
||||
let want: str = targets[rows[i].toff + k];
|
||||
if (strings.compare(results[k][0].content,
|
||||
want) != 0) {
|
||||
fail();
|
||||
};
|
||||
k += 1;
|
||||
};
|
||||
regex.result_freeall(results);
|
||||
regex.finish(&re);
|
||||
};
|
||||
case => fail();
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; lit_and_match();
|
||||
signalled = 2; size_aliases_distinct();
|
||||
@@ -2231,7 +2437,6 @@ export fn main() i32 = {
|
||||
signalled = 7; compile_literal_program();
|
||||
signalled = 8; compile_any_program();
|
||||
signalled = 9; compile_empty_program();
|
||||
signalled = 10; compile_metachar_loud();
|
||||
signalled = 11; thread_shape();
|
||||
signalled = 12; newmatch_discriminates();
|
||||
signalled = 13; result_free_noop();
|
||||
@@ -2265,5 +2470,8 @@ export fn main() i32 = {
|
||||
signalled = 41; fold5_optional_group();
|
||||
signalled = 42; fold5_submatches();
|
||||
signalled = 43; parse_repetition_cases();
|
||||
signalled = 44; fold5b_compile_errors();
|
||||
signalled = 45; fold5b_find_cases();
|
||||
signalled = 46; fold5b_findall();
|
||||
return 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user