regex: fold 5a — capture groups (compile ( ) arms + run_thread groupstart/groupend + search spread)
compile: '(' (ha:317-323) appends inst_groupstart(capture_idx) and
grows jump_idxs per level; ')' (ha:324-334) appends the void
inst_groupend, fixes up the level's pending alternation jumps (#70
range + #58 assert), range-deletes them (#8) and closes the level;
the loop-exit done arm gains the Unmatched-'(' check (ha:277-282).
The anchors' group_level arms, the postfix inst_groupend/groupstart
arms and find_last_groupstart's success path go live unchanged.
run_thread: inst_groupstart (ha:636-652) fill-grows captures to
idx+1 (count-loop spelling of Hare's 3-arg fill-append) and opens
the group with the SIZE_MAX end sentinel via the #20-fixed indexed
struct store; inst_groupend (ha:653-668) closes the innermost
unclosed capture (ha:655's 2-clause for respelled — ww has no
cond;post form) and slices content from the bytesize span through
the addr-of-element pointer.
search: the ha:820 loud bound flips to the real capture spread
(#35/#25); the pad fill self-activates for unset trailing groups.
Tests: ( ) graduate from the metachar-loud table into real-text
error rows (+ ww-added anchor-in-group / Unused-on-groupstart
re-verify rows); hand-built groupstart/groupend arm cases; the 5a
find table (+test.ha:257-275 group/alternation, :499-503/:607 jump
bugs, :610-621 submatch family, :635/:640 alternation-group,
:649-665 nested minus the 5b {m,n} twins, + ww-added multibyte
row) with len(res) pinned per row; submatch content rows
(+test.ha:704-708 + ww-added multibyte) — the 5a acceptance gate.
This commit is contained in:
@@ -12,10 +12,12 @@
|
|||||||
// (jump_idxs state + find_last_groupstart/shift + the insert()
|
// (jump_idxs state + find_last_groupstart/shift + the insert()
|
||||||
// builtin) and the run_thread split/jump arms; fold 4 = bracket
|
// builtin) and the run_thread split/jump arms; fold 4 = bracket
|
||||||
// expressions `[..]` (handle_bracket + the run_thread charset arm —
|
// expressions `[..]` (handle_bracket + the run_thread charset arm —
|
||||||
// the POSIX `[[:class:]]` BODY stays loud behind charclass_map).
|
// the POSIX `[[:class:]]` BODY stays loud behind charclass_map);
|
||||||
// Remaining metacharacter arms (`(`/`)` groups, `{` repetition — and
|
// fold 5a = capture groups `(`/`)` (compile arms + run_thread
|
||||||
// replace) are DEFERRED — probed pre-port, pA*/pB*/PB*/PC*/PD*/PE*/
|
// groupstart/groupend + the add_thread capture dup + the search
|
||||||
// PF* probes. They land with their folds.
|
// 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.
|
||||||
//
|
//
|
||||||
// One fold-1 construct is held back behind a filed compiler/fidelity
|
// One fold-1 construct is held back behind a filed compiler/fidelity
|
||||||
// gap (see the charclass_map site below):
|
// gap (see the charclass_map site below):
|
||||||
@@ -142,11 +144,10 @@ export fn finish(re: *regex) void = {
|
|||||||
free(re.charsets);
|
free(re.charsets);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ref/hare/regex/regex.ha:104-119, verbatim. The error arm is ALWAYS
|
// ref/hare/regex/regex.ha:104-119, verbatim. The '|' arm consumes the
|
||||||
// taken until the group fold ('(' is loud, no inst_groupstart can
|
// error arm as origin = 0 (whole-expression alternation); the postfix
|
||||||
// exist); the '|' arm consumes it as origin = 0 (whole-expression
|
// `?`/`*`/`+` groupend arms propagate it. Match-on-indexed scrutinee
|
||||||
// alternation). Match-on-indexed scrutinee binds through a typed let
|
// binds through a typed let (the run_thread spelling).
|
||||||
// (the run_thread spelling).
|
|
||||||
fn find_last_groupstart(insts: []inst) (size | error) = {
|
fn find_last_groupstart(insts: []inst) (size | error) = {
|
||||||
let nested: uint = 0;
|
let nested: uint = 0;
|
||||||
for (let i: size = (len(insts): size); i > 0; i -= 1) {
|
for (let i: size = (len(insts): size); i > 0; i -= 1) {
|
||||||
@@ -290,17 +291,15 @@ fn handle_bracket(
|
|||||||
// (ha:286-293), anchors `^` (294-300) / `$` (301-312), alternation
|
// (ha:286-293), anchors `^` (294-300) / `$` (301-312), alternation
|
||||||
// `|` (335-367) over the jump_idxs state (241-248 subset) +
|
// `|` (335-367) over the jump_idxs state (241-248 subset) +
|
||||||
// whole-expression fixup (470-473), postfix `?` (403-420) / `*`
|
// whole-expression fixup (470-473), postfix `?` (403-420) / `*`
|
||||||
// (421-443) / `+` (444-459) — and the fold-4 bracket surface: the
|
// (421-443) / `+` (444-459) — the fold-4 bracket surface: the
|
||||||
// in_bracket dispatch (265-275), the `[` flip (313-314) and the
|
// in_bracket dispatch (265-275), the `[` flip (313-314) and the
|
||||||
// handle_bracket state quad (249-252). The remaining metacharacter
|
// handle_bracket state quad (249-252) — and the fold-5a group arms:
|
||||||
// arms (`(`/`)` groups, `{` repetition) are one loud not-yet-ported
|
// `(` (317-323), `)` (324-334), capture_idx (256) and the loop-exit
|
||||||
// error — the explicit fold boundary; falling to literal would be a
|
// `done` Unmatched-'(' check (277-282); the anchors' group_level
|
||||||
// silent semantic lie. group_level (ha:255) is
|
// arms and the postfix inst_groupend/groupstart arms went live with
|
||||||
// kept verbatim but only ever 0 until the group fold — the anchors'
|
// them. The remaining metacharacter arm (`{` repetition) is one loud
|
||||||
// group_level arms and the postfix inst_groupend/groupstart arms are
|
// not-yet-ported error — the explicit fold boundary; falling to
|
||||||
// dead-but-verbatim. capture_idx and the bracket quad stay dropped
|
// literal would be a silent semantic lie.
|
||||||
// with their arms; the loop-head `done` Unmatched-'(' check
|
|
||||||
// (ha:278-280) rides the '(' arm.
|
|
||||||
//
|
//
|
||||||
// Hare's `defer if (!ok) free(...)` cleanup (ha:231-237) is omitted:
|
// 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()
|
// ww has no `defer if` (cf lib/strings/strings.ww:85), and the free()
|
||||||
@@ -315,9 +314,9 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
let iter: strings.iterator = strings.iter(expr);
|
let iter: strings.iterator = strings.iter(expr);
|
||||||
let r_idx: size = 0;
|
let r_idx: size = 0;
|
||||||
// jump_idxs tracks the pending alternation jumps per group level;
|
// jump_idxs tracks the pending alternation jumps per group level;
|
||||||
// only level 0 can populate until the group fold. Hare's
|
// the '(' arm grows it past level 0. Hare's `append(jump_idxs,
|
||||||
// `append(jump_idxs, [])` (ha:242) spells through a typed empty
|
// [])` (ha:242) spells through a typed empty let (the #25/#31
|
||||||
// let (the #25/#31 ruling; cf the inst_skip let below).
|
// ruling; cf the inst_skip let below).
|
||||||
let jump_idxs: [][]size;
|
let jump_idxs: [][]size;
|
||||||
let lvl0: []size;
|
let lvl0: []size;
|
||||||
append(jump_idxs, lvl0);
|
append(jump_idxs, lvl0);
|
||||||
@@ -329,6 +328,7 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
let was_prev_rune_pipe: bool = false;
|
let was_prev_rune_pipe: bool = false;
|
||||||
let n_reps: size = 0;
|
let n_reps: size = 0;
|
||||||
let group_level: size = 0;
|
let group_level: size = 0;
|
||||||
|
let capture_idx: size = 0;
|
||||||
|
|
||||||
for (true) {
|
for (true) {
|
||||||
let next: (rune | utf8.done) = strings.next(&iter);
|
let next: (rune | utf8.done) = strings.next(&iter);
|
||||||
@@ -368,7 +368,12 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let r: rune = match (next) {
|
let r: rune = match (next) {
|
||||||
case utf8.done => break;
|
case utf8.done => { // regex.ha:277-282
|
||||||
|
if (group_level > 0) {
|
||||||
|
return "Unmatched '('": error;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
};
|
||||||
case let x: rune => yield x;
|
case let x: rune => yield x;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -406,8 +411,7 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
append(insts, (types.SIZE_MAX: inst_jump));
|
append(insts, (types.SIZE_MAX: inst_jump));
|
||||||
// origin = the instruction after the innermost
|
// origin = the instruction after the innermost
|
||||||
// groupstart, or 0 for whole-expression alternation
|
// groupstart, or 0 for whole-expression alternation
|
||||||
// (the error arm — always taken until the group
|
// (the error arm). Hare binds via a match EXPRESSION
|
||||||
// fold). Hare binds via a match EXPRESSION
|
|
||||||
// (ha:337-342); statement-match into a declared
|
// (ha:337-342); statement-match into a declared
|
||||||
// local, the search/scanrune precedent (#51).
|
// local, the search/scanrune precedent (#51).
|
||||||
let origin: size = 0;
|
let origin: size = 0;
|
||||||
@@ -468,7 +472,6 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
case inst_charset => void;
|
case inst_charset => void;
|
||||||
case inst_any => void;
|
case inst_any => void;
|
||||||
case inst_groupend => {
|
case inst_groupend => {
|
||||||
// dead until the group fold ('(' is loud).
|
|
||||||
// Hare propagates with `?` (ha:410-411);
|
// Hare propagates with `?` (ha:410-411);
|
||||||
// `?` into compile's >32B tagged return is
|
// `?` into compile's >32B tagged return is
|
||||||
// loud-stopped (#38b) — the explicit D13
|
// loud-stopped (#38b) — the explicit D13
|
||||||
@@ -502,7 +505,7 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
case inst_charset => void;
|
case inst_charset => void;
|
||||||
case inst_any => void;
|
case inst_any => void;
|
||||||
case inst_groupend => {
|
case inst_groupend => {
|
||||||
// dead until the group fold; D13 match, cf '?'
|
// D13 match, cf '?'
|
||||||
match (find_last_groupstart(
|
match (find_last_groupstart(
|
||||||
insts[0:term_start_idx])) {
|
insts[0:term_start_idx])) {
|
||||||
case let e: error => return e;
|
case let e: error => return e;
|
||||||
@@ -531,7 +534,7 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
case inst_charset => void;
|
case inst_charset => void;
|
||||||
case inst_any => void;
|
case inst_any => void;
|
||||||
case inst_groupend => {
|
case inst_groupend => {
|
||||||
// dead until the group fold; D13 match, cf '?'
|
// D13 match, cf '?'
|
||||||
match (find_last_groupstart(
|
match (find_last_groupstart(
|
||||||
insts[0:term_start_idx])) {
|
insts[0:term_start_idx])) {
|
||||||
case let e: error => return e;
|
case let e: error => return e;
|
||||||
@@ -554,9 +557,44 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
in_bracket = true;
|
in_bracket = true;
|
||||||
case ']': // regex.ha:315-316 — literal outside a bracket
|
case ']': // regex.ha:315-316 — literal outside a bracket
|
||||||
append(insts, (r: inst_lit));
|
append(insts, (r: inst_lit));
|
||||||
case '(', ')', '{':
|
case '(': { // regex.ha:317-323
|
||||||
// fold-4 boundary: the group (ha:317-334) and
|
append(insts, (capture_idx: inst_groupstart));
|
||||||
// repetition (368-401) arms ride later folds.
|
group_level += 1;
|
||||||
|
capture_idx += 1;
|
||||||
|
// Hare grows with `append(jump_idxs, [])?`
|
||||||
|
// (ha:321-323); the empty-slice literal spells
|
||||||
|
// through a typed let (the #25/#31 ruling, cf the
|
||||||
|
// lvl0 prologue).
|
||||||
|
for ((jump_idxs.len: size) < group_level + 1) {
|
||||||
|
let lvl: []size;
|
||||||
|
append(jump_idxs, lvl);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
case ')': { // regex.ha:324-334
|
||||||
|
if (group_level == 0) {
|
||||||
|
// VERBATIM duplicate of find_last_groupstart's
|
||||||
|
// text — Hare keeps two copies (ha:118/326).
|
||||||
|
return "Unmatched ')'": error;
|
||||||
|
};
|
||||||
|
// payload-less void variant through a typed let (the
|
||||||
|
// inst_skip spelling above).
|
||||||
|
let ge: inst_groupend;
|
||||||
|
let v: inst = ge;
|
||||||
|
append(insts, v);
|
||||||
|
// jump fixup (ha:329-332): by-value range over an
|
||||||
|
// INDEXED base is the #70-fixed shape; assert is the
|
||||||
|
// #58 builtin.
|
||||||
|
for (let jump_idx .. jump_idxs[group_level]) {
|
||||||
|
assert(insts[jump_idx] is inst_jump);
|
||||||
|
insts[jump_idx] =
|
||||||
|
(((insts.len: size) - 1): inst_jump);
|
||||||
|
};
|
||||||
|
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;
|
return "regex: metacharacter not yet ported": error;
|
||||||
case: // regex.ha:462-463
|
case: // regex.ha:462-463
|
||||||
append(insts, (r: inst_lit));
|
append(insts, (r: inst_lit));
|
||||||
@@ -650,10 +688,11 @@ fn add_thread(threads: *[]thread, parent_idx: size, new_pc: size) (void | nomem)
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ref/hare/regex/regex.ha:589-742. Only the arms compile() can emit
|
// ref/hare/regex/regex.ha:589-742. Only the arms compile() can emit
|
||||||
// execute (skip + split + jump + match non-consuming; lit + any +
|
// execute (skip + split + jump + match + groupstart + groupend
|
||||||
// charset consuming — split/jump went live with fold 3's `|`/`?`/`*`
|
// non-consuming; lit + any + charset consuming — split/jump went live
|
||||||
// arms, charset with fold 4's brackets); every other inst arm is one
|
// with fold 3's `|`/`?`/`*` arms, charset with fold 4's brackets,
|
||||||
// loud not-yet-ported abort — the fold boundary, the compile()
|
// 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
|
// metachar discipline. The "unreachable" aborts on lit/any inside
|
||||||
// the non-consuming loop (ha:604-605) and the trailing default
|
// the non-consuming loop (ha:604-605) and the trailing default
|
||||||
// (ha:738) are Hare's own unreachable arms; Hare spells them bare
|
// (ha:738) are Hare's own unreachable arms; Hare spells them bare
|
||||||
@@ -719,10 +758,54 @@ fn run_thread(
|
|||||||
let nm: newmatch;
|
let nm: newmatch;
|
||||||
return nm;
|
return nm;
|
||||||
};
|
};
|
||||||
case inst_groupstart =>
|
case let gs: inst_groupstart => { // regex.ha:636-652
|
||||||
abort("regex: inst_groupstart not yet ported");
|
let idx: size = (gs: size);
|
||||||
case inst_groupend =>
|
// ha:637-641: Hare's 3-arg fill-append `append(...,
|
||||||
abort("regex: inst_groupend not yet ported");
|
// [capture { ... }...], idx - len + 1)?` has no ww
|
||||||
|
// spelling — the ratified count-loop fill (cf the
|
||||||
|
// search epilogue's pad loop).
|
||||||
|
for (((*threads)[i].captures.len: size) < idx + 1) {
|
||||||
|
append((*threads)[i].captures, capture { ... });
|
||||||
|
};
|
||||||
|
assert((*threads)[i].captures[idx].end
|
||||||
|
!= types.SIZE_MAX);
|
||||||
|
(*threads)[i].captures[idx] = capture {
|
||||||
|
content = "",
|
||||||
|
start = str_idx,
|
||||||
|
start_bytesize = str_bytesize,
|
||||||
|
// end=types.SIZE_MAX indicates that the
|
||||||
|
// capture group hasn't ended yet
|
||||||
|
end = types.SIZE_MAX,
|
||||||
|
end_bytesize = types.SIZE_MAX,
|
||||||
|
};
|
||||||
|
(*threads)[i].pc += 1;
|
||||||
|
};
|
||||||
|
case inst_groupend => { // regex.ha:653-668
|
||||||
|
let curr_capture: size =
|
||||||
|
((*threads)[i].captures.len: size);
|
||||||
|
// ha:655's 2-clause `for (cond; post)` has no ww
|
||||||
|
// parse form (1- and 3-clause only) — the post-step
|
||||||
|
// moves to the body tail. Equivalent: break skips
|
||||||
|
// post in both, and the body has NO continue (which
|
||||||
|
// would run post in Hare but skip the inline tail).
|
||||||
|
for (curr_capture > 0) {
|
||||||
|
// find inner-most unclosed capture group
|
||||||
|
if ((*threads)[i].captures[curr_capture - 1].end
|
||||||
|
== types.SIZE_MAX) {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
curr_capture -= 1;
|
||||||
|
};
|
||||||
|
assert(curr_capture > 0, "Found a groupend token \")\" without having previously seen a groupstart token \"(\". Please report this as a bug");
|
||||||
|
// Hare's name shadows the capture TYPE — ww splits the
|
||||||
|
// type/value namespaces (#225), so it ports verbatim.
|
||||||
|
let capture = &(*threads)[i].captures[curr_capture - 1];
|
||||||
|
capture.end = str_idx;
|
||||||
|
capture.end_bytesize = str_bytesize;
|
||||||
|
capture.content = strings.frombytes(str_bytes[
|
||||||
|
capture.start_bytesize:capture.end_bytesize]);
|
||||||
|
(*threads)[i].pc += 1;
|
||||||
|
};
|
||||||
case inst_repeat =>
|
case inst_repeat =>
|
||||||
abort("regex: inst_repeat not yet ported");
|
abort("regex: inst_repeat not yet ported");
|
||||||
case => abort("regex: unreachable");
|
case => abort("regex: unreachable");
|
||||||
@@ -900,20 +983,13 @@ fn search(
|
|||||||
// #47); the capacity hint drops with per-value alloc.
|
// #47); the capacity hint drops with per-value alloc.
|
||||||
let res: []capture;
|
let res: []capture;
|
||||||
append(res, threads[best_idx].root_capture);
|
append(res, threads[best_idx].root_capture);
|
||||||
// ha:820 spreads threads[best_idx].captures into res.
|
// ha:820 — Hare's `static append` (capacity-bounded)
|
||||||
// The indexed spread source is #35-blocked, but
|
// is a plain append (D6, no static form); the indexed
|
||||||
// captures only populate via the loud-aborted
|
// spread source is the #35/#25-landed shape.
|
||||||
// groupstart arm or add_thread's loud-bounded dup —
|
append(res, threads[best_idx].captures...);
|
||||||
// provably empty in every program this fold can run.
|
|
||||||
// Loud-bound like add_thread's dup; the verbatim
|
|
||||||
// spread lands with the group fold.
|
|
||||||
if (threads[best_idx].captures.len != 0) {
|
|
||||||
abort("regex: capture copy not yet ported (#35)");
|
|
||||||
};
|
|
||||||
// ha:821-824's sized fill-append `[capture { ... }...]`
|
// ha:821-824's sized fill-append `[capture { ... }...]`
|
||||||
// has no ww spelling; the count loop is shape-correct
|
// has no ww spelling — the ratified count-loop fill
|
||||||
// and self-activates with the group fold (length stays
|
// pads the unset trailing groups.
|
||||||
// 1 until then).
|
|
||||||
for (length != (len(res): size)) {
|
for (length != (len(res): size)) {
|
||||||
append(res, capture { ... });
|
append(res, capture { ... });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import io;
|
|||||||
import memio;
|
import memio;
|
||||||
import os;
|
import os;
|
||||||
import strings;
|
import strings;
|
||||||
|
import types;
|
||||||
|
|
||||||
let signalled: i32 = 0;
|
let signalled: i32 = 0;
|
||||||
fn fail() void = { os.exit(signalled + 10); };
|
fn fail() void = { os.exit(signalled + 10); };
|
||||||
@@ -262,23 +263,18 @@ fn fail() void = { os.exit(signalled + 10); };
|
|||||||
// mean an arm was half-ported. One pattern per deferred arm so the
|
// 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
|
// fold that ports an arm consciously deletes its row. Fold 3 flipped
|
||||||
// \ ^ $ | ? * + positive (fold3_* below); fold 4 flipped `[`
|
// \ ^ $ | ? * + positive (fold3_* below); fold 4 flipped `[`
|
||||||
// (fold4_* below); the group/repetition three remain.
|
// (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 = {
|
@test fn compile_metachar_loud() void = {
|
||||||
let pats: [3]str = [
|
match (regex.compile("a{")) {
|
||||||
"a(", "a)", "a{",
|
case let e: regex.error => {
|
||||||
];
|
if (strings.compare((e: str),
|
||||||
let i: i32 = 0;
|
"regex: metacharacter not yet ported") != 0) {
|
||||||
for (i < len(pats)) {
|
fail();
|
||||||
match (regex.compile(pats[i])) {
|
|
||||||
case let e: regex.error => {
|
|
||||||
if (strings.compare((e: str),
|
|
||||||
"regex: metacharacter not yet ported") != 0) {
|
|
||||||
fail();
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
case => fail();
|
};
|
||||||
};
|
case => fail();
|
||||||
i += 1;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -422,7 +418,7 @@ type nmexp = struct {
|
|||||||
match (regex.compile("a(")) {
|
match (regex.compile("a(")) {
|
||||||
case let e: regex.error => {
|
case let e: regex.error => {
|
||||||
if (strings.compare(regex.strerror(e),
|
if (strings.compare(regex.strerror(e),
|
||||||
"regex: metacharacter not yet ported") != 0) {
|
"Unmatched '('") != 0) {
|
||||||
fail();
|
fail();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1760,6 +1756,387 @@ type cscase = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---- fold 5a: capture groups ------------------------------------------
|
||||||
|
|
||||||
|
// The fold-5a compile-error surface, exact texts. ")" and "(" are
|
||||||
|
// Hare's own ERROR fixtures (+test.ha:276/606); "a("/"a)" graduate
|
||||||
|
// here from the metachar-loud table with their real texts. The
|
||||||
|
// anchor-in-group and groupstart-postfix rows are ww-added (no Hare
|
||||||
|
// table row carries these texts): they pin that the fold-3
|
||||||
|
// verbatim-dead arms (regex.ha:295-297/302-304 anchors,
|
||||||
|
// 413-414/434-435/453-454 Unused-on-groupstart) FIRE now that `(`
|
||||||
|
// emits inst_groupstart — the §9a A0 re-verify, as live rows.
|
||||||
|
@test fn fold5_compile_errors() void = {
|
||||||
|
let rows: [9]cerow = [
|
||||||
|
cerow { pat = ")", want = "Unmatched ')'" },
|
||||||
|
cerow { pat = "(", want = "Unmatched '('" },
|
||||||
|
cerow { pat = "a)", want = "Unmatched ')'" },
|
||||||
|
cerow { pat = "a(", want = "Unmatched '('" },
|
||||||
|
// ww-added: anchor-in-group arms (regex.ha:295-297/302-304)
|
||||||
|
cerow { pat = "(^a)",
|
||||||
|
want = "Anchor '^' in capture groups is unsupported" },
|
||||||
|
cerow { pat = "(a$)",
|
||||||
|
want = "Anchor '$' in capture groups is unsupported" },
|
||||||
|
// ww-added: postfix on a bare groupstart
|
||||||
|
// (regex.ha:413-414/434-435/453-454)
|
||||||
|
cerow { pat = "(?", want = "Unused '?'" },
|
||||||
|
cerow { pat = "(*", want = "Unused '*'" },
|
||||||
|
cerow { pat = "(+", want = "Unused '+'" },
|
||||||
|
];
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// run_thread inst_groupstart / inst_groupend driven over HAND-BUILT
|
||||||
|
// programs (the anchored-route precedent): compile() composition is
|
||||||
|
// pinned by the find/submatch tables below; these pin the arm
|
||||||
|
// mechanics — fill-grow to idx+1, the SIZE_MAX open sentinel,
|
||||||
|
// innermost-unclosed close order, content from the bytesize span,
|
||||||
|
// and the closed-group re-entry overwrite (the ha:642 assert's
|
||||||
|
// PASSING direction).
|
||||||
|
@test fn run_thread_group_arms() void = {
|
||||||
|
// groupstart (ha:636-652): grows captures to idx+1 (zero-filled
|
||||||
|
// below idx), stamps start/start_bytesize, opens with
|
||||||
|
// end = end_bytesize = SIZE_MAX
|
||||||
|
let insts: []regex.inst = [];
|
||||||
|
append(insts, ((1: size): regex.inst_groupstart));
|
||||||
|
append(insts, ('a': regex.inst_lit));
|
||||||
|
append(insts, (false: regex.inst_match));
|
||||||
|
let re: regex.regex;
|
||||||
|
re.insts = insts;
|
||||||
|
re.n_reps = 0;
|
||||||
|
let ra: (rune | io.eof) = 'a';
|
||||||
|
let ts: []thread = [];
|
||||||
|
append(ts, thread { pc = 0, ... });
|
||||||
|
let r1: (void | newmatch | nomem) = run_thread(0, &re, "ab", &ts, ra, 2, 3);
|
||||||
|
if (!(r1 is void)) { fail(); };
|
||||||
|
if (ts[0].captures.len != 2) { fail(); };
|
||||||
|
// the fill element below idx is zeroed
|
||||||
|
if (ts[0].captures[0].end != (0: size)) { fail(); };
|
||||||
|
if (ts[0].captures[0].content.len != 0) { fail(); };
|
||||||
|
// the opened group: start stamped, end still the open sentinel
|
||||||
|
if (ts[0].captures[1].start != (2: size)) { fail(); };
|
||||||
|
if (ts[0].captures[1].start_bytesize != (3: size)) { fail(); };
|
||||||
|
if (ts[0].captures[1].end != types.SIZE_MAX) { fail(); };
|
||||||
|
if (ts[0].captures[1].end_bytesize != types.SIZE_MAX) { fail(); };
|
||||||
|
// groupstart is non-consuming: pc stepped through it, then the
|
||||||
|
// lit consumed
|
||||||
|
if (ts[0].pc != (2: size)) { fail(); };
|
||||||
|
|
||||||
|
// groupend (ha:653-668): two open groups — the INNERMOST
|
||||||
|
// (highest index) closes first; back-to-back groupends close
|
||||||
|
// inner then outer in ONE call; content = str_bytes[
|
||||||
|
// start_bytesize:end_bytesize]
|
||||||
|
let insts2: []regex.inst = [];
|
||||||
|
let gv: regex.inst_groupend;
|
||||||
|
let ge: regex.inst = gv;
|
||||||
|
append(insts2, ge);
|
||||||
|
append(insts2, ge);
|
||||||
|
append(insts2, ('x': regex.inst_lit));
|
||||||
|
append(insts2, (false: regex.inst_match));
|
||||||
|
let re2: regex.regex;
|
||||||
|
re2.insts = insts2;
|
||||||
|
re2.n_reps = 0;
|
||||||
|
let caps: []capture = [];
|
||||||
|
append(caps, capture { content = "", start = 1, start_bytesize = 1,
|
||||||
|
end = types.SIZE_MAX, end_bytesize = types.SIZE_MAX });
|
||||||
|
append(caps, capture { content = "", start = 2, start_bytesize = 2,
|
||||||
|
end = types.SIZE_MAX, end_bytesize = types.SIZE_MAX });
|
||||||
|
let ts2: []thread = [];
|
||||||
|
append(ts2, thread { pc = 0, captures = caps, ... });
|
||||||
|
let rx: (rune | io.eof) = 'x';
|
||||||
|
let r2: (void | newmatch | nomem) = run_thread(0, &re2, "abcd", &ts2, rx, 3, 4);
|
||||||
|
if (!(r2 is void)) { fail(); };
|
||||||
|
if (ts2[0].captures[1].end != (3: size)) { fail(); };
|
||||||
|
if (ts2[0].captures[1].end_bytesize != (4: size)) { fail(); };
|
||||||
|
if (strings.compare(ts2[0].captures[1].content, "cd") != 0) { fail(); };
|
||||||
|
if (ts2[0].captures[0].end != (3: size)) { fail(); };
|
||||||
|
if (ts2[0].captures[0].end_bytesize != (4: size)) { fail(); };
|
||||||
|
if (strings.compare(ts2[0].captures[0].content, "bcd") != 0) { fail(); };
|
||||||
|
if (ts2[0].pc != (3: size)) { fail(); };
|
||||||
|
|
||||||
|
// closed-group re-entry: groupstart over an already-CLOSED idx
|
||||||
|
// passes the ha:642 assert (end != SIZE_MAX) and re-opens fresh
|
||||||
|
let insts3: []regex.inst = [];
|
||||||
|
append(insts3, ((0: size): regex.inst_groupstart));
|
||||||
|
append(insts3, ('a': regex.inst_lit));
|
||||||
|
append(insts3, (false: regex.inst_match));
|
||||||
|
let re3: regex.regex;
|
||||||
|
re3.insts = insts3;
|
||||||
|
re3.n_reps = 0;
|
||||||
|
let caps3: []capture = [];
|
||||||
|
append(caps3, capture { content = "ab", start = 0, start_bytesize = 0,
|
||||||
|
end = 2, end_bytesize = 2 });
|
||||||
|
let ts3: []thread = [];
|
||||||
|
append(ts3, thread { pc = 0, captures = caps3, ... });
|
||||||
|
let r3: (void | newmatch | nomem) = run_thread(0, &re3, "aba", &ts3, ra, 2, 2);
|
||||||
|
if (!(r3 is void)) { fail(); };
|
||||||
|
if (ts3[0].captures.len != 1) { fail(); };
|
||||||
|
if (ts3[0].captures[0].start != (2: size)) { fail(); };
|
||||||
|
if (ts3[0].captures[0].end != types.SIZE_MAX) { fail(); };
|
||||||
|
if (ts3[0].captures[0].content.len != 0) { fail(); };
|
||||||
|
};
|
||||||
|
|
||||||
|
// fold-5a find/test rows — the group rows of Hare's own table:
|
||||||
|
// group/alternation +test.ha:257-275, the jump-bug group rows
|
||||||
|
// :499-503 minus the `{,1}` form (5b) plus `(x?)?` :607, the
|
||||||
|
// POSIX-comment submatch-handling family :610-621 (MATCH-only root
|
||||||
|
// assertions, as Hare; the literally-duplicated (a*) pairs :614-617
|
||||||
|
// appear once), `a|(b)` :635, `(a|b|c|d|e)f` :640, and the
|
||||||
|
// nested-group block :649-665 minus the `{0,}`/`{1,}`/`{0,1}` twins
|
||||||
|
// (5b) and Hare's own TODO-disabled anchor-in-group rows. end == -1
|
||||||
|
// resolves to rune length (+test.ha:693-697). ncaps additionally pins
|
||||||
|
// len(res) = last-groupstart payload + 2 (the search length scan +
|
||||||
|
// pad fill — unset groups pad to zeroed captures, so `a|(b)` over "a"
|
||||||
|
// still yields 2). The multibyte row is ww-added (B4: every idx
|
||||||
|
// splits from its bytesize). `(a+|b)*` over "ab" is rob's
|
||||||
|
// thread-explosion stress row (group split × star respawn ×
|
||||||
|
// dedup/trim/leftmost pins). Cross-pins test() == (find() matched).
|
||||||
|
type f5case = struct {
|
||||||
|
expr: str,
|
||||||
|
input: str,
|
||||||
|
matches: bool,
|
||||||
|
ncaps: i32,
|
||||||
|
start: size,
|
||||||
|
sb: size,
|
||||||
|
end: size,
|
||||||
|
eb: size,
|
||||||
|
content: str,
|
||||||
|
};
|
||||||
|
|
||||||
|
@test fn fold5_find_cases() void = {
|
||||||
|
let rows: [32]f5case = [
|
||||||
|
// group/alternation (+test.ha:257-275)
|
||||||
|
f5case { expr = "^(cafe|b)x$", input = "cafex", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 5, eb = 5,
|
||||||
|
content = "cafex" },
|
||||||
|
f5case { expr = "^(cafe|b)x$", input = "bx", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 2, eb = 2,
|
||||||
|
content = "bx" },
|
||||||
|
f5case { expr = "^(cafe|b)x$", input = "XXXx",
|
||||||
|
matches = false, ... },
|
||||||
|
f5case { expr = "^(Privat|Jagd)(haftpflicht|schaden)versicherungs(police|betrag)$",
|
||||||
|
input = "Jagdhaftpflichtversicherungsbetrag",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 34, eb = 34,
|
||||||
|
content = "Jagdhaftpflichtversicherungsbetrag" },
|
||||||
|
f5case { expr = "^(Privat|Jagd)(haftpflicht|schaden)versicherungs(police|betrag)$",
|
||||||
|
input = "Jagdhaftpflichtversicherungsbetrug",
|
||||||
|
matches = false, ... },
|
||||||
|
f5case { expr = "^(Privat|Jagd)(haftpflicht|schaden)versicherungs(police|betrag)$",
|
||||||
|
input = "Jagdversicherungspolice",
|
||||||
|
matches = false, ... },
|
||||||
|
// jump bugs (+test.ha:499-503 minus `{,1}`; :607)
|
||||||
|
f5case { expr = "ab?c", input = "ac", matches = true,
|
||||||
|
ncaps = 1, start = 0, sb = 0, end = 2, eb = 2,
|
||||||
|
content = "ac" },
|
||||||
|
f5case { expr = "ab?c|z", input = "ac", matches = true,
|
||||||
|
ncaps = 1, start = 0, sb = 0, end = 2, eb = 2,
|
||||||
|
content = "ac" },
|
||||||
|
f5case { expr = "(ab?c)?", input = "ac", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 2, eb = 2,
|
||||||
|
content = "ac" },
|
||||||
|
f5case { expr = "(ab?c)*", input = "ac", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 2, eb = 2,
|
||||||
|
content = "ac" },
|
||||||
|
f5case { expr = "(x?)?", input = "x", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 1, eb = 1,
|
||||||
|
content = "x" },
|
||||||
|
// submatch handling (+test.ha:610-621) — MATCH-only root
|
||||||
|
// assertions, as Hare (POSIX submatch semantics diverge)
|
||||||
|
f5case { expr = "(a|ab)(c|bcd)(d*)", input = "abcd",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 4, eb = 4, content = "abcd" },
|
||||||
|
f5case { expr = "(a|ab)(bcd|c)(d*)", input = "abcd",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 4, eb = 4, content = "abcd" },
|
||||||
|
f5case { expr = "(ab|a)(c|bcd)(d*)", input = "abcd",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 4, eb = 4, content = "abcd" },
|
||||||
|
f5case { expr = "(ab|a)(bcd|c)(d*)", input = "abcd",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 4, eb = 4, content = "abcd" },
|
||||||
|
f5case { expr = "(a*)(b|abc)(c*)", input = "abc",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 3, eb = 3, content = "abc" },
|
||||||
|
f5case { expr = "(a*)(abc|b)(c*)", input = "abc",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 3, eb = 3, content = "abc" },
|
||||||
|
f5case { expr = "(a|ab)(c|bcd)(d|.*)", input = "abcd",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 4, eb = 4, content = "abcd" },
|
||||||
|
f5case { expr = "(a|ab)(bcd|c)(d|.*)", input = "abcd",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 4, eb = 4, content = "abcd" },
|
||||||
|
f5case { expr = "(ab|a)(c|bcd)(d|.*)", input = "abcd",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 4, eb = 4, content = "abcd" },
|
||||||
|
f5case { expr = "(ab|a)(bcd|c)(d|.*)", input = "abcd",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 4, eb = 4, content = "abcd" },
|
||||||
|
// alternation with a group (+test.ha:635) — the (b) branch
|
||||||
|
// never runs on "a"; the pad fill still yields 2 captures
|
||||||
|
f5case { expr = "a|(b)", input = "a", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 1, eb = 1,
|
||||||
|
content = "a" },
|
||||||
|
// multiple alternation inside a group (+test.ha:640)
|
||||||
|
f5case { expr = "(a|b|c|d|e)f", input = "ef", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 2, eb = 2,
|
||||||
|
content = "ef" },
|
||||||
|
// nested groups (+test.ha:649-665 minus the `{…}` twins)
|
||||||
|
f5case { expr = "((a))", input = "abc", matches = true,
|
||||||
|
ncaps = 3, start = 0, sb = 0, end = 1, eb = 1,
|
||||||
|
content = "a" },
|
||||||
|
f5case { expr = "((a)(b)c)(d)", input = "abcd", matches = true,
|
||||||
|
ncaps = 5, start = 0, sb = 0, end = 4, eb = 4,
|
||||||
|
content = "abcd" },
|
||||||
|
f5case { expr = "((((((((((a))))))))))", input = "a",
|
||||||
|
matches = true, ncaps = 11, start = 0, sb = 0,
|
||||||
|
end = 1, eb = 1, content = "a" },
|
||||||
|
f5case { expr = "(((((((((a)))))))))", input = "a",
|
||||||
|
matches = true, ncaps = 10, start = 0, sb = 0,
|
||||||
|
end = 1, eb = 1, content = "a" },
|
||||||
|
f5case { expr = "(([a-z]+):)?([a-z]+)$", input = "smil",
|
||||||
|
matches = true, ncaps = 4, start = 0, sb = 0,
|
||||||
|
end = 4, eb = 4, content = "smil" },
|
||||||
|
f5case { expr = "^((a)c)?(ab)$", input = "ab", matches = true,
|
||||||
|
ncaps = 4, start = 0, sb = 0, end = 2, eb = 2,
|
||||||
|
content = "ab" },
|
||||||
|
f5case { expr = "(a+|b)*", input = "ab", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 2, eb = 2,
|
||||||
|
content = "ab" },
|
||||||
|
f5case { expr = "(a+|b)+", input = "ab", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 2, eb = 2,
|
||||||
|
content = "ab" },
|
||||||
|
// ww-added multibyte group row (B4)
|
||||||
|
f5case { expr = "(ä|b)x", input = "äx", matches = true,
|
||||||
|
ncaps = 2, start = 0, sb = 0, end = 2, eb = 3,
|
||||||
|
content = "äx" },
|
||||||
|
];
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// `(a+|b)?` over "ab" (+test.ha:665) matches (0,1) "a" — the
|
||||||
|
// non-greedy END pins that the optional group stops at the leftmost-
|
||||||
|
// longest SINGLE term, not the star/plus whole-string sweep above.
|
||||||
|
@test fn fold5_optional_group() void = {
|
||||||
|
let c: (regex.regex | regex.error | nomem) = regex.compile("(a+|b)?");
|
||||||
|
match (c) {
|
||||||
|
case let re: regex.regex => {
|
||||||
|
let fr: (regex.result | nomem) = regex.find(&re, "ab");
|
||||||
|
if (!(fr is regex.result)) { fail(); };
|
||||||
|
let res: regex.result = fr as regex.result;
|
||||||
|
if (len(res) != 2) { fail(); };
|
||||||
|
if (res[0].start != (0: size)) { fail(); };
|
||||||
|
if (res[0].end != (1: size)) { fail(); };
|
||||||
|
if (strings.compare(res[0].content, "a") != 0) { fail(); };
|
||||||
|
regex.result_free(res);
|
||||||
|
regex.finish(&re);
|
||||||
|
};
|
||||||
|
case => fail();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// submatch rows (+test.ha:704-708 via run_submatch_case :72-100) —
|
||||||
|
// THE 5a acceptance gate: per-group .content equality through find(),
|
||||||
|
// root first. The second row is ww-added (B4): a 2-byte ß inside both
|
||||||
|
// captured groups splits every byte offset the contents are sliced
|
||||||
|
// from. Targets live in a flat pool indexed by (toff, tcnt), the
|
||||||
|
// findall_content shape.
|
||||||
|
type smcase = struct {
|
||||||
|
expr: str,
|
||||||
|
input: str,
|
||||||
|
toff: i32,
|
||||||
|
tcnt: i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
@test fn fold5_submatches() void = {
|
||||||
|
let targets: [6]str = [
|
||||||
|
"aaa bbb ccc", "bbb", "ccc",
|
||||||
|
"aaa bßb cßc", "bßb", "cßc",
|
||||||
|
];
|
||||||
|
let rows: [2]smcase = [
|
||||||
|
smcase { expr = "aaa ([^ ]*) (...)", input = "aaa bbb ccc",
|
||||||
|
toff = 0, tcnt = 3 },
|
||||||
|
// ww-added multibyte variant
|
||||||
|
smcase { expr = "aaa ([^ ]*) (...)", input = "aaa bßb cßc",
|
||||||
|
toff = 3, tcnt = 3 },
|
||||||
|
];
|
||||||
|
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 ((len(res): i32) != rows[i].tcnt) { fail(); };
|
||||||
|
let k: i32 = 0;
|
||||||
|
for (k < rows[i].tcnt) {
|
||||||
|
let want: str = targets[rows[i].toff + k];
|
||||||
|
if (strings.compare(res[k].content,
|
||||||
|
want) != 0) {
|
||||||
|
fail();
|
||||||
|
};
|
||||||
|
k += 1;
|
||||||
|
};
|
||||||
|
regex.result_free(res);
|
||||||
|
regex.finish(&re);
|
||||||
|
};
|
||||||
|
case => 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();
|
||||||
@@ -1798,5 +2175,10 @@ export fn main() i32 = {
|
|||||||
signalled = 35; fold4_find_cases();
|
signalled = 35; fold4_find_cases();
|
||||||
signalled = 36; fold4_findall();
|
signalled = 36; fold4_findall();
|
||||||
signalled = 37; add_thread_dup_independence();
|
signalled = 37; add_thread_dup_independence();
|
||||||
|
signalled = 38; fold5_compile_errors();
|
||||||
|
signalled = 39; run_thread_group_arms();
|
||||||
|
signalled = 40; fold5_find_cases();
|
||||||
|
signalled = 41; fold5_optional_group();
|
||||||
|
signalled = 42; fold5_submatches();
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user