Skip to content

M7b: $match + $replace regex builtins#25

Merged
flearc merged 6 commits into
mainfrom
feature/m7b-match-replace
Jun 25, 2026
Merged

M7b: $match + $replace regex builtins#25
flearc merged 6 commits into
mainfrom
feature/m7b-match-replace

Conversation

@flearc

@flearc flearc commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Summary

Implements the two remaining regex builtins on M7a's foundation, taking the regex group fully green.

  • Helpers (2b6ef89): hoist is_regex + the lazy apply into shared H (third use); H.serialize now skips function-valued (and NOTHING) object keys so a raw match object serializes to valid JSON (no …"next":}); adds D3010/D3011/D3012/D3040/T1010.
  • $match (7d42bc6) <s-f<s:o>n?:a<o>>: applies the regex value, walks global matches via the closure's .next, reshapes each to {match, index, groups} (jsonata's startindex), singleton-unwraps a single result, D3040 on negative limit.
  • $replace (e254c4b) <s-(sf)(sf)n?:s>: string pattern → literal replace (replacement verbatim); regex pattern → a ported jsonata $-scanner ($$$, $0→whole, $N→group via the maxDigits rule) or a function replacer (D3012 if it returns non-string); D3010 empty pattern, D3011 negative limit.
  • Fidelity (63a9efe): adversarial review caught a real crashlrexlib returns Lua false for a non-participating optional capture group where jsonata uses null, which made $replace's string replacer table.concat on a boolean and put false in $match groups. One root-cause fix (normalize falsenull at the regex.lua boundary; the $N substituter only emits actual string captures) closes both symptoms and regex/case016.

Results

  • Official suite 1261 → 1296 (+35, → 77.1%); regex group 10 → 39/39 (fully green), function-replace value cases +5, matchers +1.
  • 528 unit tests green; zero-regression guard green (additions-only); $contains/$split and the HOFs (apply-hoist call path) byte-identical.
  • Adversarial review vs genuine jsonata-js v2.2.1: $match shapes/limits, the full $N scanner incl. maxDigits + alternation/non-participating edges, function replacers, string-vs-regex patterns, errors, and the serialize fix — all oracle-faithful.

Deferred (non-suite)

$match(…)[0].groups singleton-unwrap ("b" vs ["b"]) — affects zero suite cases (a probe-only edge); the holistic cons-array navigation fix remains a separate follow-up. Plus minor cleanups (H.is_callable hoist, module-level parse_int, $split O(n²) re-slice).

Test plan

  • busted spec/ — 528/0
  • busted spec/jsonata_suite_spec.lua — zero-regression guard green
  • bash scripts/run-suite.sh — 1296/1682, regex 39/39
  • Adversarial oracle review (jsonata@2.2.1) incl. the $N maxDigits + non-participating-group edges

🤖 Generated with Claude Code

flearc and others added 6 commits June 25, 2026 17:12
…NOTHING keys

Shares the regex-value apply helpers (third use, for $match/$replace) and stops
a match object's function-valued `next` field from producing invalid JSON in
$string. Adds D3010/D3011/D3012/D3040/T1010 error messages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… walker

Reshapes the match closure's start->index, iterates global matches, unwraps a
single result (jsonata sequence semantics), D3040 on negative limit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…limits

String pattern does a literal replace (replacement verbatim); regex pattern
iterates matches with a ported jsonata $-scanner ($$ literal, $0 whole, $N
group via maxDigits) or a function replacer (D3012 if it returns non-string).
D3010 empty pattern, D3011 negative limit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…essions

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…fidelity)

Adversarial review found lrexlib yields `false` for an unmatched optional group;
jsonata uses null. We crashed ($replace string replacer concat on a boolean) and
mis-rendered ($match groups had false). Normalize false->V.NULL at the regex.lua
boundary, and the $N substituter only emits actual string captures (null -> empty).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…case016 (39/39)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@flearc flearc merged commit a72395d into main Jun 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant