Commit Graph
276 Commits
Author SHA1 Message Date
Chris Tate 6d521671df Fix Windows cross-target CLI setup 2026-07-26 17:25:37 -05:00
Chris Tate eed983cdad Fix Windows CLI smoke toolchain 2026-07-26 16:08:30 -05:00
Chris Tate 50b135de8d Fix workspace build on Windows 2026-07-26 16:01:30 -05:00
Chris TateandKhaled Ghallab d7b5891b4f Fix scriptc run on Windows
- Normalize Windows paths passed through the TS7 virtual filesystem.
- Emit and launch .exe outputs by default on Windows.
- Add targeted regressions and a Windows GitHub Actions smoke test.

Co-authored-by: Khaled Ghallab <171967089+Khaled-Ghallab@users.noreply.github.com>
2026-07-26 15:50:38 -05:00
Chris Tate 4b2c775965 Merge pull request #9 from vercel-labs/ctate/v0.0.16
Prepare v0.0.16 release
v0.0.16
2026-07-26 10:31:44 -05:00
Chris Tate aacfc4cbf0 Prepare v0.0.16 release
- Synchronize package versions and regenerate the compiler surface manifest.
- Publish release notes for prompt output flushing and Linux host clang builds.
2026-07-26 10:22:45 -05:00
Chris Tate 2a27b91cfc Merge pull request #8 from vercel-labs/ctate/fix-linux
Fix Linux host clang static builds
2026-07-26 09:44:39 -05:00
8f131ae312 Fix Linux host clang static builds
- Add glibc feature visibility and trailing libm linkage.
- Gate native host clang builds with regression coverage and Ubuntu CI.

Co-authored-by: farangkao <7920378+farangkao@users.noreply.github.com>
Co-authored-by: Swadhin Biswas <107450069+swadhinbiswas@users.noreply.github.com>
2026-07-26 09:36:46 -05:00
Chris Tate 0e83e70baf Merge pull request #4 from vercel-labs/ctate/console-log
fix: flush console output promptly
2026-07-26 08:50:45 -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 84e0b052b8 Merge pull request #2 from vercel-labs/ctate/v0.0.15
chore: release v0.0.15
v0.0.15
2026-07-25 12:57:38 -05:00
Chris Tate 3817e74e74 chore: release v0.0.15
- Bump all published packages to 0.0.15 and refresh the surface manifest.
- Promote the outbound native FFI notes into the marked release block.
- Verify the workspace build plus plain and sanitized full test lanes.
2026-07-25 12:48:14 -05:00
Chris Tate 13c1229ddf Merge pull request #1 from vercel-labs/ctate/outbound-ffi
feat: add outbound native FFI
2026-07-25 12:22:21 -05:00
Chris Tate 1a5bc86bc9 fix: harden outbound FFI validation 2026-07-25 11:52:55 -05:00
Chris Tate 2098e0df6d fix: validate unused FFI bindings 2026-07-25 10:57:54 -05:00
Chris Tate bed63d3223 feat: add outbound native FFI
- Add a strict versioned manifest and direct C ABI lowering for both backends.
- Link declared native inputs through the CLI and compiler APIs with precise diagnostics.
- Cover the ABI under plain and sanitized integration tests and document its contracts.
2026-07-25 09:56:48 -05:00
Chris Tate ee1f8697b8 Release 0.0.14 v0.0.14 2026-07-24 23:30:35 -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 46643230d8 Resolve hostnames at the client dial
- http, https, TLS and HTTP/2 clients now resolve the hostname before connecting. A client that dialed by name got ENOTFOUND regardless of the name — only literal addresses worked, which is most of what a from-scratch client writes.
- Only the dial takes the address. The original name stays on the request, which is what the Host header carries and what SNI and certificate verification see, so a resolved dial does not weaken the TLS check.
- node:net's own connect surface stays resolver-less: Node's async lookup semantics there are a separate piece of work, so `net.connect(port, hostname)` still refuses to resolve.
2026-07-24 23:24:41 -05:00
Chris Tate 701e2795a1 CLI: -v, and argument errors that read as errors
- `scriptc -v` / `--version` prints the installed version, read from the package manifest so a release build and a source checkout answer the same way. It previously fell through to the compile path and crashed trying to read `-v` as an entry file.
- An unknown flag or a missing flag value now prints one line naming what was wrong, followed by usage. parseArgs' ERR_PARSE_ARGS_* used to escape to the top level and paint a Node stack trace over the terminal.
- Reworded `--backend` help: llvm is the default and the output that ships, c is the readable reference backend for inspecting what the compiler produced.
2026-07-24 23:23:58 -05:00
Chris Tate 91245d659f Release 0.0.13 v0.0.13 2026-07-24 21:20:01 -05:00
Chris Tate 6345fabfcb Retag || on the truthy side instead of coercing the left
- tsc builds `u || d`'s result by DROPPING the left's falsy arms (`process.env.X || null` is `string | null`, `|| 3000` is `string | number`), so coercing the left into that result before the truthiness test retags an arm the test is about to rule out — and threw where Node yields the default.
- `orDefault` gains an optional `retag`: the truthy side hands the whole left box to a union→union helper whose stranded-arm throw is unreachable by construction, since truthiness has already ruled those arms out. Left evaluates once, right stays lazy, arm count is free.
- A ternary in logical-left position no longer adopts its contextual union over its own, for the same reason the eager coercion was wrong: tsc's assignability proof does not hold for that operand. Narrow to the union choice — contextual array element typing and the unmappable-own rescue are untouched.
- 2595 chained its two in-flight `fs.exists` stats: registering both after the awaited rejections orders them against the rejections, not against each other, and Node itself returns them reversed about one run in forty.
2026-07-24 21:15:53 -05:00
Chris Tate abdf858f5a Fence the CA store and record the two lanes' order baselines
- The CA-store surfaces (tlsca.get/root/set) demote the determinism attestation but no fence could deny them: three AMBIENT_SURFACE_FNS rows, one per Node spelling. Split rather than folded into a single "CA store" surface — an author who denies REPLACING the trust anchors is making a different decision from one who denies reading them, and rootCertificates is a value read with no call form to hang a table row on.
- The parity test's full-fence declaration set names the new node-builtin.tls. family; surface-manifest.json regenerated.
- Order-parity baselines for the seven fixtures the two lanes added (2556-2558, 2582-2585). Pure insertions: no recorded baseline moved.
2026-07-24 20:15:42 -05:00
Chris Tate 44d05d8e74 Route the compiler's dyn world onto the engine's own operations
- Island values held in `unknown` arm the routed operation set (SCR_DYN_JSVAL): keyed reads and writes, calls and method dispatch, Object statics, and `??` all run in the engine, so a wrapped value answers exactly what Node answers instead of meeting a fence.
- Scalars normalize at the wrap, composites stay engine values by reference, and the round trip preserves identity — a value that crosses into the checked-dynamic tree and back is the same engine value.
- deepStrictEqual over a mixed engine-vs-native pair fails with the reason stated rather than guessing at an answer.
- Corpus 2582–2585 and an npm routed-row fixture pin the behavior; the dyncheck expectations move with it.
- The retired "DOM" nickname is swept out of the sources and corpus in the same pass (29 comment sites) — the world is the checked-dynamic tree, its values are dyn values.
2026-07-24 19:53:10 -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 24fb359586 Record order-parity baselines for HTTP compatibility fixtures
- Add the five renumbered HTTP and dynamic-handle corpus entries
- Preserve every previously recorded baseline unchanged
2026-07-24 19:26:18 -05:00
Chris Tate ebba5fcea9 Regenerate options-record diagnostics snapshot
- Record the merged Agent lowering diagnostics exactly
2026-07-24 19:04:09 -05:00
Chris Tate 91770d59d1 Cross-target library conformance
- Include the Windows runtime unit in library archives
- Add opt-in library target-matrix conformance coverage
- Exercise both emission paths across supported desktop targets
2026-07-24 18:52:29 -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 3a7286b7f1 Repair the changelog: the release-cut script tripped over a duplicated merge region
- The narrowing lane's changelog merge duplicated the whole file; the cut script's insert then failed to match
- One copy, an empty Unreleased, the 0.0.12 entry carrying the lane's fixes bullets, markers on the latest release only
v0.0.12
2026-07-24 18:26:41 -05:00
Chris Tate 6ce1a44c80 Release 0.0.12 2026-07-24 18:23:39 -05:00
Chris Tate 9ac1d1ea6b Cross-target conformance lane for library mode (SCRIPTC_CROSS=1)
- Every K-fixture library profile cross-builds through compileLibrary for aarch64-linux-gnu.2.36, x86_64-linux-gnu.2.36, x86_64-windows-gnu, and x86_64-macos, both emissions — 112 archives, ~2min warm, which plus the hard zig requirement is why the lane is env-gated like its linux/windows siblings
- Per archive on the host: K1 symbol exactness against the profile's declared set (Apple's nm is llvm-nm and reads ELF/COFF/Mach-O alike; Mach-O's underscore is the only decoration), the K8 ambient audit in bare and COFF-dllimport spellings, and probe LINKABILITY against the target's libc plus the documented win32 embedder libs
- K2 execution probes ride the existing infrastructure gates: SCRIPTC_LINUX=1 runs the scalar round-trip per linux triple in the bookworm container, SCRIPTC_WIN=1 ships it to the box over scp and folds the mingw CRT's text-mode CRLF back on that one leg
- x86_64-macos stays build-only by contract; the probe runs as a bonus when Rosetta is detected
- README documents the fifth lane beside the linux/windows differentials
2026-07-24 18:22:45 -05:00
Chris Tate 43ba74ce15 Library archives compile the win32 libc shim TU for windows triples
- compileLibArchive now mirrors compileC's win32 arm: scr_win.c joins the archive's object list for x86_64-windows-gnu, providing stpcpy and arc4random_buf (scr_number.c, scr_lib.c, and scr_bytes_io.c call them; mingw's CRT has neither)
- Without it every win32 library archive carried undefined refs no embedder link could resolve — caught by the cross-target library lane's probe links on its first run
- The system-DLL imports (advapi32's CSPRNG/GetUserNameA, iphlpapi's GetAdaptersAddresses, ws2_32's inet_ntop/htonl) stay the embedder's link line: an archive carries no -l flags
- Host archives cannot change by a byte: the TU is gated on targetPlatform(driver) === "win32" and is an empty TU elsewhere anyway
2026-07-24 18:22:34 -05:00
Chris Tate b3752bb181 Integer attestations keep their declared class; model-slot writes enter the boundary check
- integer_slots records u64 as u64: the wire flattening narrows to the frozen TypeRef spellings where it belongs
- Declaring any integer slot force-lowers the designated init, update, and subscription exports, so every model-field write proves or refuses like an export slot; declared field reads seed their class shapes
- Export integer classes stay attested by the emitted C signature under the same gate — the sidecar list is the document-side complement, and its refusal message now says so
2026-07-24 18:00:49 -05:00
Chris Tate 5e5d5bf8a9 Record declared u64 classes in the sidecar attestation and prove model/msg slot writes
- integer_slots now records each slot's DECLARED class ({i64, u64}); the i64 flattening narrows to the frozen format-1 TypeRef/descriptor spellings where unsigned-ness genuinely has no vocabulary, and the V1 self-check accepts both classes
- library builds declaring sidecar integer slots force-lower the designated init/update/subscriptions exports and every model-first contract helper, so record-field and msg-arm writes enter the prove-or-refuse boundary check instead of attesting from dead-stripped vacuity
- declared record-field reads seed their class shape (whole, class range), the assumption side of the slot contract: an unguarded counter increment now refuses RANGE with the teaching triple rather than a spurious may-be-NaN wholeness complaint
- profile-export param/return classes stay out of integer_slots by design — the attestation mirrors the document's own i64-spelled slots (the V10 bijection; abi.exports carries no TypeRefs) while an export's class is attested by the artifact's C signature under the same gate; the unconsumed-path refusal teaches this
- regressions added: u64 attests u64 while the TypeRef spells i64, unproven update writes into a declared model field refuse SC4022/SC4023 by slot path, and guarded writes prove and attest
2026-07-24 17:56:59 -05:00
Chris Tate d1192f3785 2470's deferred fence is cured: the general for-of lowering claims its table loop 2026-07-24 17:56:17 -05:00
Chris Tate 45dcaf9ca9 Record order-parity baselines for the four-lane train 2026-07-24 17:23:52 -05:00
Chris Tate fed7193648 Consumers take the named fence for provably-non-stream arguments
- Node's consumers reject asynchronously with the plain not-async-iterable TypeError; no sync ladder exists to borrow, so the provable case refuses with the rejection domain named
2026-07-24 17:21:12 -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 de37b09716 Trap-claim carve-outs restore two over-narrowed shapes; extending a poisoned base refuses at build time
- The written-binding decline yields when the declared type has no mapping or the write's RHS roots at an ambient-undefined name
- A class extending a collection-poisoned base flushes the base's diagnostics eagerly: the heritage evaluates at module init, so deferring the compiler's own fence manufactured a silent wrong output
2026-07-24 17:18:25 -05:00
Chris Tate 6388ffdd52 pipeline argument ladders throw Node's errors instead of escaping the internal marker
- Both pipeline lowerings catch the arg-type marker the finished paths already caught; provably-invalid stages throw Node's synchronous ERR_INVALID_ARG_TYPE in every position
- Accepted-but-unlowered sources fence naming what Node accepts; finished(null) joins the isNodeStream ladder
2026-07-24 17:17:15 -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 a7cd284944 Trap claims survive writes storage cannot serve; extending a rejected base reports at compile time
- trapDeclRootOf's written-binding decline now requires a mappable declared type: ordinary storage only buys anything when it compiles — an unmappable recursive call shape traded the compiling no-storage trap for a guaranteed SC2009 on a value that never exists
- bindingEverWritten skips statement-position writes whose RHS chain roots at an ambient-undefined name: that statement IS the RHS root's throw (lowerExprStatement's first claim) and never touches the target's storage, so it cannot justify the decline
- A poisoned base a top-level class extends flushes its deferred diagnostics eagerly (collectClassShape): the heritage evaluates at module init and the base's fence is the compiler's own — Node defines the base fine — so the deferred trap compiled a binary that refused at startup where Node runs; leaf and derived-only poisoned classes keep the JS deferral
- Fixtures: corpus 2632 (unmappable written trap binding) and 2633 (ambient-rooted rewrite), diagnostics js-extends-poisoned-base (the eager report names the base's real blocker), errors.test pins for both deferral edges that must NOT report eagerly; order-parity baselines recorded for the new entries
2026-07-24 15:03:30 -05:00
Chris Tate 72ccd05c34 pipeline's stage ladder throws Node's body clause instead of crashing the compiler
- lowerStreamArg's arg-type marker escaped both pipeline lowerings uncaught (only finished caught it), so a compile-time non-stream stage — pipeline('', dst, cb) — crashed the CLI with a raw StreamArgTypeThrow; both pipeline paths now catch and answer it as the call's value, matching finished
- The ladder splits by API to match Node exactly: finished keeps the isNodeStream clause (null now included), while pipeline stages render makeAsyncIterable's "body" clause — the same text in source, middle, and destination positions — for numbers, booleans, null, and pair-less records
- Shapes Node accepts but scriptc can't lower yet never take a throw Node never throws: strings and arrays (iterables) and records carrying a readable/writable member (the duplex-pair form) keep the pointed fence, whose hint now names those inputs
- tests/corpus/2632-stream-pipeline-arg-ladders.cjs pins the ladder in all three positions plus finished(null) and a live pipe, byte-identical through both backends in the plain and sanitized lanes
2026-07-24 12:48:41 -05:00
Chris Tate e96d1264c1 Release 0.0.11 v0.0.11 2026-07-24 12:47:01 -05:00
Chris Tate 78177039a4 The jsval-element-array exit stays on its own targets: JSON-safe arrays keep the round trip, any[]-declared locals keep the island handle
- The jsExit emitters' array arm intercepted EVERY array target — string[] exits (the rest-args map/join idiom, corpus 2449) came back as handle-element arrays and native join trapped. Both backends now gate on the jsval element kind; JSON-safe element types keep the dynCheck round trip.
- An island value under an any[]-declared LOCAL stays an island HANDLE (the runtime-world rule, the package-promise local's twin): the exit is a CALL-boundary conversion — a converted local would strand the engine's own prototypes where the handle routes every use.
2026-07-24 12:25:34 -05:00
Chris Tate 9f85b2cdfd Record order-parity baselines for the six-lane train 2026-07-24 12:16:32 -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 aac4f9390b Buffer views alias for real; stream ticks interleave with process.nextTick in Node's order
- Buffer slice and subarray become true aliasing views over the retained owner — mutating through a view was silently computing wrong bytes
- Each stream tick posts a one-to-one marker on the user tick queue, so stream emissions interleave with process.nextTick in enqueue order, Node's order by construction; the station remains for teardown
- Stream emitters model the pre-created event-key shape governing eventNames order; push honors defaultEncoding with Node's unknown-encoding errors

# Conflicts:
#	packages/compiler/test/ts7/baselines/order-parity.json
2026-07-24 12:11:31 -05:00