Commit Graph
32 Commits
Author SHA1 Message Date
Chris Tate 52459a86d4 feat(compiler): lower stored text codec calls (#85)
* feat(compiler): lower stored text codec calls

- Lower same-scope const TextEncoder and TextDecoder call receivers without runtime instances.
- Preserve fences for escaping, captured, and imported codec values with actionable diagnostics.
- Add differential, diagnostic, and preflight baseline coverage for the supported idiom.

* fix(compiler): fence deferred text codec calls

* fix text codec switch-clause TDZ handling
2026-08-02 21:24:33 -05:00
Chris Tate 5ac9dcda3e Fix fetch surface fence coverage 2026-08-01 18:53:02 -05:00
Chris Tate a6a68ea861 fix(fetch): preserve coercion and call semantics 2026-08-01 07:46:54 -05:00
Chris Tate b73decae91 fix(fetch): address stream ownership edge cases 2026-07-30 11:35:00 -05:00
Chris Tate 8790cefbab fix(fetch): address review feedback 2026-07-30 11:35:00 -05:00
Chris Tate dafd7ac647 fix: close static fetch parity gaps 2026-07-30 11:35:00 -05:00
Chris Tate a1dc60d8f0 fix: align fetch and streams with Node.js 2026-07-30 11:35:00 -05:00
Chris Tate f11e51256c feat: make fetch static-compatible
- Add native RequestInit, AbortSignal, and streaming request and response body support.
- Lower the static fetch surface through both C and LLVM without the embedded engine.
- Add differential, Node-typing, sanitizer, and regression coverage.
2026-07-30 11:34:59 -05:00
Chris Tate 9b0ad004f8 Fix top-level await rejection checkpoints 2026-07-29 01:32:26 -05:00
Chris Tate 481dd9c974 fix: flush console output promptly
- Submit console, process, readline, and island writes before returning.
- Add live-pipe and SIGKILL parity coverage against Node 24.
2026-07-26 01:30:42 -05:00
Chris Tate a7538fd87d URL-string and URL-object arguments to the http and https clients
- `http.get("http://host/path")` and its https spelling now compile. The declarations only described the options-record form, so the first thing a from-scratch client writes was a type error — the shape worked under --dynamic, where the engine does not consult our declarations, which is how it read as a hello-world failure.
- A URL object is accepted the same way, as its href through the same parse. An unparsable input is the WHATWG "Invalid URL" TypeError and a scheme that is not the calling module's is ERR_INVALID_PROTOCOL, both catchable, matching Node rather than silently upgrading the dial.
- `request` and `get` take one signature with a union first parameter instead of Node's two overloads: `tls ? https.request : http.request` unions two function types, and resolving a call on that union collapses each side to a single signature, so an overload set misresolves in either declaration order. The lowering dispatches on the argument's own type.
- Both rows run on the LLVM backend, and the tls CA-store entries joined it too — the omission there was stale, so 2557-tls-ca-store moved off the C lane with identical output.
- Corpus 2644 and 2645 cover both schemes against loopback servers, so neither needs the network.
2026-07-24 23:24:53 -05:00
Chris Tate 27e7537cec Crypto introspection, the TLS CA store, and the http2/rejection tail
- The crypto introspection statics (getFips and the cipher/hash/curve name lists) bake at the call site, and the crypto constant table joins http2's under a generalized per-module baked-constants lowering.
- The CA-store introspection surface lands in its own unit (scr_tls_ca.c) behind its own link gate, so a getCACertificates-only binary never pulls mbedTLS: getCACertificates, rootCertificates, setDefaultCACertificates.
- http2.createSecureServer grows the eager request handler and the runtime options record, riding the same server-options walk as tls.createServer; string-typed 'data' listeners decode.
- process once/off for 'unhandledRejection' plus the sibling 'rejectionHandled' registry, removal by closure identity per the warning-registry stance.
- Merge resolution unions this lane with main's fs ladders, createRequire erasure, and dyn secure-context work; the runtime's retired "DOM" nickname is spelled "dyn" throughout.
2026-07-24 19:49:54 -05:00
Chris Tate 2c0f01ad93 HTTP Agent and dynamic-handle compatibility
- Add Agent connection accounting and HTTP/socket compatibility surfaces
- Support dynamic Buffer at and slice access
- Pin behavior with differential corpus coverage
2026-07-24 18:52:19 -05:00
Chris Tate 6c4430e0de Bare 'module' resolves the builtin like node:module
- Node serves the builtin for both spellings, so both key the same lowering tables; the stale prefix-only caution predated the createRequire erasure
2026-07-24 17:18:36 -05:00
Chris Tate e947502af6 The long tail of engine-held values: iteration, promises crossing, and the driver through its plugin pipeline
- for-of, destructuring, and spread over engine-held dyn values ride the engine's own iterator protocol with V8's exact non-iterable spellings; for-of over dyn lowers generally
- Static promises cross into the engine as thenables; Promise.all over mixed and non-literal entries runs the engine's own combinator; engine-array fulfillments exit by reference
- The re-minted silent-wrong-answer path is closed: island-literal members whose values poison fence at the read with the captured diagnostic
- The checked-dynamic tree replaces the old nickname across comments and internal docs
2026-07-24 17:17:00 -05:00
Chris Tate ad3a7a830b Bare 'module' resolves the builtin like node:module
- Node serves the builtin for both spellings — a builtin wins over a same-named npm package for the bare specifier — so both key the same lowering tables
- The stale prefix-only caution predated the createRequire erasure; the hint's claim and the behavior now agree
2026-07-24 15:25:47 -05:00
Chris Tate 07c9a4128c node:stream/consumers compiles statically; createRequire erases to static requires
- text, json, and buffer settle real promises over the readable machinery with Node's settle timing and rejection set; arrayBuffer and blob fence with their representation reasons
- createRequire over this file's URL is compile-time plumbing: builtin specs become namespace imports, relative JSON bakes as validated documents, npm packages ride the require-condition graph, unresolvable names throw Node's catchable MODULE_NOT_FOUND
- module.builtinModules bakes as the compat target's exact list

# Conflicts:
#	packages/compiler/src/frontend/lowering/lower-modules.ts
#	packages/compiler/src/frontend/lowering/lowerer.ts
2026-07-24 12:13:08 -05:00
Chris Tate 6b6445ab90 Retire the "DOM" nickname in comments, internal docs, and message prose: the checked-dynamic tree / dyn values
- The ratified rename rider (world-unification §7 lane 5): "DOM" collided with the browser DOM and, post-lane-1, the structure is no longer a document tree. Comments and doc prose now say "the checked-dynamic tree" for the noun and "dyn" adjectivally; runtime symbol names (scr_dyn_*), the error.domClone libCall, and the real web DOMException family are unchanged.
- The few user-facing strings carrying the nickname move with it (the structuredClone cyclic message, the dc subscriber/publish fences, two emitter ICE texts); diagnostics snapshots regenerated (96 pass). One private compiler constant (DOM_PROTO_METHOD_NAMES -> DYN_PROTO_METHOD_NAMES) rides along.
- Mechanical sweep, 142 files, comments/prose only — no behavior change.
2026-07-24 11:14:58 -05:00
Chris Tate 4abd8e4fff node:module compiles: createRequire's static erasure and the baked builtinModules
- createRequire(import.meta.url) (or __filename / import.meta.filename) in a const binding is compile-time plumbing that emits nothing; each require call through it resolves per site against the binding's own file, and the inline createRequire(import.meta.url)("spec") spelling erases identically
- The erasure per target: a builtin spec makes the binding a namespace import in const clothing (namespace, destructured, and inline-member spellings all key the existing module tables, with the fallback-typed 'as typeof import(...)' cast idiom stripped); a relative .json document validates at compile time and lowers to json.parse over its baked text (JSON.parse's checked-dynamic unknown stance — exactly Node's value); a bare name nothing installed resolves compiles to Node's catchable MODULE_NOT_FOUND throw (the optional-dependency try/require pattern); an installed npm package embeds under --dynamic through the island's NEW require-condition entry (NpmGraphBuilder.addRequire — a dual package answers its CJS arm, exactly Node's createRequire) and reports the requires-dynamic diagnostic in a static build
- Dynamic specifiers, '#' project imports, relative non-.json targets, --npm-static opt-ins, and non-this-file bases all fence by name; the island-handle rescue skips the plumbing decls so --dynamic builds erase them too
- module.builtinModules bakes as Node v24's exact list (a fresh string[] per read, pinned to the compat target so emitted programs stay host-independent); isBuiltin and syncBuiltinESMExports fence per site with pointed hints, and the createRequire hint, its diagnostics snapshot, the surface manifest, and the npm-static offender wording follow
- Corpus 2606 pins json/builtin/builtinModules/MODULE_NOT_FOUND differentially on both backends and under ASan; the npm create-require fixture case pins cjszoo's module.exports, dual's require-condition CJS arm, and the missing-package rejection against Node
2026-07-24 10:32:20 -05:00
Chris Tate 135aec0383 Buffer slice/subarray become true aliasing views; typed arrays gain element fill and Buffer.from(x.buffer)
- scr_bytes_subarray: a same-elem view retaining the owner (the DataView rule, chain depth 1); subarray() and Buffer's slice() lower there, plain typed arrays' slice() keeps the copy — mutations through views are visible both ways now, byte-exactly with Node
- Buffer.from(x.buffer, byteOffset?, length?) lowers as the dataViewNew view construction (the syntactic .buffer peel); the fallback lib gains the ArrayBuffer overload
- fillElem: TypedArray.prototype.fill on non-u8 receivers, per-element coercion with slice-clamped indices; u8 keeps the Buffer fill family
- Both backends emit the new intrinsics; corpus 2604-bytes-views pins aliasing, offset composition, swap-through-slice, clamping, and fill coercion differentially
2026-07-24 09:28:37 -05:00
Chris Tate 417ece6724 node:stream/consumers compiles statically: text, json, and buffer settle real promises
- scr_sc_text/json/buffer accumulate every chunk through a native 'data' listener (string chunks as their utf8 bytes, the Blob rule) and settle at the terminal point through the finished watcher — Node's own eos timing, verified byte-exact including resolution landing after 'close'
- Rejections match Node's set: the stream's error, ERR_STREAM_PREMATURE_CLOSE on an early close, json's SyntaxError on malformed text, and the async-iterable TypeError for a stream with no readable side
- lower-stream's stream/consumers arm lowers text/json/buffer over one lowered stream argument (json answers a checked-dynamic promise — the JSON.parse unknown stance); arrayBuffer and blob fence module-qualified with pointed hints, since neither value has a representation
- Both backends emit sc.text/sc.json/sc.buffer; the trio joins the may-throw seeds, the loop-liveness set, and moduleUsesStream's link gate; the SC1010 hint, its snapshots, and the surface manifest gain stream/consumers
- Corpus 2604/2605 pin the consumers differentially on both backends and under ASan + RC audit: split multibyte sequences across chunks, encoded string-chunk streams, settle ordering, empty streams, and all four rejection arms
2026-07-24 09:27:44 -05:00
Chris Tate 53bad7830e Typed-lane socket compat: pause/resume/setNoDelay/destroySoon, finish, bytesWritten/readable, handle identity ===, Agent type maps to dyn
- the static net.Socket lane gains pause()/resume()/setNoDelay() (chaining, like Node), destroySoon(), on/once('finish'), and the bytesWritten/readable reads — the same runtime entry points the dyn dispatcher uses
- strict equality over runtime handle kinds is pointer identity (c.pause() === c — JS object equality; validator and both backends)
- http/https Agent TYPES map to dyn (the value IS the DOM handle), the stdlib member fence steps aside for dyn-mapped receivers, and ClientRequest joins DYN_HANDLE_KINDS so typed client requests box by reference
- fallback declarations catch up (Socket flow control, the full Agent surface incl. getName/defaultPort/protocol); fixture 2575 pins flavor-independent dyn Buffer at()/slice()
2026-07-23 23:33:20 -05:00
Chris Tate 07961782ef node:stream/promises compiles statically: finished and pipeline settle void promises
- The promise forms ride the callback machinery: scr_sp_finished/scr_sp_pipeline park a settling watcher (fulfilled on a clean finish, rejected with the stream's error or ERR_STREAM_PREMATURE_CLOSE), verified byte-exact against Node including the already-closed async settlement
- lower-stream's stream/promises arm replaces its not-yet fence: finished(stream) and pipeline(...streams) lower to sp.finished/sp.pipeline (stream stages only — the options argument and iterable/generator/function stages keep pointed fences); both specifier spellings and the CJS require forms resolve
- Both backends emit it: the C compound-literal stream list and an LLVM stack array beside the callback pipeline's emission; sp.* joins the may-throw seeds, the loop-liveness set, and moduleUsesStream's link gate
- The SC1010 hint gains stream/promises and the long-missing querystring; hint snapshots and the surface manifest repin
- Corpus 2560/2561/2562 pin pipeline success/error teardown, finished's clean/errored/premature/writable arms, and the CJS destructured-require spelling — green on both backends and under ASan + RC audit
2026-07-23 22:05:28 -05:00
Chris Tate 85ad8eba44 Console prints every inspectable shape; union literals widen per-field
- console.log routes non-scalar arguments through the static inspect machinery
- Union arguments dispatch per arm at runtime; string arms print raw
- Object literals widen per-field into a uniquely-fitting union arm
- The limitations page documents the type surface
2026-07-23 09:14:02 -05:00
Chris Tate 7e8dc0c2cb node:querystring compiles statically
- The full legacy surface: parse, stringify, escape, unescape, the aliases
- Node's scan state machine in C: separators, maxKeys, malformed-escape and truncation quirks
- Link-gated; escape-only programs never link the unit
2026-07-23 09:14:00 -05:00
Chris Tate 9e8904ad3b External-use fixes: performance global, Response surface, n-ary Math, workspaces
- The performance global routes through the perf_hooks lowering in all spellings
- Response declares its implemented headers/arrayBuffer/bytes surface
- Math.max and Math.min lower at any arity
- Copy-installed workspace members classify like symlinked ones
2026-07-23 09:13:00 -05:00
Chris Tate 7bdd40453a node:querystring lowers statically — parse, stringify, escape, unescape
- scr_qs.c ports Node v24's legacy codec quirk-faithfully (the scan state machine with maxKeys' pair budget, unescapeBuffer's code-unit byte truncation with U+FFFD replacement decode, encodeStringified's value rules over the DOM crossing); link-gated by moduleUsesQs, and escape rides the always-linked component encoder
- parse's result is the call site's ParsedUrlQuery dictionary (the networkInterfaces verification stance; the runtime fills the overflow map and groups repeats into string[] buckets), sep/eq/maxKeys complete to Node's defaults, and custom encoder/decoder options fence by name
- decode/encode lower as Node's own aliases; both backends emit the same runtime calls byte-identically
- querystring joins SUPPORTED_BUILTIN_MODULES, the fallback declarations, and the regenerated surface manifest, so npm-static packages requiring it unguarded stop falling back to the island (the shim stays for island code)
- corpus 2460-2464 pin the grammar corners against Node: malformed escapes, '+' vs %2B, repeated keys, maxKeys with empty segments, multi-char/multi-byte separators, astral truncation, and every CJS acquisition spelling
2026-07-23 02:38:44 -05:00
Chris Tate 7c93ab6505 Console prints every inspectable shape with Node's console semantics
- console.log/info/debug/error/warn take unknown[] and render every non-scalar argument through the static util.inspect at the rest-args depth 2, strings verbatim
- top-level unions dispatch per arm at runtime with string arms raw, and util.format's %s/rest args take the same per-arm rule
- info and debug lower as stdout aliases of log; the remaining stock console members are declared in the fallback so stock-clean programs meet per-site SC2020 hints instead of a fallback-manufactured SC0001
- corpus 2440/2441 pin the widened shapes on both backends, console.log(process.argv), a find() miss union, and console.log(undefined) included
- diagnostics snapshots re-pinned: the union console fences retire and utility-types reports its real per-site fences
2026-07-23 01:28:47 -05:00
Chris Tate b5f6b0dc46 Cite patterns, not target projects, across comments and hints
- Lowering rationale names the idiom; one user-facing hint reworded
- Diagnostics snapshot re-pinned to the neutral hint text
2026-07-23 01:18:50 -05:00
Chris Tate 009a24b469 Field redeclares, class destructuring, unknown-field completion, node:module fence
- redeclaring an inherited field WITH an initializer lowers as the [[Define]]-equivalent assignment into the base slot at the subclass's field-init position (builtin Error prefix included — prettier's errors.js `name = "ConfigError"`); bare and type-changing redeclares keep sharpened fences (corpus 2428, diagnostics inheritance re-record)
- object destructuring of CLASS instances desugars to one member read per element, left to right: fields read slots, accessors call getters through the fieldGetExpr dispatch, renames/parameter patterns/defaults included (corpus 2429 — prettier's AstPath { previous, next })
- an object literal missing an 'unknown' field completes with the DOM undefined (the absent-property read's answer), at literal completion and in the record width relation (corpus 2430 — prettier's getFileInfo(file, {}))
- node:module joins the supported builtins prefix-only as an admit-then-fence surface: createRequire keeps a per-member fence that defers to a catchable runtime error in JS sources (diagnostics create-require pins the hint naming the pattern)
2026-07-22 23:48:01 -05:00
Chris Tate 871284a382 Mutable-default snapshots, npm named re-exports, and perf_hooks performance.now
- export default <mutable let> registers Node's snapshot as const storage keyed by the default alias symbol; resolveValueSymbol's default-hop walk stops importer reads there instead of chasing to the live let (corpus 2426 pins the snapshot/live split against export { x as default })
- named re-exports from installed npm packages lower as import-plus-export plumbing: the island load registers at the statement's position and bindings key the aliased symbols direct imports use (npm case npm-reexport covers named, renamed, CJS, and as-default spellings)
- node:perf_hooks joins the supported builtins: performance.now() lowers to scr_perf_now (the uptime anchor's monotonic clock, fractional ms), and performance.now.bind(performance) lowers as a () => number function value (corpus 2427); both backends
2026-07-22 23:21:59 -05:00
Chris Tate 23d5918a53 init 2026-07-22 18:08:04 -05:00