# Legacy Perl engine

This engine uses the unmodified prebuilt WebPerl `v0.09-beta` distribution,
which contains Perl `v5.28.1` compiled by Emscripten `1.38.28`. It is an
explicitly legacy, beta compatibility target. It is not current desktop Perl.

## Trust boundary

`regex_tools_bridge.pl` is fixed application source. The classic runtime worker
writes each exact-key, byte-bounded request as JSON to a fixed MEMFS path and
invokes only the constant Perl expression `RegexTools::run_request()`. The
metadata-only response uses a second bounded JSON file. Successful replacement
bytes use a third, fixed binary file; the worker checks its exact declared
length, output bound and canonical UTF-8 before supplying the decoded string to
the adapter. Pattern, subject, flags and replacement values are never
interpolated into Perl or JavaScript source.

The bridge:

- compiles a scalar pattern with `no re 'eval'`;
- independently rejects `(?{...})` and `(??{...})` outside escaped literals
  and character classes;
- never imports the WebPerl JavaScript interoperability module;
- pre-tokenizes a deliberately bounded replacement grammar consisting of
  literal text, `$$`, greedy `$n` and `${name}`;
- streams unmatched spans, literals and native capture values to the binary
  output file in small UTF-8 chunks, stopping before a code point would cross
  the output-byte bound;
- stops replacement at the match/capture-row result bound and preserves the
  remaining subject as an unchanged tail;
- compares fixed named and numbered streaming fixtures with native Perl
  `s///` output during the identity self-test;
- validates every request again inside Perl; and
- reports native Perl character offsets as Unicode code-point offsets.

Numbered capture participation and spans come from Perl's native `@-` and `@+`
arrays. The legacy runtime does not expose a stable name-to-number table, so
the adapter annotates those native capture rows with names from regex-tools'
syntax metadata. Numbered replacement values are streamed directly from their
native spans. Named replacement lookup itself uses Perl's native `%+`, and only
names present in the pre-tokenized template are read.

The prebuilt `emperl.js` contains one JavaScript `eval(code)` site in its
optional Perl-to-JavaScript interoperability import. The fixed bridge does not
load or call that facility. A Chromium CSP smoke succeeds with
`script-src 'self' 'wasm-unsafe-eval'` and without `'unsafe-eval'`.

The module worker remains responsive while the nested classic worker executes.
Terminating the supervised module worker terminates its worker descendants, so
catastrophic matching remains killable.

## Provenance

- WebPerl release: `v0.09-beta`
- Release commit: `6f2173d29a2c2e3536e1de75ff5d291ae96ab348`
- Prebuilt archive:
  `https://github.com/haukex/webperl/releases/download/v0.09-beta/webperl_prebuilt_v0.09-beta.zip`
- Archive SHA-256:
  `5f441249217e90ab378c666f473d4206ab4f44907f6bb0aa8d70834bc38c40dc`
- Perl runtime identity: `v5.28.1`
- Emscripten toolchain identified by the pinned upstream build configuration:
  `1.38.28`

The deployed `emperl.js`, `emperl.wasm` and `emperl.data` files are copied
byte-for-byte from that archive. See `public/engines/perl/engine-metadata.json`,
`NOTICE.txt`, and the adjacent license files.
