feat: add multi-engine regex flavour support

This commit is contained in:
2026-07-27 11:43:51 +02:00
parent 7079cde15f
commit 7f3a91ad37
340 changed files with 643286 additions and 483 deletions

View File

@@ -9,13 +9,22 @@ React workbench
│ ├─ Regexpp ECMAScript provider → normalized AST
│ ├─ PCRE2 lexical provider → partial normalized structure
│ ├─ Python lexical provider → partial normalized structure
─ Java lexical provider → partial normalized structure
─ Java lexical provider → partial normalized structure
│ └─ PHP/Perl/Ruby/C++/Go/Rust/.NET/Scala lexical providers → partial structures
├─ Replacement SyntaxSupervisor → syntax.worker → typed replacement tokens
├─ EngineSupervisor
│ ├─ ecmascript.worker → native RegExp → match DTOs
│ ├─ pcre2.worker → PCRE2 10.47 WASM ABI → match DTOs
│ ├─ php.worker → PHP 8.5.8 preg / PCRE2 10.44 → match DTOs
│ ├─ perl.worker → legacy WebPerl 0.09-beta / Perl 5.28.1 → match DTOs
│ ├─ python.worker → Pyodide 314.0.3 → CPython 3.14.2 re → match DTOs
java.worker → TeaVM 0.15.0 java.util.regex module → match DTOs
ruby.worker → ruby.wasm → CRuby 4.0.0 Regexp → match DTOs
│ ├─ java.worker → TeaVM 0.15.0 java.util.regex module → match DTOs
│ ├─ cpp.worker → Emscripten 6.0.4 libc++ std::wregex → match DTOs
│ ├─ go.worker → Go 1.26.5 standard-library regexp → match DTOs
│ ├─ rust.worker → Rust regex crate 1.13.1 → match DTOs
│ ├─ dotnet.worker → .NET 10.0.10 System.Text.RegularExpressions → match DTOs
│ └─ scala.worker → explicit compatibility adapter → TeaVM Java module
├─ Pcre2TraceSupervisor → pcre2-trace.worker
│ └─ separate ABI-v3 PCRE2_AUTO_CALLOUT operation → bounded trace DTOs
├─ AnalysisPanel
@@ -50,6 +59,9 @@ a new generation. Timeout is a distinct error state. A separate idempotent
load operation verifies a worker's runtime identity before execution; its
flavour-specific startup deadline is not charged to the 250 ms live or selected
manual execution deadline. A killed generation must load and verify again.
The supervisor has a two-worker retention target; before creating another
profile worker it evicts the least recently used idle generation. Active work
is never evicted and may temporarily exceed that target.
The Python worker imports only the self-hosted Pyodide loader and pack, then
evaluates the application-owned bounded bridge in CPython. The bridge returns
@@ -59,6 +71,22 @@ ES2015 module. That module executes TeaVM's own `java.util.regex.Pattern` and
`Matcher` class-library implementation and returns native UTF-16 ranges; it is
not OpenJDK.
PHP, Perl, Ruby, C++, Go, Rust and .NET each use a fixed bounded bridge to the
named self-hosted runtime. User values cross as structured/JSON data, never as
generated source. Scala intentionally reuses the TeaVM Java module and rewrites
only request/result profile metadata; it contains no Scala runtime. The legacy
Perl topology is unusual: the supervised module worker owns the classic worker
required by WebPerl, so supervisor termination still discards the complete
worker tree.
Ruby's production bridge avoids ruby.wasm's generic JavaScript object
conversion: the worker writes one bounded length-prefixed request into its
private WASI memory filesystem, calls the fixed bridge with no user arguments,
reads one bounded inert metadata JSON string, and obtains bounded UTF-8
replacement output from a separate private file. That path avoids JSON output
amplification and passes the same strict-CSP browser gate as the other
profiles.
PCRE2 tracing is not an `EngineSupervisor` match or replacement operation. Its
own worker compiles with `PCRE2_AUTO_CALLOUT`, copies only complete fixed
records and bounded mark bytes, and stops natively at either trace cap.
@@ -86,9 +114,10 @@ deterministic golden identities and an exact PCRE2 10.47 compile/execute gate.
Subject minimization is a main-thread bounded reducer whose expensive predicate
checks stay in independently terminable ECMAScript or PCRE2 workers. Fixed
pattern syntax is parsed once for capture metadata. Python and Java are blocked
at this feature boundary rather than routed to a different engine. The baseline
and every accepted candidate retain the exact target and engine identity.
pattern syntax is parsed once for capture metadata. Every other profile is
blocked at this feature boundary rather than routed to a different engine. The
baseline and every accepted candidate retain the exact target and engine
identity.
Timeout, crash, cancellation, worker failure and incomplete output are separate
outcomes. Deterministic ddmin deletion is followed by a fixed-point local sweep
over Unicode-scalar deletion and lower-rank canonical replacement; only
@@ -139,13 +168,13 @@ separator during apply. This makes anchor and cross-line behavior deliberately
different rather than silently rewriting the pattern. Match DTOs are reduced to
bounded per-group participation counts and samples before the next document.
Native ranges are retained in the engine's declared unit. ECMAScript and Java
use UTF-16 code units. PCRE2 always uses UTF/UCP and exposes UTF-8 byte ranges;
its ABI copies scalar records and names out of WebAssembly before returning and
retains no code pointer. CPython `re` exposes Unicode code-point indices.
Browser editor ranges are half-open UTF-16 code-unit ranges. Reusable
converters cover UTF-8 byte and Unicode code-point offsets, including
invalid-boundary rejection and lone-surrogate detection.
Native ranges are retained in the engine's declared unit. ECMAScript, Java,
Scala compatibility and .NET use UTF-16 code units. Standalone PCRE2, PHP, Go
and Rust expose UTF-8 byte ranges. CPython, CRuby, libc++ `std::wregex` and
legacy Perl expose Unicode code-point positions. Browser editor ranges are
half-open UTF-16 code-unit ranges. Reusable converters cover UTF-8 byte and
Unicode code-point offsets, including invalid-boundary rejection and
lone-surrogate detection.
The release boundary is `dist/` plus checked-in legal/source documents. The
Portal consumes the resulting immutable ZIP and never imports React source.