181 lines
11 KiB
Markdown
181 lines
11 KiB
Markdown
# Architecture
|
|
|
|
Regex Tools is a static browser application with framework-neutral regex
|
|
boundaries.
|
|
|
|
```text
|
|
React workbench
|
|
├─ Pattern SyntaxSupervisor → syntax.worker
|
|
│ ├─ Regexpp ECMAScript provider → normalized AST
|
|
│ ├─ PCRE2 lexical provider → partial normalized structure
|
|
│ ├─ Python 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
|
|
│ ├─ 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
|
|
│ ├─ normalized-AST ECMAScript static heuristics
|
|
│ └─ AnalysisSupervisor → analysis.worker → native RegExp benchmark/growth probes
|
|
├─ ComparisonOrchestrator
|
|
│ ├─ two exact syntax snapshots + independently killable engine workers
|
|
│ └─ normalized UTF-16 match/capture alignment + explicit incomplete states
|
|
├─ PCRE2 C17 generator → validated snapshot → exact UTF-8 byte-array source
|
|
├─ SubjectMinimizer
|
|
│ ├─ fixed syntax snapshots + exact real-engine failure or comparison oracle
|
|
│ └─ deterministic Unicode-scalar reducer → bounded local-minimal result
|
|
├─ CaseGenerationOrchestrator
|
|
│ ├─ generation.worker → deterministic bounded ECMAScript AST candidates
|
|
│ └─ EngineSupervisor → selected actual-engine label verification
|
|
├─ ECMAScript literal/control formatter
|
|
│ ├─ exact regexpp literal-token ranges → idempotent candidate preview
|
|
│ └─ PatternFormatValidator → paired syntax + actual-engine workers and exact tests
|
|
├─ Corpus EngineSupervisor → sequential bounded document jobs → summaries/outputs
|
|
├─ Test SyntaxSupervisor + EngineSupervisor → isolated cancellable test runs
|
|
└─ project validator / serializer / IndexedDB persistence
|
|
```
|
|
|
|
Provider AST objects never cross the worker boundary. The syntax worker emits
|
|
application-owned nodes, tokens, diagnostics, capture definitions and explicit
|
|
provenance. React never imports or traverses regexpp's cyclic AST.
|
|
|
|
Every engine request carries a protocol version, monotonically increasing
|
|
request ID and worker generation. A supervisor allows one active request,
|
|
rejects stale responses, terminates on timeout/crash/cancel, and lazily creates
|
|
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
|
|
code-point ranges, which are retained as native values and converted only at
|
|
valid boundaries to editor UTF-16. The Java worker imports a verified TeaVM
|
|
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.
|
|
Reported callout fields retain byte positions; movement classifications are a
|
|
separate derived UI layer. Normal execution, corpus, tests and benchmarks never
|
|
run through the trace operation.
|
|
|
|
Static analysis traverses the normalized ECMAScript tree on the UI side under
|
|
node/finding caps. Timing and generated-input growth probes use the independent
|
|
analysis worker. Timeout, cancellation or crash discards that worker; no trace
|
|
mode is benchmarked.
|
|
|
|
Comparison is a separate orchestration layer, not an `EngineSupervisor`
|
|
operation. It runs explicit ECMAScript and PCRE2 syntax/execution snapshots,
|
|
retains each engine identity and native range model, and aligns only normalized
|
|
editor ranges. Timeout, cancellation, compile rejection and truncation remain
|
|
distinct non-comparable outcomes. Shared patterns are sent unchanged;
|
|
per-flavour ports are user-owned variants.
|
|
|
|
The PCRE2 C generator is application-owned and never implements browser
|
|
execution. It validates one exact PCRE2 snapshot, emits user strings as
|
|
independent UTF-8 byte arrays, and states the host-level mappings that the
|
|
PCRE2 API cannot express directly. Its advertised C17 target is protected by
|
|
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. 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
|
|
completion of that sweep permits a transform-local minimality claim.
|
|
|
|
Generated-case synthesis and verification are separate trust boundaries. The
|
|
dedicated generation worker receives only a validated, complete ECMAScript
|
|
normalized tree plus explicit settings and seed. The main-thread orchestrator
|
|
then sends each bounded candidate to `EngineSupervisor`; only the selected real
|
|
adapter can establish a `should-match` or `should-not-match` label. Worker
|
|
timeout, crash, cancellation, compile rejection, wrong outcome and ordinary
|
|
failure stay distinct. Settings/results are ephemeral, while explicitly added
|
|
unit tests retain field-validated generator provenance.
|
|
|
|
Formatting is not an engine operation and never rewrites from heuristic text
|
|
alone. The ECMAScript formatter consumes an exact accepted regexpp snapshot and
|
|
changes only parser-reported literal/control token ranges. Its validator
|
|
reparses source and candidate separately, preserves capture shape, runs both in
|
|
separate actual-engine workers against the current replacement snapshot, then
|
|
replays every enabled test tied to the exact active pattern/version/flags/options.
|
|
Any difference, incomplete output, one-sided timeout, identity change or
|
|
inconclusive worker outcome blocks apply. The preview and observations are
|
|
ephemeral, and user confirmation is required even after all bounded gates pass.
|
|
|
|
Pattern and replacement syntax use independent supervisors. A pattern snapshot
|
|
is bound to its exact pattern, ordered flags and revision; execution cannot use
|
|
acceptance or capture metadata from an earlier input. Replacement output is
|
|
built while the native engine produces the same bounded authoritative match
|
|
sequence that is returned to the UI.
|
|
|
|
Per-match replacement ranges and token contributions are deterministic mappings
|
|
over those actual matches, the complete replacement-token model and the bounded
|
|
output. They execute no replacement callback or user code and have separate
|
|
presentation and token-evaluation limits.
|
|
|
|
Corpus documents are ephemeral React session state, not project state. A
|
|
dedicated engine supervisor processes one document at a time and is terminated
|
|
on cancellation, timeout or workspace exit. Batch orchestration retains only
|
|
per-document summaries and, for apply runs, bounded outputs. It enforces
|
|
document-count, per-document byte, aggregate input byte, aggregate match,
|
|
aggregate output and batch wall-time limits. Exact-output export is unavailable
|
|
if any document is partial, failed, cancelled or not run.
|
|
|
|
Whole-document mode sends each document to the engine once. Independent-line
|
|
mode segments CRLF, CR, LF, U+2028 and U+2029 without discarding them, executes
|
|
each logical line as its own subject, and reattaches the exact original
|
|
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, 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.
|