P8 - language modernization - #118
Merged
Merged
Conversation
…e work The decision: do the new language features first, then promote --types into the self-hosted compiler. maam-plan's self-hosting strategy gains the 2026-07-31 addendum with the dist audit that motivates the ordering (zero external requires — the analysis is pure; the ES2022 output's unparseable residue is exactly the language-P3 payoff list plus six stdlib call sites, so language-first turns the phase into build config + an import seam). maam-P5 defines the work items and the stage0-vs-stage1 differential gate; plans.md grows P11 referencing it, ordered after P8, interleaving freely with P9.5/P10. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
test/test262/run-test262.mjs: host-side probe runner over a curated test262 slice (all of language/, 3-per-leaf-dir built-ins sample, harness/) against a staged ejs — frontmatter/includes assembly, negative-test and async semantics, outcome classification, and a per-feature prioritized report. Probe of 26,820 tests @ test262 5ef1e572: 35% pass; the parser is the quantified long pole (44% of the language area fails to parse). New beyond the modernization census: builtin property attributes wrong everywhere (propertyHelper poisoned, ~2.4k tests), 589 JS-reachable runtime aborts that should be TypeErrors, super-in-object-literal EIR lowering error, 352 early-error gaps (regexp validation the mass). Full analysis + language-P3 payoff ordering in docs/language-p1-results.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All parse entry points (gather-imports parseFile, eir unit tests) now go through lib/parser.ts. The contract is the ESTree dialect in lib/estree.ts; the parser behind the seam becomes swappable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Running acorn under the self-hosted compiler exposed five runtime bugs,
all pre-existing:
- RegExp: pcre16_compile failures were silently ignored, leaving a NULL
compiled_pattern that matched anything (acorn's lineBreak regex with
\u2028 hit this). Now: PCRE_JAVASCRIPT_COMPAT (\uXXXX escapes), a
loud SyntaxError on compile failure, and UTF-16 mode only under /u --
non-u patterns match per code unit and may contain lone surrogates
(parser identifier tables; PCRE_UTF16 rejects those outright).
- String.prototype.indexOf ignored fromIndex (acorn's block-comment
scanner loops forever: indexOf('*/', pos) returned an earlier match
and the cursor moved backward). lastIndexOf same, now a bounded
reverse search.
- utf8_to_ucs2 had no 4-byte branch: 0xF0 leads fell into the 3-byte
case (0xF0 & 0xE0 == 0xE0), decoded garbage, and the leftover
continuation byte truncated the rest of the string. Astral chars in
a file ate everything after them. Now decodes code points and emits
surrogate pairs.
- JSON.stringify hex escapes used hexdigits table "012356789abcdef" --
missing the 4; every digit >= 4 was off by one (\u000b printed as
\u000c).
- String.fromCharCode used the NUL-terminated string constructor, so
fromCharCode(0) built a zero-length string.
With these, acorn's ES5 bundle compiled by stage1 parses the entire
srcdir+test corpus (537 files) byte-identically to acorn under node.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The upstream flat ESM bundle transpiled to ES5-level syntax (regen.sh, pinned versions) so stage1+ can self-compile it. A generated artifact, not a forked submodule. Wired into //external-deps:compiler-js and the stage0 CommonJS conversion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… gates
lib/parser.ts now defaults to acorn (ecmaVersion latest, standard
ESTree) and adapts to the compiler dialect in the seam:
- top-level parameter AssignmentPatterns hoist to the aligned defaults
array (nested pattern defaults stay in place, matching the fork)
- TryStatement grows handlers[] / guardedHandlers
- MetaProperty meta/property flatten to raw names
Everything acorn parses but the backend cannot lower yet dies at the
seam with a located error instead of miscompiling silently (the census
'async m() {}' hazard class): async/await, for await, class fields /
private members / static blocks, object spread, optional chaining,
??/**/logical-assignment operators, BigInt literals, dynamic import(),
import.meta, catch without binding. language-P3 removes gates as
features land.
--parser esprima keeps the pre-P2 fork reachable for bisection.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
generator5 (kangax generator value-sending) un-xfailed: it passes under acorn. Matrix all lanes 426/20/0, test-eir 227, lowtier green, corpus AST-identity acorn-under-stage1 == acorn-under-node (537 files). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… class fields/private, async/await Deletes the P8.2 unsupported-syntax gates in payoff order: - ** / **= as a real generic binop (EIR `exp` op, _ejs_op_exp; _ejs_number_exponentiate shared with Math.pow for the C-pow spec edges) - ?? lowered natively in EIR's logical() (loose_eq-null nullish test) - logical assignment + optional chaining: DesugarModernOps (new pass, runs first; arrow-IIFE desugars keep this/arguments/super lexical) - object spread (CopyDataProperties + descriptor-preserving chunk merge runtime helpers) and object rest (exclusion lists, computed keys evaluated once); catch without a binding (adapter-synthesized param) - class fields, private members, static blocks: DesugarClasses grows a private-scope stack; fields init via per-class %initFields closures (base: ctor top; derived: after each super()), computed keys evaluate at class-definition time, #names are per-name weakmaps + a brand map with checked C accessors (real TypeErrors, runtime-thrown for private-method writes so logical assignment can short-circuit past), static fields/blocks run in order via %initStatics - async/await: DesugarAsyncFunctions rewrites async bodies to the coroutine generators (await -> yield) driven by a per-wrapper __ejs_asyncDrive promise stepper; async methods/arrows covered; `for await` lowers to the async-iteration protocol with the async-from-sync fallback; Symbol.asyncIterator added. async generator functions stay gated. Eight pre-existing bugs flushed out and fixed: super.other() dispatched via the enclosing method's key (miscompile as old as classes), DesugarGeneratorFunctions popped its %gen mapping for every nested function, Promise.all's resolve-element had been an #if-notyet stub since 2015 (shared remaining-count record now), array/string OwnPropertyKeys/GetOwnProperty were map-only (elements invisible to Reflect-style consumers; holes reported as own; index descriptors lacked attributes), array DefineOwnProperty clobbered elements/length on attribute-only defines (freeze emptied template callsites), ToEJSBool aborted on symbols and called NaN truthy, String(symbol) aborted, and class methods/accessors were defined non-writable/non-configurable. test262 probe runner: shim print() for async tests (doneprintHandle reports through it; echojs has no print global). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
12 files, node-generated expected-outs through the value harness: exponentiation1, nullish1, optchain1, logical-assign1, object-spread1, object-rest1, catch-binding1, class-fields1, class-private1, class-static1, async1, for-await1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ticks Matrix 438/20/0 at stage0-3 + shapes-off, test-eir 227, lowtier OK. test262 area probes: class elements 26%->71%, async functions 7-14%-> 76-82%, optional chaining 13->25 of 38, for-await 387/1234 (residue is the async-generator gate). Numbers and follow-ons in docs/language-p3-results.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comments describe the code, not the plan history: the gc-P*/runtime-P*/ compiler-P*/sinking-P*/shapes-P*/language-P* call-outs (including the ones the language work just added on its bug fixes) reword to what the comment was actually saying, or drop where the phase id was the whole parenthetical. Also covers two test labels, the xfail reason strings, and the --parser help text. Phase ids remain where they belong: the plan and results docs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-through on the phase-id sweep: "used to", "the old X",
"pre-existing", "found by/found the hard way", "long-standing", "since
2015" and friends go stale the same way phase ids do. Comments now
state the invariant or rationale in the present tense ("writing
n.body.body here would clobber ...", "an unconditional shift would let
..."), and pure war-story parentheticals are dropped. Present-tense
uses stay: algorithmic state ("no longer reachable from entry"), GC
generation terms ("the old gen"), the live shape census, and spec
quotations. The parser-seam gate examples update to the currently
gated set (async generators, BigInt, dynamic import()).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
test/test262/lane.sh runs a fixed curated selection (every 6th language test, 2 per built-ins leaf dir, all of harness — 6,121 tests) against the suite SHA pinned in suite.sha, checked against the checked-in expectations.txt. Regressions (expected-pass test failing) and stale expectations (expected-fail test passing) both fail the run, so the file only shrinks — a conformance ratchet. Runs in the macOS bootstrap job after the stage ladder. Runner: --stride-language proportional sampling, --expectations / --update-expectations (membership-checked; `skip` lines mark environment-sensitive tests; harness-error is never baselined). Baseline at suite b363f29d: 2,584/5,977 pass (43%), 3,393 expected failures, verified deterministic across two full runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Async generators (async function*) land on the coroutine generators:
the body becomes a sync generator speaking a marker protocol (awaits
and yields become marked yields), driven by a per-wrapper
__ejs_asyncGenDrive that queues next/throw/return requests and settles
each with a promised iterator result; yield* delegates through a sync
relay generator whose marked yields pass through untouched. Parser
gate deleted.
Pre-existing bugs fixed along the way:
- yield* was statement-position-only and dropped both the delegated
return value and sent-value forwarding; now a delegation-helper call
(valid in any expression position — the coroutine stack lets the
helper yield from a nested frame) with IteratorClose on abrupt exit.
- for-in over objects with private fields aborted in
_ejs_primstring_flatten: the weak-collection inverted-rep slot is
symbol-keyed and key collection flattened it as a string. for-in now
skips non-string keys; the slot is non-enumerable (it also leaked
into object spread).
- Function .length did not exist on any function; the parser records
spec length before desugars rewrite params, make_closure carries it,
compiled closures define it via _ejs_function_new_closure. (Builtin
lengths are a separate sweep.)
- Function .name: NamedEvaluation (declarators, assignments,
properties, defaults), class methods ("A:m" internal id -> "m"),
private methods ("#m") via ejs_display_name.
- Destructuring gaps: nested patterns under rest, member-expression
targets, rest-pattern formals, elision in assignment position
(emitted assignments to undeclared temps).
- globalThis added; hasOwnProperty does ToObject(this) instead of
aborting on undefined receivers.
- Uncaught exceptions print ToString of the thrown value (the throw
path stashes it for the terminate handler); previously blank.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
generator26.js pins value-position yield*, sent-value forwarding, the delegated return value, nested delegation, and inner-iterator close on gen.return(); async-generator1.js pins the async-generator protocol (awaits, delegation over async+sync sources, queued nexts, throw/ return, class/object methods, self-asyncIterator). generator15/16 drop their xfail — yield* iterator closing works now. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Results doc + plan ticks; test/test262/expectations.txt regenerated against the fixed compiler: 3,393 -> 2,781 expected failures (612 tests flipped to passing, zero newly failing), lane pass rate 43% -> 53%. Headline areas: class/elements 71% -> 90/91%, for-await-of 31% -> 90%, async-generator 0 (gated) -> 63%. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The buy in the BigInt buy-vs-build (docs/bigint-plan.md): V8's src/bigint is a JS engine's BigInt core deliberately factored for reuse — its DEPS file forbids depending on anything outside the directory, internals include only std headers, and the caller- preallocated RWDigits convention lets our GC cells own their digits inline. BSD-licensed; extraction is a plain file copy (external-deps/v8-bigint/regen.sh pins the commit). Built as a C++20 static library with the advanced algorithms (Toom-Cook/FFT multiplication, Barrett division) enabled. Alternatives surveyed in the plan doc: libtommath (the Unlicense C fallback), libbf (QuickJS moved off it for BigInt), imath, GMP (LGPL-blocked), and building our own (division/radix correctness risk argued against). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The BigInt primitive over the vendored v8-bigint library:
- New EJSVAL_TYPE_BIGINT tag (0x09); OBJECT moves to 0x0A — it must
stay the maximum tag (the 64-bit IS_OBJECT is a >= compare on the
shifted tag; the emitter's mirrored isObject constant updated for
both word sizes). EJSBigInt cells are GC leaves (EJS_SCAN_TYPE_
BIGINT): sign + inline little-endian digits, relocatable, no
finalizer, no satellite allocation — results are computed directly
into freshly allocated cells via the library's caller-preallocates
convention (runtime/ejs-bigint.cpp, the echo-dtoa pattern, merged
into libecho.a).
- Full ES2020 operator semantics in ejs-ops.c: ToNumeric split on
every arithmetic/bitwise op (mixing BigInt with anything else is a
TypeError), mixed-type relationals and loose equality (numbers,
strings via StringToBigInt), strict-eq/SameValue by value, typeof
"bigint", ToString/ToEJSBool/ToObject(wrapper), unary + and >>>
reject bigints, Number(bigint) converts (the one ToNumber caller
that does), JSON.stringify TypeError, console prints 123n.
- BigInt()/asIntN/asUintN (ToIndex semantics)/prototype
{toString(radix), toLocaleString, valueOf, @@toStringTag}.
- Literals: the parser adapter transmutes Literal{bigint} nodes into
%bigintFromLiteral("<digits>") intrinsic calls (acorn's .value is
null under the self-hosted parse; separators stripped at runtime).
Parser gate deleted.
- Optimizer soundness: the "result is always Number" assumptions
(cleanup.ts NUMBER_RESULT, optimize-guards) are false under BigInt.
Replaced with the one-proven-number-operand rule — mixing throws,
so an op that completes with a number operand produced a number —
keeping every existing lattice fold and guard elision (the hypot2
eir tests now pin the slow-path add staying generic: it may
legally add two bigints).
- ++/-- lower as to_numeric (new op; bigints pass through, folds
mirror unary_plus) + add/sub carrying an `update` imm routed to
_ejs_op_add_update/_ejs_op_sub_update in generic emission — BigInt
increments stay in-type while typed paths see the ordinary ops.
Gates: full matrix green (test-eir, lowtier, stage0-3 incl. the
stage2/3 fixed point and shapes-off; the compiler self-compiles under
the renumbered tags); test/bigint{1,2}.js byte-identical to node.
test262 built-ins/BigInt 77% (residue: builtin length/name attribute
gap, isConstructor-on-builtins — both global pre-existing — and $262
realm tests).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
test/bigint{1,2}.js pin the whole surface against node byte-for-byte:
literals in every radix (+separators), arithmetic/pow/div-mod signs
and errors, two's-complement bitwise and shifts, mixed comparisons and
loose equality, BigInt()/asIntN/asUintN edges, toString(radix),
increments, truthiness, the mixing/JSON TypeErrors, wrappers.
Lane expectations regenerated: 2,781 -> 2,735 expected failures, pass
rate 53% -> 54% (BigInt gates flipped; three compile-timeout flakes
from a concurrent build re-verified passing and excluded). Plan ticks
note the P4.2 turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Measured 2026-07-31 by compiling maam's ES-module tsc output with stage1: the ES2022 syntax surface is covered (all 22 modules lower clean; the smoke reaches makeMachine), so the prereqs are module plumbing (export * / export * as ns, .js-suffixed specifiers — the skip-module root cause), 14 probe-verified stdlib methods, the NUL-in-source read truncation, and the maam ⊤-operand arithmetic soundness fix now that BigInt exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…piles
Everything the self-hosted type oracle needs from the language and
runtime, plus four pre-existing bugs the stage0-vs-stage1 differential
gate flushed.
Module system:
- `export * from` and `export * as ns from`: gather-imports records
star nodes and expands them post-gather to concrete exports via a
fixpoint (chains work; explicit local exports shadow star names; a
name reaching a module through two stars is exported only when both
resolve to the same original export, else dropped with a warning).
Lowering copies the source module's slots (the `export {a} from`
snapshot semantics); `export * as ns` stores the source module's
namespace object into the slot, and member reads on it resolve at
runtime through the export accessors.
- `.js`-suffixed relative specifiers (NodeNext output style) key the
same module as the suffix-free form — the test262 skip-module /
_FIXTURE.js root cause.
Standard library: Object.{entries, values, fromEntries, hasOwn},
Array.prototype.{includes, at, flat, flatMap, findLast},
String.prototype.{at, padStart, padEnd, trimStart, trimEnd,
replaceAll} — spec-shaped, correct .lengths, 14 new test files.
Gate-flushed fixes (each invisible until the identical maam analysis
ran under both hosts):
- generateEJSValueForString re-resolved the just-created literal
global BY NAME; LLVM names are NUL-terminated C strings, so literals
differing only past an embedded U+0000 fused into one constant.
- SameValue, SameValueZero (Map/Set membership), strict/loose string
equality and the relational operators compared flat strings with the
C-string ucs2_strcmp, stopping at the first NUL; new length-aware
ucs2_strcmp_len at all seven ejs-ops.c sites.
- _ejs_string_new_utf8_len treated U+0000 as end-of-input (source
files truncated at a raw NUL — "unterminated template") and
advanced its byte count once per code point.
- emitEjsvalFromPtr still OR'd the pre-BigInt SHIFTED_TAG_OBJECT
(0xFFFC…) after OBJECT moved to 0x0A (0xFFFD…): module namespace
objects were mistagged, invisible while every member read was
compile-time-resolved.
- Array.prototype.every returned false only for literal false; any
other falsy callback result passed the predicate (ToBoolean now).
- String.prototype.replace dropped the tail when a match ended at
index len-1, and `$` + backtick (before-match) substitution was
missing.
Tests: exportall1/2, jsimport1, nulsource1 (a raw NUL byte in a string
literal), nulstring1 (NUL-embedded equality/Map/Set), array-every1,
object-values1, and the stdlib suites. Gates: full matrix green
(test-eir, lowtier, stage0-3, shapes-off), tsc clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
--types works in the shipped compiler (plans P11.1). The seam is ONE static import: lib/eir/oracle.ts imports `$maam` (ambient surface in lib/maam.d.ts, structural narrowing unchanged); the __dirname-walk lazy require() is gone. The self-compile resolves it with -I maam=<tree>/external-deps/echojs-maam/dist/src/index (buck-stage.sh) to maam's ESM build, which gather-imports compiles in; the stage0 CJS conversion seds the specifier to the CJS build staged into the generated tree (buck-gen-js.sh). Both builds come from emit-only tsc genrules over the submodule src (//external-deps:maam-esm/:maam-cjs — staging maam's package.json matters: without its "type": "module", tsc's NodeNext mode silently emits CommonJS). The analysis itself still runs only under --types; flag-off compiles pay module-load cost only. buck-test-types-diff.sh grows a host-vs-host mode (4th arg = stage1+ exe): every test compiled --types --types-dump by BOTH hosts; the normalized analysis stderr AND the run stdout must match. Lane run: 520 files, 516 identical, 0 divergent (the 4 giant esprima/typedarray files exceed the 120s per-file cap under the self-hosted compiler; verified identical with a longer leash). --types-dump binding sorts switched to code-point order (localeCompare is host collation). maam submodule @c4942c0: the ⊤-operand soundness fix (one-proven- number-operand rule), exact concrete bigint evaluation, visibly- degraded async/generator modeling, bigint/async corpus, TS7 toolchain, and an emptied ejs-known-divergences.json — the ejs lane verified all seven 2026-07-23 entries fixed (runtime-P1) and now runs 51/51 OK. Gates: full bootstrap matrix green, the types lane above, maam typecheck + 274 tests + diff-harness GATE PASS, and the README's source-checkout-only caveat deleted. docs/maam-p5-results.md records the phase. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The test262 CI lane climbs 3260->4489 of 5977 (54.5% -> 75.1%); expectations.txt ratchets 2735 -> 1488. Repo suite grows to 466 green (object7/object9/tostring5 un-xfailed — their behaviors are now spec). Runtime, attributes and semantics: - every builtin function gets own .name (configurable) and .length; spec arities stamped from a generated table (runtime/ejs-builtin-arities.h) applied at end of init - plain install macros define non-enumerable properties; Math/Number constants, global undefined/NaN/Infinity, constructor .prototype all carry spec attributes - builtin methods are no longer constructors (CONSTRUCTOR_KIND_NONE; Array keeps its self-allocating construct path via a named kind); bound functions construct through their target - runtime aborts become TypeErrors: Construct on non-constructors, setprop on primitives, Reflect.defineProperty/deleteProperty (now implemented), Object.create/setPrototypeOf/defineProperties, Function.prototype.apply; ToObject null/undefined messages fixed - unresolvable reads/writes throw ReferenceError; typeof keeps the non-throwing global load (get_global for_typeof imm) - strict mode threaded through the compiler (FnInfo.strict, directive prologue scan skips hoisted decls): strict set_global / member stores / delete throw per PutValue - property descriptors: stored properties are complete (absent fields default), FromPropertyDescriptor emits [[Set]] (was gated on [[Get]] — setter-only accessors were invisible) - SameValue/SameValueZero handle symbols; `in` uses ToPropertyKey; IteratorWrapper propagates next/value throws and IteratorClose runs on normal destructuring completion; RequireObjectCoercible guards empty object patterns - generator/async-generator parameter destructuring throws at call time (prologue hoisted out of the deferred body) - async generators join a real %AsyncGeneratorFunction% / %AsyncGeneratorPrototype% / %AsyncIteratorPrototype% chain (%markAsyncGen at each definition) - NamedEvaluation covers anonymous classes (no more %anonClass_N in .name); BigInt literal property keys name by decimal value - toplevel `this` is the global object (script semantics) New surface: Date rewritten to a [[DateValue]] double (full getter/ setter/toISOString/parse/UTC API — it had three methods), BigInt64/ BigUint64Array, DataView spec checks, %TypedArray%.prototype filled out (iterators, copy methods, sort, toLocaleString, prototype getters, constructor-from-iterable/array-like), Array toReversed/toSorted/ toSpliced/with, Set methods (union et al), Iterator + iterator helpers, SharedArrayBuffer + single-agent Atomics, DisposableStack/ AsyncDisposableStack/SuppressedError, FinalizationRegistry, WeakRef, AggregateError, Error.isError + cause, Map/WeakMap getOrInsert(, Computed) + groupBy + WeakMap symbol keys, String isWellFormed/ toWellFormed, Math f16round/sumPrecise + missing constants, JSON rawJSON/isRawJSON + real parse SyntaxErrors, arguments-object property-map semantics (define/delete/descriptors), Uint8Clamped correct clamping, array holes fall through to the prototype chain, accessors on array indices, new Array(n) holes (was reading zeros). Test harness: the runner grows a partial $262 (detachArrayBuffer via __ejs.detachArrayBuffer over a real detached flag, gc) and publishes $DONE on globalThis for async tests. Carve-outs recorded in expectations: Temporal, eval/Function constructor, $262.createRealm/evalScript/agent, dynamic import, module-flagged tests (runner skips), mapped-arguments aliasing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… await
Programs now compile under the ECMAScript Module goal: every toplevel
is strict and toplevel `this` is undefined. The new `--script` flag
restores script-goal semantics (sloppy toplevel unless a "use strict"
directive, `this` = globalThis). Parsing uses the module grammar
either way — the goal is a semantics switch (CompilerOptions.script ->
analyzeToplevel strictness + mod_ctx.script for toplevel `this`).
Landed alongside, since the flip exposed them:
- top-level await: a module toplevel containing `await` (or toplevel
for-await) becomes an async function via the existing async desugar;
module resolution gets a promise and the runloop drives the
continuations. The toplevel promise's rejection routes to
__ejs.unhandledException so a failed await exits nonzero.
- node-visitor now visits computed MethodDefinition keys (no pass saw
them before — surfaced by `class { [await x]() {} }`).
- class bodies are strict (10.2.1): the class desugar stamps its IIFE
ejs_strict, which every synthesized class function inherits.
- sloppy-mode `this` coercion (9.2.1.2): functions that read `this` in
sloppy code coerce null/undefined receivers to the global object at
entry. Strict code — i.e. everything under the module default —
emits nothing.
- async-generator declarations' instances now sit on the spec chain
(driver objects are Object.create(fn.prototype)).
- process.env is mutable (node parity; its non-writable entries made
the driver's PATH prepend a silent no-op, which strict mode turned
into a crash).
test262 runner: unflagged tests compile with --script; flags:[module]
tests use the module default with sibling *_FIXTURE.js files staged
next to the source (kept under their original basename so
self-imports resolve); negative resolution-phase tests expect
compile-time failure; captured child output is capped so runaway
tests can't overflow the collector. The 142 formerly-skipped module
tests now run: lane 4575/6119 (74.8% on the grown denominator; 75.5%
on the previous non-module basis), expectations regenerated at 1544.
Repo tester passes --script (its node baselines run under CJS
require, i.e. script semantics). Suite 466 green under stage1 AND
stage2; stage3 builds — the compiler bootstraps as strict module code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The array-pattern desugar now emits wrapper.close() for the normal-completion IteratorClose; the literal-walk fold's use discipline rejected the two extra wrapper uses, so destructuring over literals stopped dissolving to pure SSA (test-eir's two destructuring fold tests, red on CI for macos-arm64/linux-arm64). IteratorClose on a literal's exhausted array iterator is a no-op — there is no return method — so the fold accepts exactly the getNextValue pairs plus close pairs, folds the close call to undefined, and removes both getters with the wrapper. Full local matrix green: test-eir + test-stage0..3. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The 0.1.0 release happened in 2011, back in the ES5 days. 0.2.0 brought us forward in most areas, but not language version. This PR does that.
Also add a
--scriptcommand line flag to toggle strict mode (the default) to sloppy at the toplevel.We now pass 74.8% of test262 (previously was 54.5%). The increased language support means we can run the static analysis in stage2/3, which is awesome.
Fable's output below:
How it went: I clustered the ~2,700 baseline failures by normalized error message rather than feature tag, which exposed a handful of choke points, then worked them in three waves (with 8 parallel subagents on disjoint runtime files, serialized through a buck2 lock):
What's left (recorded in expectations as carve-outs): Temporal (~486 tests, the single biggest future lever), eval/new Function, $262.createRealm, dynamic import, and mapped-arguments aliasing.