119 lines
5.3 KiB
Markdown
119 lines
5.3 KiB
Markdown
# ECMAScript/PCRE2 comparison and PCRE2 C generation
|
|
|
|
## Comparison contract
|
|
|
|
The comparison panel sends two explicit requests: one to the native browser
|
|
ECMAScript worker and one to the bundled PCRE2 10.47 worker. It does not
|
|
translate patterns, flags, options or replacement templates.
|
|
|
|
Two pattern models are available:
|
|
|
|
- **Shared pattern** sends the same string unchanged to both engines.
|
|
- **Per-flavour variants** retains two explicit ports supplied by the user.
|
|
|
|
Flags are selected independently from each flavour's registered allowlist.
|
|
PCRE2 match, depth and heap bounds are part of its exact request. Both sides
|
|
share the selected subject, scan-all intent, host result bounds and wall-clock
|
|
worker timeout.
|
|
|
|
Each side retains:
|
|
|
|
- its syntax-provider request, acceptance, diagnostics and coverage;
|
|
- the exact execution or replacement request sent to its worker;
|
|
- a deterministic display key plus the complete authoritative request;
|
|
- completion, timeout, cancellation or worker-failure status;
|
|
- engine, runtime and adapter identity when the engine returns one;
|
|
- user and effective flags;
|
|
- native ranges and normalized editor UTF-16 ranges;
|
|
- compile acceptance, matches, captures and replacement output.
|
|
|
|
The orchestrator owns two syntax supervisors and the multi-engine execution
|
|
supervisor. The two engine calls run concurrently through independently
|
|
killable flavour workers. A side timeout kills only that worker. The shared
|
|
Cancel action terminates every active comparison worker. Comparison remains
|
|
outside `EngineSupervisor`, whose responsibility is one engine operation and
|
|
lifecycle boundary.
|
|
|
|
Match pairs are aligned by equal normalized UTF-16 ranges first. Unpaired
|
|
matches use an explicitly labelled ordinal fallback. Captures are aligned by
|
|
normalized range, then capture identity, then an explicitly labelled ordinal
|
|
fallback. Original native offsets remain attached to both results.
|
|
|
|
No equivalence claim is made when syntax or compilation is rejected, a worker
|
|
times out/fails/is cancelled, results or values are truncated, or replacement
|
|
output is incomplete. A completed matching result is labelled only as
|
|
agreement for the current subject; it is evidence, not a proof that two
|
|
patterns are equivalent. Timeout is never interpreted as “no match.”
|
|
|
|
The retained DTO is bounded to 5,000 displayed difference records and 2,000
|
|
match alignments while still counting all differences in the bounded engine
|
|
result. The panel renders at most 250 differences and 100 alignments at once.
|
|
|
|
## PCRE2 C17 generator
|
|
|
|
The first reviewed code-generation target is the PCRE2 10.47 8-bit C API.
|
|
Other languages remain unavailable until their generators have equivalent
|
|
escaping, semantic and toolchain gates.
|
|
|
|
The generator consumes a validated PCRE2 snapshot and:
|
|
|
|
- requires the registered PCRE2 10.47 version and flag/option allowlists;
|
|
- refuses unpaired UTF-16 surrogates rather than emitting lossy UTF-8;
|
|
- emits pattern, subject and replacement as independent explicit UTF-8 byte
|
|
arrays, so quotes, backslashes, newlines, NUL, Unicode, dollar signs and
|
|
braces cannot escape into C source syntax;
|
|
- enables mandatory `PCRE2_UTF` and `PCRE2_UCP`;
|
|
- maps `i`, `m`, `s`, `x`, `U` and `J` to named PCRE2 compile constants;
|
|
- implements application-level `g`/scan-all behavior explicitly;
|
|
- handles the PCRE2 empty-match anchored retry before advancing one UTF-8
|
|
character;
|
|
- configures native match, depth and heap limits;
|
|
- enforces match/capture row caps in the generated match loop;
|
|
- bounds replacement output with a host buffer and withholds output when its
|
|
post-run result-row bound is exceeded;
|
|
- reports compile offsets and native API errors and cleans up all PCRE2 state;
|
|
- rejects compilation against a PCRE2 header other than 10.47 and verifies the
|
|
runtime version.
|
|
|
|
The generated program states limitations that cannot be mapped honestly:
|
|
|
|
- PCRE2 has no `g` compile flag;
|
|
- match/capture rows and replacement-output size are host-application bounds,
|
|
not PCRE2 matching options;
|
|
- replacement result-row limits can be checked only after
|
|
`pcre2_substitute()` has completed;
|
|
- PCRE2 exposes no native wall-clock timeout, so hard elapsed-time
|
|
cancellation belongs to the containing process;
|
|
- C API offsets are UTF-8 bytes, not browser editor UTF-16 units.
|
|
|
|
Generated snippets are examples only and are never used to implement the
|
|
browser runtime.
|
|
|
|
## Golden and toolchain gate
|
|
|
|
`scripts/pcre2-codegen-golden.test.ts` pins deterministic SHA-256 identities
|
|
for match and replacement fixtures:
|
|
|
|
```text
|
|
match 22b91d578a449b0ed5c30e6eadad30f19a2bcb26ac9db355c8ec7a69328675da
|
|
replacement ab90a0d9831ea7b7145aa0072ac352b42baf9a795319d81f531b0f341b04a636
|
|
```
|
|
|
|
The compile/execute gate was run against a host static build from official
|
|
signed tag `pcre2-10.47`, commit
|
|
`f454e231fe5006dd7ff8f4693fd2b8eb94333429`. Both generated fixtures compile
|
|
under C17 with `-Wall -Wextra -Werror`; the match fixture verifies native UTF-8
|
|
ranges and named captures, and the replacement fixture verifies exact Unicode
|
|
output and substitution count.
|
|
|
|
To repeat the gate with an exact local PCRE2 installation:
|
|
|
|
```sh
|
|
PCRE2_CODEGEN_PREFIX=/path/to/pcre2-10.47-prefix \
|
|
npm test -- scripts/pcre2-codegen-golden.test.ts
|
|
```
|
|
|
|
The prefix must provide `include/pcre2.h` and
|
|
`lib64/libpcre2-8.a`. A different static-library location can be supplied
|
|
through `PCRE2_CODEGEN_LIBRARY`.
|