Files
rust_browser/docs/test262_roadmap.md
Zachary D. Rowitsch 0c21feb090
Some checks failed
ci / fast (linux) (push) Failing after 11m14s
Implement JSON.stringify and JSON.parse with full spec compliance
Add the JSON global object with both methods following the sentinel
NativeFunction + interpreter interception pattern. The implementation
includes a dedicated recursive descent JSON parser (strict spec: no
trailing commas, no single quotes, no hex/octal, surrogate pair support),
JSON.stringify with replacer function/array, space indentation, toJSON,
boxed primitive unwrapping, and circular reference detection via ptr_eq.

Safety: depth-limited to 512 levels for both parse and stringify to
prevent stack overflow from malicious input. Space string truncation
uses char boundaries to avoid panics on multi-byte UTF-8.

138 unit tests, 2 conformance tests (js262).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 17:00:47 -05:00

12 KiB

Test262 Roadmap

What needs to be built to run real Test262 conformance tests.

Current State

We have a custom JS262 harness (tests/js262_harness.rs) with 214 hand-written tests plus 550 real Test262 tests vendored from tc39/test262. The real Test262 suite has 50,000+ tests. Phase A vendored 50 tests; Phase B expanded to 550 with automated triage.

Tier 1: Test262 Harness Requirements

These features are used by assert.js and sta.js — the support files that every Test262 test includes. All of these must work before any real Test262 test can run.

Feature Used For Parser Interpreter Effort
try / catch / finally assert.throws() wraps test code in try/catch Done Done Medium
throw statement sta.js throws Test262Error on failure Done Done Small
Logical && / || Short-circuit guards in assertions Done Done Small
Object literals { k: v } Building error message objects Done Done Medium
Property assignment obj.prop = v assert.sameValue = function ... Done (dot only) Done (host + plain objects)
Prototype chain Test262Error.prototype.toString = ... N/A Done Large
this keyword Constructor bodies: this.message = msg Done Done
switch / case assert._toString type formatting Done Done Medium
Template literals `${x}` Assertion error messages Done Done
new + constructor functions new Test262Error(msg) Done Done Prototype-linked instances
String methods (.name, .call) Object.prototype.toString.call() Done Done Medium

Minimum viable slice

To run the simplest Test262 tests, implement in this order:

  1. throw — trivial addition to parser + interpreter Done
  2. try / catch — parser + interpreter control flow Done
  3. Logical operators && / || — parser + short-circuit eval Done
  4. Object literals — parser + runtime plain-object type Done
  5. this keyword — parser + interpreter binding Done
  6. switch / case — parser + interpreter control flow Done
  7. Template literals — tokenizer + parser + string interpolation eval Done

After these 7 features, we can shim assert.js and sta.js and run Test262 tests that only use basic syntax (variable declarations, functions, if/else, comparisons).

Tier 2: Common Test File Features

Most Test262 tests go beyond basic syntax. These features unlock large swaths of the suite.

Feature % of Test262 tests using it Parser Interpreter Effort
for loops ~60% Done Done Medium
for...in / for...of ~25% Done Done Medium
while / do...while ~15% Done Done Small
Array literals [1,2,3] ~50% Done Done Medium
Computed member obj[key] ~40% Done Done Small
Arrow functions => ~30% Done Done Medium
Ternary ? : ~20% Done Done Small
Compound assignment += etc. ~20% Done Done Small
Increment/decrement ++/-- ~15% Done Done Small
Destructuring ~10% Done Done Large
Spread / rest ... ~10% Done Done Medium
class declarations ~10% Done Done Large

After Tier 1 is complete:

  1. for loops — unlocks the most tests Done
  2. Array literals + computed member — tightly coupled, unlock array tests Done
  3. Arrow functions — widely used in modern test262 tests Done
  4. while / do...while — small effort, moderate test coverage Done
  5. Ternary ? : — trivial parser change Done
  6. Compound assignment / increment-decrement — small parser + desugar Done
  7. Spread / rest ... — arrays, strings, function args/params, object spread Done
  8. Destructuring — array/object destructuring in declarations, assignments, parameters, for-of/in Done

Tier 3: Richer Runtime

These require more substantial runtime work beyond parsing and basic interpretation.

Feature What it unlocks Effort Parser Interpreter
Plain JS objects Object literals, enumeration, Object.keys/values/entries, Object.create/assign/getPrototypeOf, hasOwnProperty, propertyIsEnumerable, non-enumerable properties Medium Done Done
Prototype chain / Object.create Inheritance, method resolution, for...in inherited enumeration Large Done Done
JSON.stringify / JSON.parse Harness error messages, JSON tests Medium N/A Done
String.prototype methods .length, .charAt(), .slice(), .indexOf() Medium N/A Done
Array.prototype methods .push(), .pop(), .map(), .forEach() Large N/A Done (push/pop/join/indexOf/slice/concat/toString/map/forEach/filter/find/findIndex/some/every/reduce/reduceRight/sort/includes/lastIndexOf/reverse/shift/unshift; splice/flat/fill deferred)
RegExp Regex literal tests, string matching Very Large Done Done (literals, constructor, test, exec, toString, flags, lastIndex, String integration; no function replacers, no matchAll/replaceAll)
Closures over mutable state Counter patterns, module-like scoping Medium Done Partial (no heap-allocated closure env for returned functions)
Symbol, WeakMap, Proxy Advanced ES6+ tests Very Large N/A Done (Symbol with well-known symbols, WeakMap, Proxy with get/set/has/deleteProperty/apply traps)
eval() Direct eval with scope access, indirect eval, strict mode isolation Medium N/A Done

Integration Plan

Phase A: Shim the Harness (after Tier 1) — Done

  1. Add mode = "test262" to the JS262 manifest schema Done
  2. Before running each test, prepend the contents of sta.js and assert.js Done
  3. Map Test262Error exceptions to test failure outcomes Done
  4. ~Vendor a curated subset of 50 basic Test262 tests into tests/external/js262/test262/ Done
  5. Add manifest entries with mode = "test262" and feature tags from Test262 metadata Done

Phase A Results

  • 50 real Test262 tests vendored from tc39/test262
  • 35 pass (70%), 15 known_fail (30%)
  • Feature areas covered: ASI (5), block-scope (20), comments (5), directive-prologue (5), expressions (15)
  • Known-fail breakdown: ASI gaps (2), label syntax (2), function declarations in blocks (2), strict mode (5), other parser gaps (4)
  • New JS feature added during Phase A: function property support (fn.prop = val, fn.prop, fn.method())

Phase B: Expand Coverage (after Tiers 1+2) — Done

  1. ~Vendor 500 tests covering variables, expressions, functions, control flow Done (500 new tests)
  2. Use Test262's features metadata to filter to supported features only Done
  3. Script the manifest generation: parse Test262 YAML frontmatter → TOML entries Done
  4. Track pass rate as a project metric Done (in scripts/metrics.sh)

Phase B Results

  • 550 total real Test262 tests (50 from Phase A + 500 new)
  • 263 pass (47.8%), 287 known_fail (52.2%)
  • Feature areas covered: ASI (25), block-scope (39), comments (15), computed-property-names (18), destructuring (14), directive-prologue (25), expressions (414)
  • Automated triage promoted 155 known_fail tests to pass on first run
  • Updated assert.throws to use instanceof for error type checking
  • ASI implementation promoted 39 tests (16 ASI, 4 comments, 19 expressions)
  • Error constructors (Error, TypeError, ReferenceError, SyntaxError, RangeError, EvalError, URIError) promoted 72 tests
  • New scripts: scripts/curate_test262.py (updated), scripts/triage_test262.py (new)
  • New just commands: curate-test262, triage-test262

Phase C: Full Test262 Integration — Done

  1. Clone tc39/test262 upstream to gitignored tests/external/js262/upstream/ Done
  2. Generate full-suite manifest (js262_full_manifest.toml) from upstream clone Done
  3. Dynamic harness include loading (30+ harness files, not just sta.js/assert.js) Done
  4. Two-tier system: Tier 1 (vendored, PR gate) + Tier 2 (full suite, just test262-full) Done
  5. Automated triage script (just triage-test262-full) Done
  6. ES5.1 subset tracking in metrics Done

Phase C Infrastructure

  • scripts/clone_test262.py — shallow-clones tc39/test262 to upstream/
  • scripts/scan_test262.py — scans upstream, generates full manifest with all qualifying tests
  • scripts/triage_test262_full.py — promotes passing known_fail tests, updates js262_full_status.toml
  • Status overrides: tests/external/js262/js262_full_status.toml (checked in, simple id = "pass" format)
  • New just commands: clone-test262, test262-scan, test262-full, triage-test262-full
  • Full suite is NOT part of just ci / just test — runs separately via just test262-full
  • Target: 90%+ pass rate on ES5.1 subset

Quick Reference: Feature Gap Summary

Blocking Test262 harness (must fix first): this, switch, template literals, string methods / .name / .call(), prototype chain — All done.

Blocking large test coverage: (none — arrow functions now implemented)

Already implemented: var/let/const, if/else, functions (declaration + expression + new), typeof, ===/!==/==/!=, arithmetic, string concat, ! (not), object literals, try/catch/finally, throw, &&/||, string methods (.length, .charAt(), .indexOf(), .slice(), etc.), Function.name, Function.prototype.call(), Object.prototype.toString.call(), for/for...in/for...of/while/do-while loops, break/continue, ++/--, +=/-=/*=/&=/|=/^=/<<=/>>=/>>>=, bitwise operators (&, |, ^, ~, <<, >>, >>>), exponentiation (**, **=), nullish coalescing (??), logical assignment (&&=, ||=, ??=), delete, void, in operator, function properties (fn.prop = val, fn.method()), array literals ([1,2,3]), computed member access (obj[key]), array methods (.push(), .pop(), .join(), .indexOf(), .slice(), .concat(), .map(), .forEach(), .filter(), .find(), .findIndex(), .some(), .every(), .reduce(), .reduceRight(), .sort(), .includes(), .lastIndexOf(), .reverse(), .shift(), .unshift()), Array.isArray(), prototype chain, class declarations (extends, super(), super.method(), static), instanceof, spread/rest ... (arrays, strings, function args/params, object spread), destructuring (array, object, nested, defaults, rest, function params, assignment, for-of/in), ToPrimitive (valueOf/toString coercion with hint), wrapper objects (new Number/String/Boolean), Object.keys/values/entries, Object.create/assign/getPrototypeOf, hasOwnProperty, propertyIsEnumerable, non-enumerable properties, for...in inherited enumeration, Promises, setTimeout, queueMicrotask, DOM bindings, event dispatch, eval() (direct/indirect, scope access, strict mode isolation), Symbol (unique identity, description, well-known symbols: iterator/toPrimitive/hasInstance/toStringTag/species/isConcatSpreadable, Symbol.for()/Symbol.keyFor(), symbol-keyed properties, Object.getOwnPropertySymbols()), WeakMap (get/set/has/delete with object keys), Proxy (get/set/has/deleteProperty/apply traps, Proxy.revocable())

JS262 conformance: 738 tests, 572 pass, 165 known_fail, 1 skip. Test262: 550 vendored, 385 pass (70%) — Phase B complete. See docs/js_conformance_report.md.

See docs/js_feature_matrix.md for the full current feature status.