regex: fold 4 — bracket expressions (handle_bracket + run_thread charset arm)
Port of ref/hare/regex/regex.ha:135-225 (handle_bracket, whole),
265-275 (in_bracket dispatch), 313-314 (the `[` flip), 249-252 (the
bracket state quad) and 704-737 (the consuming charset arm). `[`
graduates from the fold-2a loud set; `(` `)` `{` are the last
three loud metachars. The POSIX-class arm keeps its DETECTION
verbatim but loud-aborts its BODY (charclass_map stays #25-blocked;
falling through to the literal arm would silently compile
[[:alpha:]] as a 9-literal charset). is_consuming_inst already
covered inst_charset.
Spelling divergences, all site-documented: the dispatch propagates
via the explicit D13 match, not `?` (compile's 64B sret return is
the #38b loud-stop; the fold-3 find_last_groupstart precedent);
charset's declaration moves BELOW its member types (cstage sizes a
tagged alias with forward-declared members at a degenerate 8B —
ww-core #69, wwstage is correct); run_thread binds the charset
structurally, not via the alias (alias-typed slice locals mis-scale
their index reads in wwstage — ww-core #68).
Tests: Hare's own bracket block (+test.ha:278-345, the group and
POSIX rows excluded with their loud arms) as the 72-row find/test
table incl. multibyte literal+range brackets and an unanchored
[ab]+ composition row; charsets-table content pins (lit/range
discrimination, first-char ]/[ literals, literal dashes, multibyte
codepoints); program-shape pins ([abc] / ^[abc]$ / [^ab] /
[ab][cd] / [abc]*); exact-text error rows (Unmatched '[' ×3 incl
the escape interaction, descending [z-a]); findall composition.
The [[:alpha:]] abort text is unpinnable in-process (it kills the
runner) — source-audited until the POSIX fold.
This commit is contained in:
@@ -10,10 +10,12 @@
|
|||||||
// findall/result_freeall over the memio seeker; fold 3 = anchors
|
// findall/result_freeall over the memio seeker; fold 3 = anchors
|
||||||
// `^`/`$`, the `\` escape, postfix `?`/`*`/`+`, alternation `|`
|
// `^`/`$`, the `\` escape, postfix `?`/`*`/`+`, alternation `|`
|
||||||
// (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. Remaining
|
// builtin) and the run_thread split/jump arms; fold 4 = bracket
|
||||||
// metacharacter arms (`[` bracket, `(`/`)` groups, `{` repetition —
|
// expressions `[..]` (handle_bracket + the run_thread charset arm —
|
||||||
// and replace) are DEFERRED — probed pre-port, pA*/pB*/PB*/PC*/PD*/
|
// the POSIX `[[:class:]]` BODY stays loud behind charclass_map).
|
||||||
// PE* probes. They land with their folds.
|
// Remaining metacharacter arms (`(`/`)` groups, `{` repetition — and
|
||||||
|
// replace) are DEFERRED — probed pre-port, pA*/pB*/PB*/PC*/PD*/PE*/
|
||||||
|
// PF* 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):
|
||||||
@@ -93,12 +95,17 @@ type thread = struct {
|
|||||||
// boundary. ref/hare/regex/regex.ha:66.
|
// boundary. ref/hare/regex/regex.ha:66.
|
||||||
type newmatch = void;
|
type newmatch = void;
|
||||||
|
|
||||||
// ref/hare/regex/regex.ha:68-72.
|
// ref/hare/regex/regex.ha:68-72. Declaration ORDER diverges from Hare
|
||||||
export type charset = [](charset_lit_item | charset_range_item |
|
// (which declares charset first): a cstage type-table bug leaves a
|
||||||
charset_class_item);
|
// tagged alias whose member types are forward-declared with a
|
||||||
|
// degenerate 8-byte tinfo — silent payload truncation (filed, ww-core
|
||||||
|
// #69; wwstage resolves the forward refs correctly). Members first
|
||||||
|
// until #69 lands.
|
||||||
export type charset_lit_item = rune;
|
export type charset_lit_item = rune;
|
||||||
export type charset_range_item = (u32, u32);
|
export type charset_range_item = (u32, u32);
|
||||||
export type charset_class_item = (str, *fn(c: rune) bool);
|
export type charset_class_item = (str, *fn(c: rune) bool);
|
||||||
|
export type charset = [](charset_lit_item | charset_range_item |
|
||||||
|
charset_class_item);
|
||||||
|
|
||||||
// ref/hare/regex/regex.ha:74-87 — charclass_map: the const
|
// ref/hare/regex/regex.ha:74-87 — charclass_map: the const
|
||||||
// [](str, *fn(rune) bool) table mapping POSIX class tokens to the
|
// [](str, *fn(rune) bool) table mapping POSIX class tokens to the
|
||||||
@@ -179,16 +186,116 @@ fn shift(sl: []inst) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handles a rune inside a bracket expression, mutating the in-flight
|
||||||
|
// charset / bracket state through the pointer params.
|
||||||
|
//
|
||||||
|
// ref/hare/regex/regex.ha:135-225, whole except the POSIX-class arm
|
||||||
|
// BODY: its DETECTION (`[` + `:` peek) is verbatim, but the
|
||||||
|
// charclass_map scan it guards is loud-aborted — the map itself is
|
||||||
|
// blocked behind the array→slice element-coercion gap (#25; see the
|
||||||
|
// charclass_map note above) and falling through to the literal arm
|
||||||
|
// would silently compile `[[:alpha:]]` as a 9-literal charset. The
|
||||||
|
// skip_charclass_rest block (ha:164-170) is verbatim-dead until then:
|
||||||
|
// only the loud arm sets it; it self-activates with the POSIX fold.
|
||||||
|
// Hare's `append(charsets, [])?` / `append(...)?` nomem propagation
|
||||||
|
// drops as usual (#36, ww append returns void); the discarded
|
||||||
|
// `strings::next` advances (ha:214-215) bind to throwaway lets — a
|
||||||
|
// bare call statement of a tagged-returning fn is an unprobed shape.
|
||||||
|
fn handle_bracket(
|
||||||
|
insts: *[]inst,
|
||||||
|
r: rune,
|
||||||
|
r_idx: *size,
|
||||||
|
bracket_idx: *int,
|
||||||
|
iter: *strings.iterator,
|
||||||
|
charsets: *[]charset,
|
||||||
|
skip_charclass_rest: *bool,
|
||||||
|
is_charset_positive: *bool,
|
||||||
|
in_bracket: *bool,
|
||||||
|
) (void | error | nomem) = {
|
||||||
|
let peek1: (rune | utf8.done) = strings.next(iter);
|
||||||
|
let peek2: (rune | utf8.done) = strings.next(iter);
|
||||||
|
let peek3: (rune | utf8.done) = strings.next(iter);
|
||||||
|
if (!(peek1 is utf8.done)) {
|
||||||
|
strings.prev(iter);
|
||||||
|
};
|
||||||
|
if (!(peek2 is utf8.done)) {
|
||||||
|
strings.prev(iter);
|
||||||
|
};
|
||||||
|
if (!(peek3 is utf8.done)) {
|
||||||
|
strings.prev(iter);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (*bracket_idx == -1) {
|
||||||
|
// Hare `append(charsets, [])?` (ha:160) — the empty slice
|
||||||
|
// literal spells through a bare typed let (#25/#31 ruling).
|
||||||
|
let empty: charset;
|
||||||
|
append(*charsets, empty);
|
||||||
|
};
|
||||||
|
*bracket_idx += 1;
|
||||||
|
|
||||||
|
if (*skip_charclass_rest) {
|
||||||
|
if (r == ']') {
|
||||||
|
*skip_charclass_rest = false;
|
||||||
|
};
|
||||||
|
*r_idx += 1;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_range: bool = peek1 is rune && (peek1 as rune) == '-'
|
||||||
|
&& !(peek2 is utf8.done) && !(peek3 is utf8.done)
|
||||||
|
&& !((peek2 as rune) == ']');
|
||||||
|
let range_end: (rune | utf8.done) = peek2;
|
||||||
|
let is_first_char: bool = *bracket_idx == 0 || *bracket_idx == 1
|
||||||
|
&& !*is_charset_positive;
|
||||||
|
|
||||||
|
if (r == ']' && !is_first_char) { // regex.ha:179-187
|
||||||
|
let newinst: inst = inst_charset {
|
||||||
|
idx = (len(*charsets): size) - 1,
|
||||||
|
is_positive = *is_charset_positive,
|
||||||
|
};
|
||||||
|
append(*insts, newinst);
|
||||||
|
*in_bracket = false;
|
||||||
|
*bracket_idx = -1;
|
||||||
|
*is_charset_positive = true;
|
||||||
|
} else if (r == '^' && *bracket_idx == 0) { // regex.ha:188-189
|
||||||
|
*is_charset_positive = false;
|
||||||
|
} else if (r == '[' && !(peek1 is utf8.done)
|
||||||
|
&& (peek1 as rune) == ':') { // regex.ha:190-204
|
||||||
|
abort("regex: POSIX character class not yet ported");
|
||||||
|
} else if (is_range) { // regex.ha:205-217
|
||||||
|
let start_b: u32 = (r: u32);
|
||||||
|
let end_b: u32 = ((range_end as rune): u32);
|
||||||
|
|
||||||
|
if (end_b < start_b) {
|
||||||
|
return "Descending bracket expression range '[z-a]'": error;
|
||||||
|
};
|
||||||
|
|
||||||
|
append((*charsets)[len(*charsets) - 1],
|
||||||
|
((start_b, end_b): charset_range_item));
|
||||||
|
let skip1: (rune | utf8.done) = strings.next(iter);
|
||||||
|
let skip2: (rune | utf8.done) = strings.next(iter);
|
||||||
|
*r_idx += 2;
|
||||||
|
} else { // regex.ha:218-221
|
||||||
|
append((*charsets)[len(*charsets) - 1],
|
||||||
|
(r: charset_lit_item));
|
||||||
|
};
|
||||||
|
|
||||||
|
*r_idx += 1;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
// Compiles a regular expression string into a [[regex]].
|
// Compiles a regular expression string into a [[regex]].
|
||||||
//
|
//
|
||||||
// ref/hare/regex/regex.ha:227-263 + the fold-3 arms: `\` escape
|
// ref/hare/regex/regex.ha:227-263 + the fold-3 arms: `\` escape
|
||||||
// (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). The remaining metacharacter arms (`[`
|
// (421-443) / `+` (444-459) — and the fold-4 bracket surface: the
|
||||||
// bracket, `(`/`)` groups, `{` repetition) are one loud
|
// in_bracket dispatch (265-275), the `[` flip (313-314) and the
|
||||||
// not-yet-ported error — the explicit fold boundary; falling to
|
// handle_bracket state quad (249-252). The remaining metacharacter
|
||||||
// literal would be a silent semantic lie. group_level (ha:255) is
|
// arms (`(`/`)` groups, `{` repetition) are one loud not-yet-ported
|
||||||
|
// error — the explicit fold boundary; falling to literal would be a
|
||||||
|
// silent semantic lie. group_level (ha:255) is
|
||||||
// kept verbatim but only ever 0 until the group fold — the anchors'
|
// kept verbatim but only ever 0 until the group fold — the anchors'
|
||||||
// group_level arms and the postfix inst_groupend/groupstart arms are
|
// group_level arms and the postfix inst_groupend/groupstart arms are
|
||||||
// dead-but-verbatim. capture_idx and the bracket quad stay dropped
|
// dead-but-verbatim. capture_idx and the bracket quad stay dropped
|
||||||
@@ -204,7 +311,7 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
// zeroes the header (cgen.c:9836 no-rhs multi-word composite
|
// zeroes the header (cgen.c:9836 no-rhs multi-word composite
|
||||||
// zero-fill, symmetric in cgenstmt.ww).
|
// zero-fill, symmetric in cgenstmt.ww).
|
||||||
let insts: []inst;
|
let insts: []inst;
|
||||||
let charsets: []charset; // stays empty until the '[' fold
|
let charsets: []charset;
|
||||||
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;
|
||||||
@@ -214,6 +321,11 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
let jump_idxs: [][]size;
|
let jump_idxs: [][]size;
|
||||||
let lvl0: []size;
|
let lvl0: []size;
|
||||||
append(jump_idxs, lvl0);
|
append(jump_idxs, lvl0);
|
||||||
|
// bracket-expression state (regex.ha:249-252).
|
||||||
|
let in_bracket: bool = false;
|
||||||
|
let skip_charclass_rest: bool = false;
|
||||||
|
let bracket_idx: int = -1;
|
||||||
|
let is_charset_positive: bool = true;
|
||||||
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;
|
||||||
@@ -233,6 +345,28 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
append(insts, v);
|
append(insts, v);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (in_bracket) { // regex.ha:265-275
|
||||||
|
if (next is utf8.done) {
|
||||||
|
return "Unmatched '['": error;
|
||||||
|
};
|
||||||
|
// Hare propagates with `?` (ha:271-274); `?` into
|
||||||
|
// compile's >32B tagged return is loud-stopped (#38b)
|
||||||
|
// — the explicit D13 match, harec's own desugaring
|
||||||
|
// (ref/harec/src/check.c:2780), the fold-3
|
||||||
|
// find_last_groupstart-arm precedent. The continue
|
||||||
|
// skips the loop tail — handle_bracket owns r_idx
|
||||||
|
// inside a bracket (the #138-fixed shape).
|
||||||
|
match (handle_bracket(&insts, next as rune, &r_idx,
|
||||||
|
&bracket_idx, &iter, &charsets,
|
||||||
|
&skip_charclass_rest,
|
||||||
|
&is_charset_positive, &in_bracket)) {
|
||||||
|
case let e: error => return e;
|
||||||
|
case let n: nomem => return n;
|
||||||
|
case void => void;
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
let r: rune = match (next) {
|
let r: rune = match (next) {
|
||||||
case utf8.done => break;
|
case utf8.done => break;
|
||||||
case let x: rune => yield x;
|
case let x: rune => yield x;
|
||||||
@@ -416,12 +550,13 @@ export fn compile(expr: str) (regex | error | nomem) = {
|
|||||||
let v: inst = av;
|
let v: inst = av;
|
||||||
append(insts, v);
|
append(insts, v);
|
||||||
};
|
};
|
||||||
|
case '[': // regex.ha:313-314
|
||||||
|
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 '(', ')', '{':
|
||||||
// fold-3 boundary: the bracket (ha:313-334 + 268-275),
|
// fold-4 boundary: the group (ha:317-334) and
|
||||||
// group (317-334) and repetition (368-401) arms ride
|
// repetition (368-401) arms ride later folds.
|
||||||
// later folds.
|
|
||||||
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));
|
||||||
@@ -523,19 +658,19 @@ 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 non-consuming; lit + any +
|
||||||
// consuming — split/jump went live with fold 3's `|`/`?`/`*` arms);
|
// charset consuming — split/jump went live with fold 3's `|`/`?`/`*`
|
||||||
// every other inst arm is one loud not-yet-ported abort — the fold
|
// arms, charset with fold 4's brackets); every other inst arm is one
|
||||||
// boundary, the compile() metachar discipline. The "unreachable"
|
// loud not-yet-ported abort — the fold boundary, the compile()
|
||||||
// aborts on lit/any inside the non-consuming loop (ha:604-605) and
|
// metachar discipline. The "unreachable" aborts on lit/any inside
|
||||||
// the trailing default (ha:738) are Hare's own unreachable arms;
|
// the non-consuming loop (ha:604-605) and the trailing default
|
||||||
// Hare spells them bare `abort()`, ww carries a message — the
|
// (ha:738) are Hare's own unreachable arms; Hare spells them bare
|
||||||
// zero-arg builtin form is shadowed in any combined unit that
|
// `abort()`, ww carries a message — the zero-arg builtin form is
|
||||||
// declares its own abort fn (os.ww:16 is private yet shadows
|
// shadowed in any combined unit that declares its own abort fn
|
||||||
// cross-module; filed, ww-core #45). Hare's loop match omits inst_charset
|
// (os.ww:16 is private yet shadows cross-module; filed, ww-core
|
||||||
// (consuming — the loop condition excludes it); ww has no
|
// #45). Hare's loop match omits inst_charset (consuming — the loop
|
||||||
// match-exhaustiveness analysis, so the omission becomes the loud
|
// condition excludes it); ww has no match-exhaustiveness analysis,
|
||||||
// default arm.
|
// so the omission becomes the loud default arm.
|
||||||
fn run_thread(
|
fn run_thread(
|
||||||
i: size,
|
i: size,
|
||||||
re: *regex,
|
re: *regex,
|
||||||
@@ -619,8 +754,52 @@ fn run_thread(
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
case inst_any => void;
|
case inst_any => void;
|
||||||
case inst_charset =>
|
case let cs: inst_charset => { // regex.ha:704-737
|
||||||
abort("regex: inst_charset not yet ported");
|
// 24B header bind off the ptr-field slice index. Spelled
|
||||||
|
// structurally, not `charset`: an alias-typed slice local's
|
||||||
|
// INDEX read mis-scales in wwstage (cs≠ww, ww-core #68) —
|
||||||
|
// reverts to the alias with the #47 family.
|
||||||
|
let cset: [](charset_lit_item | charset_range_item |
|
||||||
|
charset_class_item) = re.charsets[cs.idx];
|
||||||
|
// Disprove the match if we're looking for a negative match
|
||||||
|
// Prove the match if we're looking for a positive match
|
||||||
|
let matched: bool = !cs.is_positive;
|
||||||
|
// Hare loops `for (let i = 0z; ...) match (charset[i])`
|
||||||
|
// (ha:709) — index loop with the typed-let scrutinee bind
|
||||||
|
// (the run_thread spelling); Hare's inner `i` renames to k
|
||||||
|
// (it shadows the thread-index param). The class arm is the
|
||||||
|
// loud fold boundary: compile() cannot emit a class item
|
||||||
|
// until the POSIX fold (charclass_map is #25-blocked).
|
||||||
|
for (let k: size = 0; k < (len(cset): size); k += 1) {
|
||||||
|
let cur: (charset_lit_item | charset_range_item |
|
||||||
|
charset_class_item) = cset[k];
|
||||||
|
match (cur) {
|
||||||
|
case let l: charset_lit_item => {
|
||||||
|
if (r == (l: rune)) {
|
||||||
|
// Succeeded if positive match
|
||||||
|
// Failed if negative match
|
||||||
|
matched = cs.is_positive;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
case let range: charset_range_item => {
|
||||||
|
let r_b: u32 = (r: u32);
|
||||||
|
|
||||||
|
if (r_b >= range.0 && r_b <= range.1) {
|
||||||
|
// Succeeded if positive match
|
||||||
|
// Failed if negative match
|
||||||
|
matched = cs.is_positive;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
case charset_class_item =>
|
||||||
|
abort("regex: POSIX character class not yet ported");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (!matched) {
|
||||||
|
(*threads)[i].failed = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
case => abort("regex: unreachable"); // unreachable (ha:738)
|
case => abort("regex: unreachable"); // unreachable (ha:738)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -261,11 +261,11 @@ fn fail() void = { os.exit(signalled + 10); };
|
|||||||
// silently compile a wrong program, and any OTHER error text 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
|
// 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); the bracket/group/
|
// \ ^ $ | ? * + positive (fold3_* below); fold 4 flipped `[`
|
||||||
// repetition four remain.
|
// (fold4_* below); the group/repetition three remain.
|
||||||
@test fn compile_metachar_loud() void = {
|
@test fn compile_metachar_loud() void = {
|
||||||
let pats: [4]str = [
|
let pats: [3]str = [
|
||||||
"a[", "a(", "a)", "a{",
|
"a(", "a)", "a{",
|
||||||
];
|
];
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < len(pats)) {
|
for (i < len(pats)) {
|
||||||
@@ -419,7 +419,7 @@ type nmexp = struct {
|
|||||||
// through a REAL compile() error, completing the exported error
|
// through a REAL compile() error, completing the exported error
|
||||||
// surface end to end.
|
// surface end to end.
|
||||||
@test fn strerror_identity() void = {
|
@test fn strerror_identity() void = {
|
||||||
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) {
|
"regex: metacharacter not yet ported") != 0) {
|
||||||
@@ -1078,6 +1078,11 @@ fn instsig(v: regex.inst) i64 = {
|
|||||||
};
|
};
|
||||||
case let g: regex.inst_groupstart => return 7000 + ((g: size): i64);
|
case let g: regex.inst_groupstart => return 7000 + ((g: size): i64);
|
||||||
case regex.inst_groupend => return 8000;
|
case regex.inst_groupend => return 8000;
|
||||||
|
case let c: regex.inst_charset => {
|
||||||
|
// fold 4: 10xxx positive / 11xxx negated, + charset index
|
||||||
|
if (c.is_positive) { return 10000 + (c.idx: i64); };
|
||||||
|
return 11000 + (c.idx: i64);
|
||||||
|
};
|
||||||
case => return 9999;
|
case => return 9999;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1351,6 +1356,357 @@ type cerow = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---- fold 4: bracket expressions --------------------------------------
|
||||||
|
|
||||||
|
// Emitted-program pins for the `[..]` arm: the charset inst lands where
|
||||||
|
// a literal would (and composes with fold-3's postfix/anchors), the
|
||||||
|
// charsets table grows one entry per bracket, negation rides
|
||||||
|
// is_positive. Derived by hand-executing regex.ha:265-275 + 313-314 +
|
||||||
|
// handle_bracket.
|
||||||
|
@test fn fold4_programs() void = {
|
||||||
|
let sigs: [17]i64 = [
|
||||||
|
// "[abc]": skip, charset 0 positive, match(false)
|
||||||
|
2000, 10000, 6000,
|
||||||
|
// "^[abc]$": anchored both ends — charset, match(TRUE)
|
||||||
|
10000, 6001,
|
||||||
|
// "[^ab]": skip, charset 0 NEGATED, match(false)
|
||||||
|
2000, 11000, 6000,
|
||||||
|
// "[ab][cd]": two brackets — charset 0, charset 1
|
||||||
|
2000, 10000, 10001, 6000,
|
||||||
|
// "[abc]*": the fold-3 a* shape with charset as the term
|
||||||
|
2000, 4004, 10000, 5001, 6000,
|
||||||
|
];
|
||||||
|
let rows: [5]pgmcase = [
|
||||||
|
pgmcase { expr = "[abc]", soff = 0, scnt = 3 },
|
||||||
|
pgmcase { expr = "^[abc]$", soff = 3, scnt = 2 },
|
||||||
|
pgmcase { expr = "[^ab]", soff = 5, scnt = 3 },
|
||||||
|
pgmcase { expr = "[ab][cd]", soff = 8, scnt = 4 },
|
||||||
|
pgmcase { expr = "[abc]*", soff = 12, scnt = 5 },
|
||||||
|
];
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < len(rows)) {
|
||||||
|
let ex: str = rows[i].expr;
|
||||||
|
let c: (regex.regex | regex.error | nomem) = regex.compile(ex);
|
||||||
|
match (c) {
|
||||||
|
case let re: regex.regex => {
|
||||||
|
if (re.insts.len != rows[i].scnt) { fail(); };
|
||||||
|
let k: i32 = 0;
|
||||||
|
for (k < rows[i].scnt) {
|
||||||
|
if (instsig(re.insts[k])
|
||||||
|
!= sigs[rows[i].soff + k]) {
|
||||||
|
fail();
|
||||||
|
};
|
||||||
|
k += 1;
|
||||||
|
};
|
||||||
|
regex.finish(&re);
|
||||||
|
};
|
||||||
|
case => fail();
|
||||||
|
};
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// cssig — flatten a charset element: lits as 1_000_000 + codepoint,
|
||||||
|
// ranges as start*10000 + end (codepoints stay < 10000 in these rows),
|
||||||
|
// class items can't exist (compile()'s POSIX arm is loud).
|
||||||
|
// The element binds structurally, not via the `charset` alias — an
|
||||||
|
// alias-typed slice local's index read mis-scales in wwstage (#68).
|
||||||
|
fn cssig(cs: [](charset_lit_item | charset_range_item |
|
||||||
|
charset_class_item), k: size) i64 = {
|
||||||
|
let cur: (charset_lit_item | charset_range_item |
|
||||||
|
charset_class_item) = cs[k];
|
||||||
|
match (cur) {
|
||||||
|
case let l: charset_lit_item =>
|
||||||
|
return 1000000 + ((l: rune): i64);
|
||||||
|
case let range: charset_range_item =>
|
||||||
|
return (range.0: i64) * 10000 + (range.1: i64);
|
||||||
|
case => return -1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type cscase = struct {
|
||||||
|
expr: str,
|
||||||
|
eoff: i32,
|
||||||
|
ecnt: i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
// charsets-table content pins: literal vs range element discrimination,
|
||||||
|
// the first-char `]`/`[` literal rules, literal dashes, and multibyte
|
||||||
|
// codepoints in both element kinds (regex.ha:172-221 state machine).
|
||||||
|
@test fn fold4_charsets() void = {
|
||||||
|
let exp: [15]i64 = [
|
||||||
|
// "[abc]"
|
||||||
|
1000097, 1000098, 1000099,
|
||||||
|
// "[]ab]" — first-char ] is a literal
|
||||||
|
1000093, 1000097, 1000098,
|
||||||
|
// "[[ab]" — [ inside a bracket is a literal
|
||||||
|
1000091, 1000097, 1000098,
|
||||||
|
// "[a-c]"
|
||||||
|
970099,
|
||||||
|
// "[-a-c]" — leading literal dash
|
||||||
|
1000045, 970099,
|
||||||
|
// "[a-c-]" — trailing literal dash
|
||||||
|
970099, 1000045,
|
||||||
|
// "[ä-ö]" — multibyte range, codepoints 228..246
|
||||||
|
2280246,
|
||||||
|
];
|
||||||
|
let rows: [7]cscase = [
|
||||||
|
cscase { expr = "[abc]", eoff = 0, ecnt = 3 },
|
||||||
|
cscase { expr = "[]ab]", eoff = 3, ecnt = 3 },
|
||||||
|
cscase { expr = "[[ab]", eoff = 6, ecnt = 3 },
|
||||||
|
cscase { expr = "[a-c]", eoff = 9, ecnt = 1 },
|
||||||
|
cscase { expr = "[-a-c]", eoff = 10, ecnt = 2 },
|
||||||
|
cscase { expr = "[a-c-]", eoff = 12, ecnt = 2 },
|
||||||
|
cscase { expr = "[ä-ö]", eoff = 14, ecnt = 1 },
|
||||||
|
];
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < len(rows)) {
|
||||||
|
let ex: str = rows[i].expr;
|
||||||
|
let c: (regex.regex | regex.error | nomem) = regex.compile(ex);
|
||||||
|
match (c) {
|
||||||
|
case let re: regex.regex => {
|
||||||
|
if (re.charsets.len != 1) { fail(); };
|
||||||
|
let cs0: [](charset_lit_item | charset_range_item |
|
||||||
|
charset_class_item) = re.charsets[0];
|
||||||
|
if ((len(cs0): i32) != rows[i].ecnt) { fail(); };
|
||||||
|
let k: i32 = 0;
|
||||||
|
for (k < rows[i].ecnt) {
|
||||||
|
if (cssig(cs0, (k: size))
|
||||||
|
!= exp[rows[i].eoff + k]) {
|
||||||
|
fail();
|
||||||
|
};
|
||||||
|
k += 1;
|
||||||
|
};
|
||||||
|
regex.finish(&re);
|
||||||
|
};
|
||||||
|
case => fail();
|
||||||
|
};
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// The fold-4 compile-error surface, exact texts (regex.ha:267 / 211).
|
||||||
|
// The `[[:alpha:]]` POSIX-class arm is a loud ABORT, not an error —
|
||||||
|
// unpinnable in-process (it kills the runner); its boundary is
|
||||||
|
// source-audited (handle_bracket's class arm) until the POSIX fold.
|
||||||
|
@test fn fold4_compile_errors() void = {
|
||||||
|
let rows: [4]cerow = [
|
||||||
|
cerow { pat = "a[", want = "Unmatched '['" },
|
||||||
|
cerow { pat = "[abc", want = "Unmatched '['" },
|
||||||
|
cerow { pat = "[z-a]",
|
||||||
|
want = "Descending bracket expression range '[z-a]'" },
|
||||||
|
// the escape arm must not eat `[`: "\[" is a literal, the
|
||||||
|
// SECOND `[` opens an unterminated bracket
|
||||||
|
cerow { pat = "\\[[", want = "Unmatched '['" },
|
||||||
|
];
|
||||||
|
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-4 find/test rows — Hare's own bracket block (+test.ha:278-345)
|
||||||
|
// minus the group row (`(` is loud) and the POSIX-class rows (loud
|
||||||
|
// abort), plus multibyte riders (literal and range brackets over
|
||||||
|
// 2-byte runes, idx != bytesize) and an unanchored composition row.
|
||||||
|
// MATCH 0 -1 resolves to (0, runelen, input) per +test.ha:693-697;
|
||||||
|
// every input is ASCII unless noted. Cross-pins test() == find().
|
||||||
|
@test fn fold4_find_cases() void = {
|
||||||
|
let rows: [72]fcase = [
|
||||||
|
fcase { expr = "^test[abc]$", input = "testa", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testa" },
|
||||||
|
fcase { expr = "^test[abc]$", input = "testb", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testb" },
|
||||||
|
fcase { expr = "^test[abc]$", input = "testc", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testc" },
|
||||||
|
fcase { expr = "^test[abc]$", input = "testd", matches = false, ... },
|
||||||
|
fcase { expr = "^test[abc]*$", input = "test", matches = true,
|
||||||
|
start = 0, sb = 0, end = 4, eb = 4, content = "test" },
|
||||||
|
fcase { expr = "^test[abc]*$", input = "testa", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testa" },
|
||||||
|
fcase { expr = "^test[abc]*$", input = "testaaa", matches = true,
|
||||||
|
start = 0, sb = 0, end = 7, eb = 7, content = "testaaa" },
|
||||||
|
fcase { expr = "^test[abc]*$", input = "testabc", matches = true,
|
||||||
|
start = 0, sb = 0, end = 7, eb = 7, content = "testabc" },
|
||||||
|
fcase { expr = "^test[abc]?$", input = "test", matches = true,
|
||||||
|
start = 0, sb = 0, end = 4, eb = 4, content = "test" },
|
||||||
|
fcase { expr = "^test[abc]?$", input = "testa", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testa" },
|
||||||
|
fcase { expr = "^test[abc]+$", input = "testa", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testa" },
|
||||||
|
fcase { expr = "^test[abc]+$", input = "test", matches = false, ... },
|
||||||
|
fcase { expr = "^test[]abc]$", input = "test]", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "test]" },
|
||||||
|
fcase { expr = "^test[[abc]$", input = "test[", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "test[" },
|
||||||
|
fcase { expr = "^test[^abc]$", input = "testd", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testd" },
|
||||||
|
fcase { expr = "^test[^abc]$", input = "test!", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "test!" },
|
||||||
|
fcase { expr = "^test[^abc]$", input = "testa", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^abc]$", input = "testb", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^abc]$", input = "testc", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^]abc]$", input = "test]", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^abc[]$", input = "test[", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^abc]*$", input = "testd", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testd" },
|
||||||
|
fcase { expr = "^test[^abc]*$", input = "testqqqqq", matches = true,
|
||||||
|
start = 0, sb = 0, end = 9, eb = 9, content = "testqqqqq" },
|
||||||
|
fcase { expr = "^test[^abc]*$", input = "test", matches = true,
|
||||||
|
start = 0, sb = 0, end = 4, eb = 4, content = "test" },
|
||||||
|
fcase { expr = "^test[^abc]*$", input = "testc", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^abc]?$", input = "test", matches = true,
|
||||||
|
start = 0, sb = 0, end = 4, eb = 4, content = "test" },
|
||||||
|
fcase { expr = "^test[^abc]?$", input = "testd", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testd" },
|
||||||
|
fcase { expr = "^test[^abc]?$", input = "testc", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^abc]+$", input = "testd", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testd" },
|
||||||
|
fcase { expr = "^test[^abc]+$", input = "testddd", matches = true,
|
||||||
|
start = 0, sb = 0, end = 7, eb = 7, content = "testddd" },
|
||||||
|
fcase { expr = "^test[^abc]+$", input = "testc", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^abc]+$", input = "testcccc", matches = false, ... },
|
||||||
|
fcase { expr = "^test[a-c]$", input = "testa", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testa" },
|
||||||
|
fcase { expr = "^test[a-c]$", input = "testb", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testb" },
|
||||||
|
fcase { expr = "^test[a-c]$", input = "testc", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testc" },
|
||||||
|
fcase { expr = "^test[a-c]$", input = "testd", matches = false, ... },
|
||||||
|
fcase { expr = "^test[a-c]$", input = "test!", matches = false, ... },
|
||||||
|
fcase { expr = "^test[a-c]$", input = "test-", matches = false, ... },
|
||||||
|
fcase { expr = "^test[-a-c]$", input = "test-", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "test-" },
|
||||||
|
fcase { expr = "^test[a-c-]$", input = "test-", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "test-" },
|
||||||
|
fcase { expr = "^test[a-c]*$", input = "test", matches = true,
|
||||||
|
start = 0, sb = 0, end = 4, eb = 4, content = "test" },
|
||||||
|
fcase { expr = "^test[a-c]*$", input = "testa", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testa" },
|
||||||
|
fcase { expr = "^test[a-c]*$", input = "testabb", matches = true,
|
||||||
|
start = 0, sb = 0, end = 7, eb = 7, content = "testabb" },
|
||||||
|
fcase { expr = "^test[a-c]*$", input = "testddd", matches = false, ... },
|
||||||
|
fcase { expr = "^test[a-c]?$", input = "test", matches = true,
|
||||||
|
start = 0, sb = 0, end = 4, eb = 4, content = "test" },
|
||||||
|
fcase { expr = "^test[a-c]?$", input = "testb", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testb" },
|
||||||
|
fcase { expr = "^test[a-c]?$", input = "testd", matches = false, ... },
|
||||||
|
fcase { expr = "^test[a-c]+$", input = "test", matches = false, ... },
|
||||||
|
fcase { expr = "^test[a-c]+$", input = "testbcbc", matches = true,
|
||||||
|
start = 0, sb = 0, end = 8, eb = 8, content = "testbcbc" },
|
||||||
|
fcase { expr = "^test[a-c]+$", input = "testd", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c]$", input = "testa", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c]$", input = "testb", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c]$", input = "testc", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c]$", input = "testd", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testd" },
|
||||||
|
fcase { expr = "^test[^a-c]$", input = "test!", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "test!" },
|
||||||
|
fcase { expr = "^test[^a-c]$", input = "test-", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "test-" },
|
||||||
|
fcase { expr = "^test[^-a-c]$", input = "test-", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c-]$", input = "test-", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c-]*$", input = "test", matches = true,
|
||||||
|
start = 0, sb = 0, end = 4, eb = 4, content = "test" },
|
||||||
|
fcase { expr = "^test[^a-c-]*$", input = "test--", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c-]*$", input = "testq", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testq" },
|
||||||
|
fcase { expr = "^test[^a-c-]?$", input = "test", matches = true,
|
||||||
|
start = 0, sb = 0, end = 4, eb = 4, content = "test" },
|
||||||
|
fcase { expr = "^test[^a-c-]?$", input = "testq", matches = true,
|
||||||
|
start = 0, sb = 0, end = 5, eb = 5, content = "testq" },
|
||||||
|
fcase { expr = "^test[^a-c-]?$", input = "test-", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c-]+$", input = "test", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c-]+$", input = "testb", matches = false, ... },
|
||||||
|
fcase { expr = "^test[^a-c-]+$", input = "testddd", matches = true,
|
||||||
|
start = 0, sb = 0, end = 7, eb = 7, content = "testddd" },
|
||||||
|
// multibyte riders: 2-byte runes in a literal bracket and a
|
||||||
|
// codepoint range — idx != bytesize in every field (B4)
|
||||||
|
fcase { expr = "^x[äö]$", input = "xä", matches = true,
|
||||||
|
start = 0, sb = 0, end = 2, eb = 3, content = "xä" },
|
||||||
|
fcase { expr = "^x[äö]$", input = "xq", matches = false, ... },
|
||||||
|
fcase { expr = "^[à-ö]$", input = "á", matches = true,
|
||||||
|
start = 0, sb = 0, end = 1, eb = 2, content = "á" },
|
||||||
|
fcase { expr = "^[à-ö]$", input = "x", matches = false, ... },
|
||||||
|
// unanchored leftmost-longest composition with fold-3's `+`
|
||||||
|
fcase { expr = "[ab]+", input = "xxabyyba", matches = true,
|
||||||
|
start = 2, sb = 2, end = 4, eb = 4, content = "ab" },
|
||||||
|
];
|
||||||
|
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) != 1) { 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 composition: charset × split (`+`) × the 2c machinery —
|
||||||
|
// non-overlapping greedy matches over mixed input.
|
||||||
|
@test fn fold4_findall() void = {
|
||||||
|
let c: (regex.regex | regex.error | nomem) = regex.compile("[ab]+");
|
||||||
|
match (c) {
|
||||||
|
case let re: regex.regex => {
|
||||||
|
let fr: ([]regex.result | nomem) =
|
||||||
|
regex.findall(&re, "xxabyyba");
|
||||||
|
if (!(fr is []regex.result)) { fail(); };
|
||||||
|
let results: []regex.result = fr as []regex.result;
|
||||||
|
if (len(results) != 2) { fail(); };
|
||||||
|
if (results[0][0].start != (2: size)) { fail(); };
|
||||||
|
if (results[0][0].end != (4: size)) { fail(); };
|
||||||
|
if (strings.compare(results[0][0].content, "ab") != 0) {
|
||||||
|
fail();
|
||||||
|
};
|
||||||
|
if (results[1][0].start != (6: size)) { fail(); };
|
||||||
|
if (results[1][0].end != (8: size)) { fail(); };
|
||||||
|
if (strings.compare(results[1][0].content, "ba") != 0) {
|
||||||
|
fail();
|
||||||
|
};
|
||||||
|
regex.result_freeall(results);
|
||||||
|
regex.finish(&re);
|
||||||
|
};
|
||||||
|
case => fail();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
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();
|
||||||
@@ -1383,5 +1739,10 @@ export fn main() i32 = {
|
|||||||
signalled = 29; find_last_groupstart_cases();
|
signalled = 29; find_last_groupstart_cases();
|
||||||
signalled = 30; shift_direct();
|
signalled = 30; shift_direct();
|
||||||
signalled = 31; fold3_find_cases();
|
signalled = 31; fold3_find_cases();
|
||||||
|
signalled = 32; fold4_programs();
|
||||||
|
signalled = 33; fold4_charsets();
|
||||||
|
signalled = 34; fold4_compile_errors();
|
||||||
|
signalled = 35; fold4_find_cases();
|
||||||
|
signalled = 36; fold4_findall();
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user