From 64f6cc90f2c98bd8638c7e96b5d11cbea2d33f6e Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 4 Jun 2026 05:45:52 +0900 Subject: [PATCH] lib/regex: pin exact loud-boundary text across all 11 deferred metachars (fold-2a review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The loud-arm row asserted only a non-empty error on "a*" — a half-ported arm returning any other error text, or another metachar falling to the literal default, would have passed. Table over one pattern per deferred arm ('^' leading, so the r_idx==0 skip gate composes with the loud arm) compared against the exact boundary text via strings.compare. --- lib/regex/regex_test.ww | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/regex/regex_test.ww b/lib/regex/regex_test.ww index b08f4281..cd31de06 100644 --- a/lib/regex/regex_test.ww +++ b/lib/regex/regex_test.ww @@ -23,6 +23,7 @@ package regex; import regex; import os; +import strings; let signalled: i32 = 0; fn fail() void = { os.exit(signalled + 10); }; @@ -244,12 +245,30 @@ fn fail() void = { os.exit(signalled + 10); }; }; }; -// Any deferred metacharacter is a LOUD error — pins the fold-2a -// boundary so the fold that ports '*' consciously deletes this row. +// 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. '^' leads its +// pattern: the r_idx==0 skip gate (regex.ha:261) must compose with +// the loud arm, not bypass it. @test fn compile_metachar_loud() void = { - match (regex.compile("a*")) { - case let e: regex.error => { if ((e: str).len == 0) { fail(); }; }; - case => fail(); + let pats: [11]str = [ + "a\\", "^a", "a$", "a[", "a(", "a)", + "a|", "a{", "a?", "a*", "a+", + ]; + let i: i32 = 0; + for (i < len(pats)) { + match (regex.compile(pats[i])) { + case let e: regex.error => { + if (strings.compare((e: str), + "regex: metacharacter not yet ported") != 0) { + fail(); + }; + }; + case => fail(); + }; + i += 1; }; };