A from-scratch, memory-safe PHP engine written in Rust — built the same way the Bun team rewrote Bun in Rust: drive an AI with the original project's own test suite as the oracle, and watch the pass-rate climb in public.
WordPress Playground runs WordPress entirely in your browser by compiling the C PHP interpreter to WebAssembly via Emscripten. Those WASM builds are big, and the Playground team has been actively fighting binary size. Rust → WASM is leaner and memory-safe by construction. So the goal:
A PHP engine in Rust that passes PHP's own
.phpttests and boots WordPress inside Playground — at a fraction of the WASM size.
I'm not (yet) a Rust or PHP-internals expert. This is an open experiment in AI-assisted engineering. The wins and the failures are in the open, and the scoreboard never lies — see PROGRESS.md.
src/lang/— the engine: a proper language implementation — byte-level lexer (lexer.rs/token.rs) → recursive-descent parser → owned AST (ast.rs/parser.rs) → tree-walking evaluator (value.rs/eval.rs).run(php_source) -> printed output.src/lib.rs— a 52-line crate root: the publicrun/run_with_pathentry points + the shared subsystems the evaluator reuses (regex.rs,datetime.rs).src/main.rs— the scoreboard. Runs every.phptinvendor/php-src/, compares output to each test's expected section, writesPROGRESS.md.tests/phpt/— curated smoke tests. Real PHP.phptformat: each file bundles the code and its expected output, so we can score against it with no PHP runtime installed.
Note: the engine was rebuilt from scratch (the original single-pass interpreter is retired). The from-scratch lexer→parser→AST→evaluator now passes more corpus tests than the engine it replaced — see the git history.
cargo runv2 engine: 2048 / 21862 upstream php-src tests passing (9.37%). Rebuilt from scratch as a real lexer→parser→AST→evaluator, the engine now passes more corpus tests than the original single-pass interpreter it replaced (1,981), with byte-correct strings, correct operator precedence, and an AST (parse once, no re-parsing). The core language is there — variables, the full operator/type-juggling model, control flow, functions/closures (+ variadics ...$x, argument unpacking ...$arr, named args), arrays + ~200 builtins, classes/interfaces/traits/enums, exceptions, constructor promotion, attributes + 8.4 property hooks, dynamic new $cls() / $obj->$m(), class introspection + Reflection, foreach over user Iterator/IteratorAggregate, ArrayAccess ($obj[$k]), SPL containers (ArrayObject/ArrayIterator/SplStack/SplQueue/SplFixedArray/SplObjectStorage/SplHeap), date/time (date/mktime/strtotime/DateTime/DateInterval), a from-scratch regex engine (preg_*), include/require/eval, output buffering, filesystem + path functions, serialize/unserialize, and var_export/var_dump. The climb continues — see PROGRESS.md.
