@scriptc/compiler 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/ambient/package.json +3 -0
- package/ambient/scriptc-node-fallback.d.ts +3001 -0
- package/ambient/scriptc-overrides.d.ts +95 -0
- package/ambient/scriptc.d.ts +74 -0
- package/dist/backend/cc.d.ts +169 -0
- package/dist/backend/cc.js +897 -0
- package/dist/backend/cc.js.map +1 -0
- package/dist/backend/emission/emit-async.d.ts +145 -0
- package/dist/backend/emission/emit-async.js +996 -0
- package/dist/backend/emission/emit-async.js.map +1 -0
- package/dist/backend/emission/emit-exprs.d.ts +3 -0
- package/dist/backend/emission/emit-exprs.js +5949 -0
- package/dist/backend/emission/emit-exprs.js.map +1 -0
- package/dist/backend/emission/emit-island.d.ts +45 -0
- package/dist/backend/emission/emit-island.js +271 -0
- package/dist/backend/emission/emit-island.js.map +1 -0
- package/dist/backend/emission/emit-shapes.d.ts +142 -0
- package/dist/backend/emission/emit-shapes.js +575 -0
- package/dist/backend/emission/emit-shapes.js.map +1 -0
- package/dist/backend/emission/emit-stmts.d.ts +78 -0
- package/dist/backend/emission/emit-stmts.js +960 -0
- package/dist/backend/emission/emit-stmts.js.map +1 -0
- package/dist/backend/emission/emit-types.d.ts +65 -0
- package/dist/backend/emission/emit-types.js +652 -0
- package/dist/backend/emission/emit-types.js.map +1 -0
- package/dist/backend/emission/emit-walkers.d.ts +154 -0
- package/dist/backend/emission/emit-walkers.js +1587 -0
- package/dist/backend/emission/emit-walkers.js.map +1 -0
- package/dist/backend/emission/emitter.d.ts +452 -0
- package/dist/backend/emission/emitter.js +1249 -0
- package/dist/backend/emission/emitter.js.map +1 -0
- package/dist/backend/emission/may-throw.d.ts +15 -0
- package/dist/backend/emission/may-throw.js +250 -0
- package/dist/backend/emission/may-throw.js.map +1 -0
- package/dist/backend/llvm/blocks.d.ts +21 -0
- package/dist/backend/llvm/blocks.js +68 -0
- package/dist/backend/llvm/blocks.js.map +1 -0
- package/dist/backend/llvm/classes.d.ts +84 -0
- package/dist/backend/llvm/classes.js +438 -0
- package/dist/backend/llvm/classes.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +123 -0
- package/dist/backend/llvm/dyn.js +2624 -0
- package/dist/backend/llvm/dyn.js.map +1 -0
- package/dist/backend/llvm/emitter.d.ts +3 -0
- package/dist/backend/llvm/emitter.js +10102 -0
- package/dist/backend/llvm/emitter.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +78 -0
- package/dist/backend/llvm/shapes.js +754 -0
- package/dist/backend/llvm/shapes.js.map +1 -0
- package/dist/backend/llvm/unsupported.d.ts +6 -0
- package/dist/backend/llvm/unsupported.js +12 -0
- package/dist/backend/llvm/unsupported.js.map +1 -0
- package/dist/backend/llvm/walkers.d.ts +58 -0
- package/dist/backend/llvm/walkers.js +793 -0
- package/dist/backend/llvm/walkers.js.map +1 -0
- package/dist/backend/mangle.d.ts +124 -0
- package/dist/backend/mangle.js +232 -0
- package/dist/backend/mangle.js.map +1 -0
- package/dist/coverage/report.d.ts +65 -0
- package/dist/coverage/report.js +238 -0
- package/dist/coverage/report.js.map +1 -0
- package/dist/diagnostics/diagnostic.d.ts +140 -0
- package/dist/diagnostics/diagnostic.js +458 -0
- package/dist/diagnostics/diagnostic.js.map +1 -0
- package/dist/diagnostics/render.d.ts +11 -0
- package/dist/diagnostics/render.js +58 -0
- package/dist/diagnostics/render.js.map +1 -0
- package/dist/frontend/cjs-lexer.d.ts +20 -0
- package/dist/frontend/cjs-lexer.js +813 -0
- package/dist/frontend/cjs-lexer.js.map +1 -0
- package/dist/frontend/lowering/http2-constants.d.ts +1 -0
- package/dist/frontend/lowering/http2-constants.js +251 -0
- package/dist/frontend/lowering/http2-constants.js.map +1 -0
- package/dist/frontend/lowering/lib-boundary.d.ts +6 -0
- package/dist/frontend/lowering/lib-boundary.js +143 -0
- package/dist/frontend/lowering/lib-boundary.js.map +1 -0
- package/dist/frontend/lowering/lower-assert.d.ts +18 -0
- package/dist/frontend/lowering/lower-assert.js +1269 -0
- package/dist/frontend/lowering/lower-assert.js.map +1 -0
- package/dist/frontend/lowering/lower-builtins.d.ts +511 -0
- package/dist/frontend/lowering/lower-builtins.js +5249 -0
- package/dist/frontend/lowering/lower-builtins.js.map +1 -0
- package/dist/frontend/lowering/lower-calls.d.ts +581 -0
- package/dist/frontend/lowering/lower-calls.js +6286 -0
- package/dist/frontend/lowering/lower-calls.js.map +1 -0
- package/dist/frontend/lowering/lower-classes.d.ts +727 -0
- package/dist/frontend/lowering/lower-classes.js +4701 -0
- package/dist/frontend/lowering/lower-classes.js.map +1 -0
- package/dist/frontend/lowering/lower-comptime.d.ts +53 -0
- package/dist/frontend/lowering/lower-comptime.js +244 -0
- package/dist/frontend/lowering/lower-comptime.js.map +1 -0
- package/dist/frontend/lowering/lower-containers.d.ts +486 -0
- package/dist/frontend/lowering/lower-containers.js +6345 -0
- package/dist/frontend/lowering/lower-containers.js.map +1 -0
- package/dist/frontend/lowering/lower-dgram.d.ts +20 -0
- package/dist/frontend/lowering/lower-dgram.js +319 -0
- package/dist/frontend/lowering/lower-dgram.js.map +1 -0
- package/dist/frontend/lowering/lower-emitter.d.ts +10 -0
- package/dist/frontend/lowering/lower-emitter.js +688 -0
- package/dist/frontend/lowering/lower-emitter.js.map +1 -0
- package/dist/frontend/lowering/lower-enums.d.ts +22 -0
- package/dist/frontend/lowering/lower-enums.js +235 -0
- package/dist/frontend/lowering/lower-enums.js.map +1 -0
- package/dist/frontend/lowering/lower-expando.d.ts +35 -0
- package/dist/frontend/lowering/lower-expando.js +276 -0
- package/dist/frontend/lowering/lower-expando.js.map +1 -0
- package/dist/frontend/lowering/lower-exprs.d.ts +524 -0
- package/dist/frontend/lowering/lower-exprs.js +8111 -0
- package/dist/frontend/lowering/lower-exprs.js.map +1 -0
- package/dist/frontend/lowering/lower-generators.d.ts +50 -0
- package/dist/frontend/lowering/lower-generators.js +421 -0
- package/dist/frontend/lowering/lower-generators.js.map +1 -0
- package/dist/frontend/lowering/lower-inspect.d.ts +20 -0
- package/dist/frontend/lowering/lower-inspect.js +1074 -0
- package/dist/frontend/lowering/lower-inspect.js.map +1 -0
- package/dist/frontend/lowering/lower-island.d.ts +108 -0
- package/dist/frontend/lowering/lower-island.js +650 -0
- package/dist/frontend/lowering/lower-island.js.map +1 -0
- package/dist/frontend/lowering/lower-mixins.d.ts +96 -0
- package/dist/frontend/lowering/lower-mixins.js +534 -0
- package/dist/frontend/lowering/lower-mixins.js.map +1 -0
- package/dist/frontend/lowering/lower-modules.d.ts +135 -0
- package/dist/frontend/lowering/lower-modules.js +1613 -0
- package/dist/frontend/lowering/lower-modules.js.map +1 -0
- package/dist/frontend/lowering/lower-namespaces.d.ts +168 -0
- package/dist/frontend/lowering/lower-namespaces.js +706 -0
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -0
- package/dist/frontend/lowering/lower-server.d.ts +90 -0
- package/dist/frontend/lowering/lower-server.js +3471 -0
- package/dist/frontend/lowering/lower-server.js.map +1 -0
- package/dist/frontend/lowering/lower-stmts.d.ts +361 -0
- package/dist/frontend/lowering/lower-stmts.js +5341 -0
- package/dist/frontend/lowering/lower-stmts.js.map +1 -0
- package/dist/frontend/lowering/lower-stream.d.ts +88 -0
- package/dist/frontend/lowering/lower-stream.js +1533 -0
- package/dist/frontend/lowering/lower-stream.js.map +1 -0
- package/dist/frontend/lowering/lower-test.d.ts +27 -0
- package/dist/frontend/lowering/lower-test.js +353 -0
- package/dist/frontend/lowering/lower-test.js.map +1 -0
- package/dist/frontend/lowering/lowerer.d.ts +1748 -0
- package/dist/frontend/lowering/lowerer.js +6257 -0
- package/dist/frontend/lowering/lowerer.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +272 -0
- package/dist/frontend/lowering/surfaces.js +1096 -0
- package/dist/frontend/lowering/surfaces.js.map +1 -0
- package/dist/frontend/npm-static.d.ts +55 -0
- package/dist/frontend/npm-static.js +300 -0
- package/dist/frontend/npm-static.js.map +1 -0
- package/dist/frontend/npm.d.ts +330 -0
- package/dist/frontend/npm.js +1259 -0
- package/dist/frontend/npm.js.map +1 -0
- package/dist/frontend/program.d.ts +186 -0
- package/dist/frontend/program.js +2255 -0
- package/dist/frontend/program.js.map +1 -0
- package/dist/frontend/provenance-registry.d.ts +48 -0
- package/dist/frontend/provenance-registry.js +87 -0
- package/dist/frontend/provenance-registry.js.map +1 -0
- package/dist/frontend/provenance.d.ts +6 -0
- package/dist/frontend/provenance.js +459 -0
- package/dist/frontend/provenance.js.map +1 -0
- package/dist/frontend/resolve.d.ts +56 -0
- package/dist/frontend/resolve.js +682 -0
- package/dist/frontend/resolve.js.map +1 -0
- package/dist/frontend/shared.d.ts +67 -0
- package/dist/frontend/shared.js +241 -0
- package/dist/frontend/shared.js.map +1 -0
- package/dist/frontend/ts7/adapter.d.ts +7 -0
- package/dist/frontend/ts7/adapter.js +54 -0
- package/dist/frontend/ts7/adapter.js.map +1 -0
- package/dist/frontend/ts7/ast.d.ts +50 -0
- package/dist/frontend/ts7/ast.js +211 -0
- package/dist/frontend/ts7/ast.js.map +1 -0
- package/dist/frontend/ts7/census-check.d.ts +1 -0
- package/dist/frontend/ts7/census-check.js +12 -0
- package/dist/frontend/ts7/census-check.js.map +1 -0
- package/dist/frontend/ts7/checker.d.ts +140 -0
- package/dist/frontend/ts7/checker.js +544 -0
- package/dist/frontend/ts7/checker.js.map +1 -0
- package/dist/frontend/ts7/enums.d.ts +18 -0
- package/dist/frontend/ts7/enums.js +43 -0
- package/dist/frontend/ts7/enums.js.map +1 -0
- package/dist/frontend/ts7/program.d.ts +99 -0
- package/dist/frontend/ts7/program.js +278 -0
- package/dist/frontend/ts7/program.js.map +1 -0
- package/dist/frontend/ts7/world-check.d.ts +3 -0
- package/dist/frontend/ts7/world-check.js +34 -0
- package/dist/frontend/ts7/world-check.js.map +1 -0
- package/dist/frontend/types.d.ts +205 -0
- package/dist/frontend/types.js +2485 -0
- package/dist/frontend/types.js.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +429 -0
- package/dist/index.js.map +1 -0
- package/dist/ir/nodes.d.ts +4334 -0
- package/dist/ir/nodes.js +1906 -0
- package/dist/ir/nodes.js.map +1 -0
- package/dist/ir/serialize.d.ts +4 -0
- package/dist/ir/serialize.js +34 -0
- package/dist/ir/serialize.js.map +1 -0
- package/dist/ir/validate.d.ts +36 -0
- package/dist/ir/validate.js +4885 -0
- package/dist/ir/validate.js.map +1 -0
- package/package.json +30 -6
- package/README.md +0 -3
- package/index.js +0 -2
|
@@ -0,0 +1,4334 @@
|
|
|
1
|
+
/** Byte-offset span in the original source file. */
|
|
2
|
+
export interface SrcLoc {
|
|
3
|
+
file: string;
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
}
|
|
7
|
+
/** The typed-array element kinds with a runtime representation: exactly
|
|
8
|
+
* the constructors real CLI code reaches (Uint8Array/Buffer, Uint32Array,
|
|
9
|
+
* Int32Array — the Atomics.wait sleep idiom's array — Float32Array). The
|
|
10
|
+
* other TypedArray flavors stay frontend-fenced. */
|
|
11
|
+
export type IrBytesElem = "u8" | "u32" | "i32" | "f32";
|
|
12
|
+
export type IrType = {
|
|
13
|
+
kind: "f64";
|
|
14
|
+
} | {
|
|
15
|
+
kind: "string";
|
|
16
|
+
} | {
|
|
17
|
+
kind: "bool";
|
|
18
|
+
} | {
|
|
19
|
+
kind: "array";
|
|
20
|
+
elem: IrType;
|
|
21
|
+
}
|
|
22
|
+
/** ES `Map<K, V>` — heap, refcounted, insertion-ordered hash map with ONE
|
|
23
|
+
* runtime representation (ScrMap) and type-directed key/value handling,
|
|
24
|
+
* exactly the array pattern (never per-instantiation structs). Keys are
|
|
25
|
+
* f64 or string (SameValueZero); values are f64, string, bool, record,
|
|
26
|
+
* object, union, or array — anything isRefCounted or scalar EXCEPT
|
|
27
|
+
* func/promise/dyn/jsval/map (frontend-fenced, validator-checked). */
|
|
28
|
+
| {
|
|
29
|
+
kind: "map";
|
|
30
|
+
key: IrType;
|
|
31
|
+
value: IrType;
|
|
32
|
+
}
|
|
33
|
+
/** ES `Set<T>` — heap, refcounted, insertion-ordered. Map's sibling with
|
|
34
|
+
* the value slot removed: ONE runtime representation (the backend lowers
|
|
35
|
+
* sets onto the map runtime with a constant unit value), elements are
|
|
36
|
+
* exactly Map's KEY types — f64 or string, SameValueZero. Same container
|
|
37
|
+
* fences as map (no union arms, no array elements, no map values, no sets
|
|
38
|
+
* of sets, not JSON-safe) and never cycle-capable: elements are scalars
|
|
39
|
+
* or strings, which cannot point back. */
|
|
40
|
+
| {
|
|
41
|
+
kind: "set";
|
|
42
|
+
elem: IrType;
|
|
43
|
+
}
|
|
44
|
+
/** A regular expression — heap, refcounted, IMMUTABLE. No lastIndex
|
|
45
|
+
* statefulness exists: /g and /y are supported only inside
|
|
46
|
+
* replace/replaceAll/split (where the iteration is internal), and test()
|
|
47
|
+
* on them is rejected. Every regex value today originates from a literal,
|
|
48
|
+
* which backends intern as ONE immortal static per (pattern, flags) pair
|
|
49
|
+
* — bytecode compiles lazily at first use, is never freed, and the RC
|
|
50
|
+
* audit ignores immortals. Deliberately narrower than string: no array
|
|
51
|
+
* elements, no map keys/values, no union arms (a regex arm would have no
|
|
52
|
+
* narrowing test), not JSON-safe. */
|
|
53
|
+
| {
|
|
54
|
+
kind: "regex";
|
|
55
|
+
}
|
|
56
|
+
/** A typed array / Node Buffer (Uint8Array, Uint32Array, Float32Array;
|
|
57
|
+
* Buffer IS a Uint8Array subclass and shares the u8 kind) — heap,
|
|
58
|
+
* refcounted, MUTABLE, fixed-length, with ONE runtime representation
|
|
59
|
+
* (ScrBytes) that OWNS its storage: no views exist — subarray()/slice()
|
|
60
|
+
* both COPY (documented divergence for subarray), `.buffer`/
|
|
61
|
+
* `.byteOffset`/DataView are frontend-fenced. Element reads widen to
|
|
62
|
+
* f64; writes coerce JS-exactly (ToUint8/ToUint32 modular truncation,
|
|
63
|
+
* double→float rounding). OOB element access traps like arrays. Allowed
|
|
64
|
+
* as array elements and union arms (tag-based narrowing, like url);
|
|
65
|
+
* fenced out of map keys/values, set elements, and JSON. Holds only raw
|
|
66
|
+
* bytes — never part of a cycle, no trace. */
|
|
67
|
+
| {
|
|
68
|
+
kind: "bytes";
|
|
69
|
+
elem: IrBytesElem;
|
|
70
|
+
}
|
|
71
|
+
/** A WHATWG URL instance (scr_url.c): heap, refcounted, IMMUTABLE — the
|
|
72
|
+
* parsed components are frozen at construction, so getters are pure
|
|
73
|
+
* reads (the mutating lib setters are fenced). Constructed by `new URL`
|
|
74
|
+
* and url.pathToFileURL libCalls. Holds only strings — never part of a
|
|
75
|
+
* cycle, no trace. Allowed as a union arm (narrowing is tag-based, like
|
|
76
|
+
* object arms); fenced out of array elements, map keys/values, and JSON
|
|
77
|
+
* like regex. */
|
|
78
|
+
| {
|
|
79
|
+
kind: "url";
|
|
80
|
+
}
|
|
81
|
+
/** A URLSearchParams instance (scr_url.c): heap, refcounted, MUTABLE —
|
|
82
|
+
* an ordered list of decoded (name, value) string pairs. Standalone
|
|
83
|
+
* (`new URLSearchParams(...)`) or the LIVE view of a URL's query
|
|
84
|
+
* (`u.searchParams` — cached on the URL, mutations re-serialize into
|
|
85
|
+
* the URL's query so href reflects immediately). Holds only strings
|
|
86
|
+
* plus at most the owning-URL edge (the URL never points back
|
|
87
|
+
* owningly) — never part of a cycle, no trace. Same container rules
|
|
88
|
+
* as url: union arms fine, arrays/maps/JSON fenced. */
|
|
89
|
+
| {
|
|
90
|
+
kind: "searchParams";
|
|
91
|
+
}
|
|
92
|
+
/** An ES symbol value (scr_symbol.c — linked only when the IR uses the
|
|
93
|
+
* symbol surface): heap, refcounted, IMMUTABLE — a runtime-unique
|
|
94
|
+
* IDENTITY whose pointer is the identity (`===` is a pointer compare;
|
|
95
|
+
* equal descriptions are still distinct symbols, JS exactly). Holds at
|
|
96
|
+
* most two strings (description + Symbol.for registry key) — never part
|
|
97
|
+
* of a cycle, no trace. Constructed by `Symbol(desc?)` and
|
|
98
|
+
* `Symbol.for(key)`; typeof answers "symbol"; truthiness is constant
|
|
99
|
+
* true (every symbol is truthy). Allowed as union arms (tag-based
|
|
100
|
+
* narrowing — `typeof u === "symbol"` is the test, like url), array
|
|
101
|
+
* elements (SCR_ELEM_REF identity semantics, the child precedent), and
|
|
102
|
+
* Set elements (identity hashing, SCR_MAP_KEY_REF — the netServer
|
|
103
|
+
* precedent); fenced out of map keys/values and JSON (JSON.stringify
|
|
104
|
+
* drops symbols in Node — silent divergence banned, reject instead).
|
|
105
|
+
* Property KEYS stay frontend-fenced: static record/class shapes have
|
|
106
|
+
* no symbol-keyed storage. */
|
|
107
|
+
| {
|
|
108
|
+
kind: "symbol";
|
|
109
|
+
}
|
|
110
|
+
/** An fs.Stats instance (statSync / fs.promises.stat): heap, refcounted,
|
|
111
|
+
* IMMUTABLE — a snapshot of stat(2) results. Holds no references —
|
|
112
|
+
* never part of a cycle, no trace. Same container rules as url: union
|
|
113
|
+
* arms fine, arrays/maps/JSON fenced. */
|
|
114
|
+
| {
|
|
115
|
+
kind: "stats";
|
|
116
|
+
}
|
|
117
|
+
/** A child_process.spawnSync result (scr_child.c): heap, refcounted,
|
|
118
|
+
* IMMUTABLE — the reaped child's status plus its captured utf8 stdout/
|
|
119
|
+
* stderr. Holds only strings — never part of a cycle, no trace. Same
|
|
120
|
+
* container rules as stats. */
|
|
121
|
+
| {
|
|
122
|
+
kind: "spawnRes";
|
|
123
|
+
}
|
|
124
|
+
/** A child_process.spawn handle (scr_child.c): heap, refcounted, the
|
|
125
|
+
* ONE mutable builtin value kind — the event loop reaps the child and
|
|
126
|
+
* fires its registered listeners (scr_async.c polls at quiescence).
|
|
127
|
+
* Holds closures until the terminal event fires, then drops them (the
|
|
128
|
+
* registry releases every listener at reap, so a listener capturing its
|
|
129
|
+
* own child never cycles past reap — and every child IS reaped before
|
|
130
|
+
* loop exit, Node's keep-alive semantics). Lean allocation, no trace:
|
|
131
|
+
* the pre-reap closure edges are guaranteed dropped. Same container
|
|
132
|
+
* rules as stats: union arms fine, arrays/maps/JSON fenced. */
|
|
133
|
+
| {
|
|
134
|
+
kind: "child";
|
|
135
|
+
}
|
|
136
|
+
/** A node:net server handle (scr_net.c — linked only when the IR uses
|
|
137
|
+
* the net surface). Heap, refcounted, MUTABLE like child: the event
|
|
138
|
+
* loop's net hook accepts connections and fires its listeners.
|
|
139
|
+
* Listeners are held only until the handle settles ('close' fired, or
|
|
140
|
+
* the exit-time cleanup) — the child ownership story, so lean
|
|
141
|
+
* allocation, no trace header. Same container rules as child: union
|
|
142
|
+
* arms fine, arrays/maps/JSON fenced. */
|
|
143
|
+
| {
|
|
144
|
+
kind: "netServer";
|
|
145
|
+
}
|
|
146
|
+
/** A node:net socket handle (accepted connection or net.connect
|
|
147
|
+
* client) — the same runtime story as netServer. */
|
|
148
|
+
| {
|
|
149
|
+
kind: "netSocket";
|
|
150
|
+
} | {
|
|
151
|
+
kind: "http2Session";
|
|
152
|
+
} | {
|
|
153
|
+
kind: "http2Stream";
|
|
154
|
+
}
|
|
155
|
+
/** A node:dgram socket handle (scr_dgram.c — linked only when the IR
|
|
156
|
+
* uses the dgram/dns surface). Heap, refcounted, MUTABLE like
|
|
157
|
+
* netSocket: the loop's dgram hook delivers datagrams and fires its
|
|
158
|
+
* listeners. Listeners are held only until the handle settles ('close'
|
|
159
|
+
* fired, or the exit-time cleanup) — the netSocket ownership story, so
|
|
160
|
+
* lean allocation, no trace header. Same container rules: union arms
|
|
161
|
+
* fine, arrays/maps/JSON fenced. */
|
|
162
|
+
| {
|
|
163
|
+
kind: "dgramSocket";
|
|
164
|
+
}
|
|
165
|
+
/** A node:test TestContext handle (scr_test.c — linked only when the
|
|
166
|
+
* IR uses the node:test surface). Heap, refcounted, no cycles (the
|
|
167
|
+
* runner tree owns the children; the parent edge is a borrowed
|
|
168
|
+
* back-pointer): a lean handle like dgramSocket. Test bodies receive
|
|
169
|
+
* it as their parameter; t.test/t.skip/t.todo/t.diagnostic lower to
|
|
170
|
+
* test.* libCalls on it. */
|
|
171
|
+
| {
|
|
172
|
+
kind: "testCtx";
|
|
173
|
+
}
|
|
174
|
+
/** A node:http server request (scr_http.c — the parsed head + the body
|
|
175
|
+
* event lists; listeners drop when the body completes, the same
|
|
176
|
+
* settle-releases-listeners story). http.Server itself is a netServer. */
|
|
177
|
+
| {
|
|
178
|
+
kind: "httpReq";
|
|
179
|
+
}
|
|
180
|
+
/** A node:http server response (the header list + framing state; holds
|
|
181
|
+
* the socket, never listeners — lean, no trace). */
|
|
182
|
+
| {
|
|
183
|
+
kind: "httpRes";
|
|
184
|
+
}
|
|
185
|
+
/** A node:http CLIENT request handle (http.request/http.get — the
|
|
186
|
+
* outbound head + body framing state over a net client socket, with the
|
|
187
|
+
* response/error/timeout/close listener lists; listeners drop at
|
|
188
|
+
* settlement like every other handle). The RESPONSE it delivers is an
|
|
189
|
+
* httpReq — IncomingMessage is one type in Node too. */
|
|
190
|
+
| {
|
|
191
|
+
kind: "httpClientReq";
|
|
192
|
+
}
|
|
193
|
+
/** A piped child-output stream (child.stdout / child.stderr — spawn
|
|
194
|
+
* with stdio ["ignore", "pipe", "pipe"]; scr_child.c). Heap, refcounted,
|
|
195
|
+
* MUTABLE like child: the loop's reap pass services the pipe and fires
|
|
196
|
+
* 'data'/'end' listeners, which drop at EOF (the settle-releases-
|
|
197
|
+
* listeners story), so lean allocation, no trace header. Same container
|
|
198
|
+
* rules as child: union arms fine (the checker's `Readable | null`),
|
|
199
|
+
* arrays/maps/JSON fenced. */
|
|
200
|
+
| {
|
|
201
|
+
kind: "childStream";
|
|
202
|
+
}
|
|
203
|
+
/** A process output stream as a FIRST-CLASS value (process.stdout /
|
|
204
|
+
* process.stderr flowing into a `NodeJS.WritableStream` slot — the
|
|
205
|
+
* prefixStream idiom). Representation is the raw FD as a double (1 or
|
|
206
|
+
* 2): a SCALAR kind like f64 — no heap, no refcount, boxes ride
|
|
207
|
+
* SCR_BOX_F64. Truthiness is object-true (Node's streams are objects).
|
|
208
|
+
* The lowered surface is write(string); everything else fences. */
|
|
209
|
+
| {
|
|
210
|
+
kind: "procStream";
|
|
211
|
+
}
|
|
212
|
+
/** An fs.FSWatcher handle (scr_watch.c — linked only when the IR uses
|
|
213
|
+
* fs.watch). Heap, refcounted, MUTABLE like child: the event loop's
|
|
214
|
+
* watch hook drains the unit's kqueue (EVFILT_VNODE) and fires its
|
|
215
|
+
* listeners. Listeners are held only until close() (or the exit-time
|
|
216
|
+
* cleanup) — the child ownership story, so lean allocation, no trace
|
|
217
|
+
* header. Same container rules as child: union arms fine (the
|
|
218
|
+
* `FSWatcher | null` polling-fallback local), arrays/maps/JSON fenced. */
|
|
219
|
+
| {
|
|
220
|
+
kind: "fsWatcher";
|
|
221
|
+
}
|
|
222
|
+
/** A tls.SecureContext handle (scr_tls.c): heap, refcounted, IMMUTABLE —
|
|
223
|
+
* a parsed cert/key pair (tls.createSecureContext({ cert, key })) that
|
|
224
|
+
* an SNI callback answers per-servername. Holds no references — never
|
|
225
|
+
* part of a cycle, no trace. Union arms fine (the `ctx?: SecureContext`
|
|
226
|
+
* callback parameter is the `SecureContext | undefined` union); allowed
|
|
227
|
+
* as a Map VALUE (the per-hostname context cache) like child; fenced out
|
|
228
|
+
* of array elements and JSON like the other opaque handles. */
|
|
229
|
+
| {
|
|
230
|
+
kind: "secureCtx";
|
|
231
|
+
}
|
|
232
|
+
/** Heap, refcounted closure. `rest` marks a VARIADIC JS function (a
|
|
233
|
+
* `...args` rest parameter, or a zero-param function body reading
|
|
234
|
+
* `arguments` — test/common's mustCall wrapper): the lifted function
|
|
235
|
+
* takes one extra trailing `ScrDyn *` param — a DOM ARRAY carrying the
|
|
236
|
+
* call's arguments from index params.length on — which the dyn call
|
|
237
|
+
* thunk builds per call. `params` stays the DECLARED (non-rest) list
|
|
238
|
+
* (fn.length semantics). Rest-marked values are only ever CALLED
|
|
239
|
+
* through the dyn boundary (boxed thunks); direct static calls box
|
|
240
|
+
* first (lower-calls). */
|
|
241
|
+
| {
|
|
242
|
+
kind: "func";
|
|
243
|
+
params: IrType[];
|
|
244
|
+
ret: IrType;
|
|
245
|
+
rest?: true;
|
|
246
|
+
} | {
|
|
247
|
+
kind: "object";
|
|
248
|
+
className: string;
|
|
249
|
+
}
|
|
250
|
+
/** The class STATIC side as a value — `typeof C`, the type of the class
|
|
251
|
+
* name itself and of `new (…) => T` constructor-typed slots. Runtime
|
|
252
|
+
* representation is the per-class IMMORTAL class object (ScrClassObj:
|
|
253
|
+
* preorder interval, construct thunk, .name string) emitted once per
|
|
254
|
+
* classRef-referenced class — so identity `===` is one pointer compare
|
|
255
|
+
* and retains/releases are no-ops on the immortal (the regex-literal
|
|
256
|
+
* discipline; isRefCounted says true for container/RC uniformity).
|
|
257
|
+
* Values of `classval:C` are C's class object or a STRICT DESCENDANT's —
|
|
258
|
+
* the object kind's nominal, upcast-only story — and every legal flow
|
|
259
|
+
* preserves the constructor ABI (upcast requires the descendant's
|
|
260
|
+
* completed ctor signature to equal C's), which is what makes `newValue`
|
|
261
|
+
* completion against C's one signature sound. Allowed in locals,
|
|
262
|
+
* globals, params, returns, class/record fields, capture boxes, array
|
|
263
|
+
* elements, Map VALUES, and union arms; fenced out of Map keys, Set
|
|
264
|
+
* elements, JSON, dyn/jsval conversion, and ToString. */
|
|
265
|
+
| {
|
|
266
|
+
kind: "classval";
|
|
267
|
+
className: string;
|
|
268
|
+
}
|
|
269
|
+
/** Structural record shape (object literal / interface / type alias over
|
|
270
|
+
* data properties). `shapeId` indexes IrModule.records; the frontend
|
|
271
|
+
* interns shapes structurally, so equal shapeId ⇔ equal shape and
|
|
272
|
+
* typeEquals may compare ids alone. Heap, refcounted, monomorphic. */
|
|
273
|
+
| {
|
|
274
|
+
kind: "record";
|
|
275
|
+
shapeId: string;
|
|
276
|
+
}
|
|
277
|
+
/** Tagged union (`A | B`). `unionId` indexes IrModule.unions; the frontend
|
|
278
|
+
* interns unions structurally (canonical identity = the sorted arm list),
|
|
279
|
+
* so equal unionId ⇔ equal arm set and typeEquals may compare ids alone.
|
|
280
|
+
* Values are heap, refcounted, IMMUTABLE tagged boxes: a runtime tag (the
|
|
281
|
+
* arm's index in the canonical order) plus one payload slot. */
|
|
282
|
+
| {
|
|
283
|
+
kind: "union";
|
|
284
|
+
unionId: string;
|
|
285
|
+
}
|
|
286
|
+
/** A dynamic value — the type of `unknown` (JSON.parse results and
|
|
287
|
+
* unknown-typed locals/params/returns). Runtime representation is a
|
|
288
|
+
* refcounted JSON DOM tree (ScrDyn). Deliberately NARROW: a dyn value can
|
|
289
|
+
* be stored in locals/globals, passed as a param/call arg, returned,
|
|
290
|
+
* validated with a checked cast (`dynCheck`), CALLED (`dynCall` — the
|
|
291
|
+
* DOM's function kind, boxed closures with per-call argument checks),
|
|
292
|
+
* and captured by closures (an untraced obj-box: cycles through dyn are
|
|
293
|
+
* never collected, SEMANTICS.md); it can NOT ride record/class fields,
|
|
294
|
+
* array elements, union arms, or the exception cell, and every other
|
|
295
|
+
* operation on it (property access, arithmetic, truthiness, `===`,
|
|
296
|
+
* console.log, ...) is frontend-rejected with a "validate with 'as
|
|
297
|
+
* <type>' first" hint — or, in JavaScript sources, met with per-site
|
|
298
|
+
* checked lowerings (SEMANTICS.md 115-117). */
|
|
299
|
+
| {
|
|
300
|
+
kind: "dyn";
|
|
301
|
+
}
|
|
302
|
+
/** An island value handle — the type of `any` under --dynamic. Runtime
|
|
303
|
+
* representation is a refcounted cell (ScrJsval) owning one embedded-
|
|
304
|
+
* engine value. Same deliberate NARROWNESS as dyn (locals/globals/
|
|
305
|
+
* params/args/returns only — never record/class fields, array elements,
|
|
306
|
+
* union arms, or capture boxes), but the OPPOSITE operational stance:
|
|
307
|
+
* where every operation on dyn is frontend-rejected, operations on
|
|
308
|
+
* jsval compile to engine calls (jsOp) with JS-exact semantics, and
|
|
309
|
+
* exits back to static types are validated (jsExit). Exists only when
|
|
310
|
+
* the frontend runs with the dynamic option; static builds never see
|
|
311
|
+
* this kind. */
|
|
312
|
+
| {
|
|
313
|
+
kind: "jsval";
|
|
314
|
+
}
|
|
315
|
+
/** A catch binding — the type of `catch (e)`'s local, and NOTHING else
|
|
316
|
+
* (never params, returns, fields, arms, elements, globals, captures).
|
|
317
|
+
* Runtime representation is a refcounted snapshot box (ScrCaught) holding
|
|
318
|
+
* the taken exception: a kind tag plus the payload. Even NARROWER than
|
|
319
|
+
* dyn: the only expressions a caught value may appear in are `caughtTest`
|
|
320
|
+
* (kind/instanceof tests), `caughtNarrow` (checker-trusted extraction
|
|
321
|
+
* under a proven test), and the `rethrow` statement — the frontend
|
|
322
|
+
* rejects every other use with the narrowing hint. */
|
|
323
|
+
| {
|
|
324
|
+
kind: "caught";
|
|
325
|
+
} | {
|
|
326
|
+
kind: "promise";
|
|
327
|
+
inner: IrType;
|
|
328
|
+
}
|
|
329
|
+
/** A sync generator object (`function*`'s result — scr_async.c's ScrGen):
|
|
330
|
+
* heap, refcounted, MUTABLE — a paused fiber plus the typed value
|
|
331
|
+
* channels. `yieldT` is what `yield e` sends OUT (never yields → the
|
|
332
|
+
* frontend picks the channel off the declared/inferred Generator type;
|
|
333
|
+
* a generator that never yields still carries the type's slot), `retT`
|
|
334
|
+
* what `return v` completes with (VOID when the type carries no return
|
|
335
|
+
* value — the done result's value is then the undefined arm), `nextT`
|
|
336
|
+
* what `.next(v)` sends IN (the yield expression's result type). Lean
|
|
337
|
+
* allocation, NO cycle header: a suspended fiber's stack is untraceable
|
|
338
|
+
* by construction, so a generator captured into a cycle its own locals
|
|
339
|
+
* hold is a documented leak (the abandoned-fiber audit note covers
|
|
340
|
+
* generators still suspended at exit). Fenced out of union arms (no
|
|
341
|
+
* narrowing test — the map/set rule), map keys/values, set elements,
|
|
342
|
+
* array elements, and JSON. */
|
|
343
|
+
| {
|
|
344
|
+
kind: "generator";
|
|
345
|
+
yieldT: IrType;
|
|
346
|
+
retT: IrType;
|
|
347
|
+
nextT: IrType;
|
|
348
|
+
}
|
|
349
|
+
/** The `undefined` unit type — a payload-less arm kind. Representable
|
|
350
|
+
* ONLY as a union arm (`string | undefined`) or as the type of a
|
|
351
|
+
* `unitLit` on its way into a `unionWrap`; it can never stand alone in
|
|
352
|
+
* locals, globals, record/class fields, array elements, params, or
|
|
353
|
+
* returns (the frontend maps standalone `undefined` to void in return
|
|
354
|
+
* position and rejects it in value position — see mapType). A union
|
|
355
|
+
* instance holding a unit arm carries the tag and NO payload; backends
|
|
356
|
+
* may intern ONE immortal instance per (union, tag). */
|
|
357
|
+
| {
|
|
358
|
+
kind: "undefinedT";
|
|
359
|
+
}
|
|
360
|
+
/** The `null` unit type — same fences and representation as undefinedT.
|
|
361
|
+
* Unlike undefinedT it is JSON-representable: JSON `null` matches a
|
|
362
|
+
* nullT arm in dynCheck, and a null-armed union stringifies as `null`. */
|
|
363
|
+
| {
|
|
364
|
+
kind: "nullT";
|
|
365
|
+
} | {
|
|
366
|
+
kind: "void";
|
|
367
|
+
};
|
|
368
|
+
/** The ref kinds whose values are JS OBJECTS for truthiness: always true
|
|
369
|
+
* ([] and {} included) — toBool accepts them (the operand still evaluates;
|
|
370
|
+
* the test is constant), and per-union truthiness helpers answer their
|
|
371
|
+
* arms with `true`. */
|
|
372
|
+
export declare const REF_TRUTHY_KINDS: ReadonlySet<string>;
|
|
373
|
+
export declare const F64: IrType;
|
|
374
|
+
export declare const BYTES_U8: IrType;
|
|
375
|
+
export declare const STRING: IrType;
|
|
376
|
+
export declare const BOOL: IrType;
|
|
377
|
+
export declare const REGEX: IrType;
|
|
378
|
+
export declare const URL_T: IrType;
|
|
379
|
+
export declare const SEARCH_PARAMS_T: IrType;
|
|
380
|
+
export declare const SYMBOL_T: IrType;
|
|
381
|
+
export declare const STATS_T: IrType;
|
|
382
|
+
export declare const SPAWNRES_T: IrType;
|
|
383
|
+
export declare const CHILD_T: IrType;
|
|
384
|
+
export declare const NETSERVER_T: IrType;
|
|
385
|
+
export declare const NETSOCKET_T: IrType;
|
|
386
|
+
export declare const HTTP2SESSION_T: IrType;
|
|
387
|
+
export declare const HTTP2STREAM_T: IrType;
|
|
388
|
+
export declare const DGRAMSOCK_T: IrType;
|
|
389
|
+
export declare const TESTCTX_T: IrType;
|
|
390
|
+
export declare const HTTPREQ_T: IrType;
|
|
391
|
+
export declare const HTTPRES_T: IrType;
|
|
392
|
+
export declare const HTTPCLIENTREQ_T: IrType;
|
|
393
|
+
export declare const SECURECTX_T: IrType;
|
|
394
|
+
export declare const FSWATCHER_T: IrType;
|
|
395
|
+
export declare const CHILDSTREAM_T: IrType;
|
|
396
|
+
export declare const PROCSTREAM_T: IrType;
|
|
397
|
+
export declare const VOID: IrType;
|
|
398
|
+
export declare const DYN: IrType;
|
|
399
|
+
export declare const JSVAL: IrType;
|
|
400
|
+
export declare const CAUGHT: IrType;
|
|
401
|
+
export declare const UNDEFINED_T: IrType;
|
|
402
|
+
export declare const NULL_T: IrType;
|
|
403
|
+
/** True for the payload-less unit kinds (`undefined`/`null`). Unit values
|
|
404
|
+
* exist only inside unions: a unit-armed union instance is tag-only, so
|
|
405
|
+
* wrapping allocates no payload, narrowing to a unit arm produces no value
|
|
406
|
+
* (the frontend never emits it), and releasing has nothing to release. */
|
|
407
|
+
export declare function isUnitType(t: IrType): boolean;
|
|
408
|
+
export declare function arrayOf(elem: IrType): IrType;
|
|
409
|
+
export declare function bytesOf(elem: IrBytesElem): IrType;
|
|
410
|
+
export declare function mapOf(key: IrType, value: IrType): IrType;
|
|
411
|
+
export declare function setOf(elem: IrType): IrType;
|
|
412
|
+
/** The Map KEY fence: string (content) or number (SameValueZero) — the two
|
|
413
|
+
* kinds a hash of the VALUE is honest for. Booleans, objects, and the rest
|
|
414
|
+
* of JS's anything-goes keys stay out. Shared by the frontend's
|
|
415
|
+
* type mapping/diagnostics and the validator. Set ELEMENTS use the same
|
|
416
|
+
* fence: a set is hashed storage of its elements exactly as a map is of
|
|
417
|
+
* its keys (isSupportedSetElem is this predicate under its own name). */
|
|
418
|
+
export declare function isSupportedMapKey(t: IrType): boolean;
|
|
419
|
+
/** The Set ELEMENT fence — Map's key fence plus the refcounted HANDLE
|
|
420
|
+
* kinds stored under identity hashing (SameValueZero for JS objects IS
|
|
421
|
+
* reference identity, so a Set of server handles — portless's auxiliary-
|
|
422
|
+
* server registry — is honest hashed storage; SCR_MAP_KEY_REF in the
|
|
423
|
+
* runtime). netServer is the one handle admitted so far: it drops its
|
|
424
|
+
* listener closures at close, so a set-in-listener cycle is temporary —
|
|
425
|
+
* the child precedent's story. Symbols are identity values by DESIGN —
|
|
426
|
+
* SameValueZero on a symbol IS pointer identity, so a Set of symbols (the
|
|
427
|
+
* sentinel-registry idiom) is the same honest hashed storage with no
|
|
428
|
+
* cycle risk at all (symbols hold only strings). */
|
|
429
|
+
export declare function isSupportedSetElem(t: IrType): boolean;
|
|
430
|
+
/** The Map VALUE fence: scalars plus every refcounted kind EXCEPT
|
|
431
|
+
* func/promise/dyn/jsval (and map itself — no maps of maps).
|
|
432
|
+
* Record/object/union values can point back at the map holding them, which
|
|
433
|
+
* is exactly why ref-valued maps are cycle-capable (see the backend's
|
|
434
|
+
* cycle analysis and docs/memory.md). Shared frontend/validator. */
|
|
435
|
+
export declare function isSupportedMapValue(t: IrType): boolean;
|
|
436
|
+
/** The INDEX-SIGNATURE value fence (`{ [k: string]: V }` shapes): the map
|
|
437
|
+
* VALUE kinds — the overflow portion IS a string-keyed map — plus dyn
|
|
438
|
+
* (`unknown`, an unknown-valued pricing-table shape: overflow reads surface ordinary
|
|
439
|
+
* dyn values validated by the usual checked casts). Shared frontend
|
|
440
|
+
* (mapType) / validator. */
|
|
441
|
+
export declare function isSupportedIndexValue(t: IrType): boolean;
|
|
442
|
+
export declare function funcOf(params: IrType[], ret: IrType): IrType;
|
|
443
|
+
/** Canonical, injective text form of an IrType — the building block of
|
|
444
|
+
* shape/union identity keys, generic-function instantiation keys, and the
|
|
445
|
+
* backend's per-type helper interning (jsonStringify/dynCheck walkers).
|
|
446
|
+
* Nested records/unions are represented by their (already interned, already
|
|
447
|
+
* canonical) shapeId/unionId, so keys stay finite and comparable. Lives in
|
|
448
|
+
* the IR (not the frontend) because both ends need it. */
|
|
449
|
+
export declare function typeKey(t: IrType): string;
|
|
450
|
+
export declare function typeEquals(a: IrType, b: IrType): boolean;
|
|
451
|
+
/** True for types whose values are heap-allocated and reference-counted.
|
|
452
|
+
* The single dispatch point for the backend's RC machinery: retains,
|
|
453
|
+
* releases, frame/scope tracking, and NULL-initialized locals all key off
|
|
454
|
+
* this — adding a refcounted kind must not grow new per-kind checks outside
|
|
455
|
+
* the type-directed helpers. */
|
|
456
|
+
export declare function isRefCounted(t: IrType): boolean;
|
|
457
|
+
export interface IrModule {
|
|
458
|
+
/** Bumped on any breaking IR change; serialize.ts refuses mismatches. */
|
|
459
|
+
irVersion: 1;
|
|
460
|
+
sourceFile: string;
|
|
461
|
+
functions: IrFunction[];
|
|
462
|
+
/** Class shapes. Constructors and methods are ordinary module functions
|
|
463
|
+
* named `%Class.constructor` / `%Class.method` whose first param is
|
|
464
|
+
* `this`. Dispatch is static by default; single inheritance (`base`)
|
|
465
|
+
* routes the calls that can actually reach an override through per-class
|
|
466
|
+
* vtables (`virtualCall`) — everything else stays a direct `call`. */
|
|
467
|
+
classes?: IrClassDef[];
|
|
468
|
+
/** Module-level variables (file-scope `const`/`let` of every source
|
|
469
|
+
* file). Stable storage for the whole program: cross-module live
|
|
470
|
+
* bindings, and functions can reference them directly (no capture —
|
|
471
|
+
* globals are never boxed). Initialized by assignments inside the
|
|
472
|
+
* per-file `%init.<i>` functions; ids live in a distinct "%g." namespace so
|
|
473
|
+
* they can never collide with function-local ids. */
|
|
474
|
+
globals?: IrGlobal[];
|
|
475
|
+
/** The embedded npm runtime graph (--dynamic builds with npm imports):
|
|
476
|
+
* every reached module's SOURCE, keyed by resolved path, plus the
|
|
477
|
+
* (importer, specifier) → target edges the island's module loader and
|
|
478
|
+
* require shim resolve against. Emitted as static strings — binaries
|
|
479
|
+
* never read node_modules at runtime. Edge targets are module keys or
|
|
480
|
+
* "node:*" builtins (island-shimmed). */
|
|
481
|
+
embedded?: {
|
|
482
|
+
/** `esm` (CommonJS modules only) is the synthesized ESM facade the
|
|
483
|
+
* island loader evaluates when an ES module imports the CJS file:
|
|
484
|
+
* default plus the named exports LEXED from the source at build time
|
|
485
|
+
* (cjs-lexer.ts — the compiler's port of Node's vendored CJS lexer). */
|
|
486
|
+
modules: {
|
|
487
|
+
key: string;
|
|
488
|
+
source: string;
|
|
489
|
+
format: "esm" | "cjs" | "json";
|
|
490
|
+
esm?: string;
|
|
491
|
+
}[];
|
|
492
|
+
/** `kind` picks Node's "exports" condition set per CALL FORM: one
|
|
493
|
+
* (from, specifier) can name a dual package's ESM entry behind an
|
|
494
|
+
* "import" edge AND its CJS entry behind a "require" edge; "any"
|
|
495
|
+
* serves both lookups (relative files, builtins). */
|
|
496
|
+
edges: {
|
|
497
|
+
from: string;
|
|
498
|
+
specifier: string;
|
|
499
|
+
to: string;
|
|
500
|
+
kind: "any" | "import" | "require";
|
|
501
|
+
}[];
|
|
502
|
+
};
|
|
503
|
+
/** Record shapes, in first-seen (`r0`, `r1`, ...) order. Fields are in
|
|
504
|
+
* CANONICAL order (sorted by name) — the shape's identity; a `recordLit`'s
|
|
505
|
+
* fields stay in source order (evaluation order) independently. The
|
|
506
|
+
* frontend guarantees structural dedup: no two entries share a canonical
|
|
507
|
+
* field list. Backends emit one struct per shape, exactly like classes. */
|
|
508
|
+
records?: IrRecordShape[];
|
|
509
|
+
/** Tagged unions, in first-seen (`u0`, `u1`, ...) order. `arms` are in
|
|
510
|
+
* CANONICAL order (sorted by typeKey) — the union's identity; the arm's
|
|
511
|
+
* INDEX in this list is its runtime tag. The frontend guarantees
|
|
512
|
+
* structural dedup and that arms are pairwise-distinct IR types, none of
|
|
513
|
+
* them void/func/union (the unit kinds undefinedT/nullT ARE valid arms —
|
|
514
|
+
* union membership is the only place they exist). */
|
|
515
|
+
unions?: IrUnionDef[];
|
|
516
|
+
/** Name of the synthetic function holding top-level statements. */
|
|
517
|
+
entry: string;
|
|
518
|
+
}
|
|
519
|
+
export interface IrClassDef {
|
|
520
|
+
name: string;
|
|
521
|
+
/** The JS-observable `.name` of the class (the runtime class object's
|
|
522
|
+
* name string, and what `C.name` folds to). Differs from `name` because
|
|
523
|
+
* IR names are program-qualified (`%m1.C`, `%cx…` for class
|
|
524
|
+
* expressions); jsName follows NamedEvaluation — the declared name, the
|
|
525
|
+
* binding name for `const x = class {}`, or "" for truly anonymous
|
|
526
|
+
* expressions. Absent on the runtime-provided defs (never valuable). */
|
|
527
|
+
jsName?: string;
|
|
528
|
+
/** RUNTIME-PROVIDED class (the builtin Error hierarchy): the struct, RC
|
|
529
|
+
* helpers, and vtable live in the runtime (ScrError / scr_error_*), so
|
|
530
|
+
* backends emit no definitions for it — only the preorder-interval
|
|
531
|
+
* stamping in main() (the intervals are program-dependent; see
|
|
532
|
+
* RUNTIME_ERROR_CLASSES). User subclasses are ordinary emitted classes
|
|
533
|
+
* whose layout prefix embeds ScrError's fields. */
|
|
534
|
+
runtime?: true;
|
|
535
|
+
/** Base class name (single inheritance, `extends`). A class is IN A
|
|
536
|
+
* HIERARCHY when it has a base or is some class's base; hierarchy classes
|
|
537
|
+
* carry a vtable word after `rc` (backends), standalone classes are laid
|
|
538
|
+
* out exactly as before inheritance existed. */
|
|
539
|
+
base?: string;
|
|
540
|
+
/** ALL fields in layout order: the base chain's fields first — an
|
|
541
|
+
* IDENTICAL prefix, so an upcast is a pointer reinterpret and base-field
|
|
542
|
+
* offsets agree through any static type — then this class's own fields.
|
|
543
|
+
* The validator enforces the prefix property. */
|
|
544
|
+
fields: {
|
|
545
|
+
name: string;
|
|
546
|
+
type: IrType;
|
|
547
|
+
}[];
|
|
548
|
+
/** Method names DECLARED on this class (not inherited), in declaration
|
|
549
|
+
* order. Every entry EXCEPT the ones listed in `abstractMethods` has a
|
|
550
|
+
* module function `%<name>.<method>`; the backend derives vtable layout
|
|
551
|
+
* and devirtualization from these plus the base links (a method
|
|
552
|
+
* overridden nowhere keeps direct static calls). Accessors appear as
|
|
553
|
+
* `get:<prop>` / `set:<prop>` entries — names no user identifier can
|
|
554
|
+
* spell — and behave as ordinary methods here. */
|
|
555
|
+
methods?: string[];
|
|
556
|
+
/** Declared `abstract class` — never instantiated (tsc rejects `new` on
|
|
557
|
+
* it, including through class values), so its own vtable entries for
|
|
558
|
+
* abstract slots may stay empty. */
|
|
559
|
+
abstract?: true;
|
|
560
|
+
/** The subset of `methods` declared `abstract` (bodies are type-world):
|
|
561
|
+
* no module function exists for them. They still declare vtable slots —
|
|
562
|
+
* the slot's ABI signature comes from any concrete override (the
|
|
563
|
+
* frontend's override-exactness rule makes every implementation ABI-
|
|
564
|
+
* identical), and tsc guarantees each instantiable class in the
|
|
565
|
+
* declaring subtree implements them. */
|
|
566
|
+
abstractMethods?: string[];
|
|
567
|
+
/** GENERIC-CLASS INSTANTIATIONS only (`Box%0` for `Box<number>` — the
|
|
568
|
+
* generic-fn mangle): the FAMILY class's IR name — the synthetic,
|
|
569
|
+
* never-constructed ancestor registered under the generic class's own
|
|
570
|
+
* name that every instantiation extends. JS has ONE `Box` at runtime, so
|
|
571
|
+
* the instantiation's emitted CLASS OBJECT carries the family's preorder
|
|
572
|
+
* interval (instanceof through a class value answers for the whole
|
|
573
|
+
* family, exactly Node); everything else about the instantiation is an
|
|
574
|
+
* ordinary class. The validator checks the family is an ancestor. */
|
|
575
|
+
genericOf?: string;
|
|
576
|
+
loc: SrcLoc;
|
|
577
|
+
}
|
|
578
|
+
/** The runtime-provided error classes, keyed by IR class name. The names
|
|
579
|
+
* are '%'-prefixed ('%' cannot appear in a TS identifier, so a user's own
|
|
580
|
+
* `class Error` can never collide). `lib` is the standard-library name the
|
|
581
|
+
* frontend recognizes; `kind` is the runtime's SCR_ERR_* index (backends
|
|
582
|
+
* stamp scr_error_vts[kind] and pick constructor kinds by it). Every
|
|
583
|
+
* emitted module carries all four class defs (flagged `runtime`) so the
|
|
584
|
+
* program's preorder numbering always covers them — the runtime's own
|
|
585
|
+
* throws (JSON/dynCheck/regex) mint instances of these classes whether or
|
|
586
|
+
* not user code mentions Error. */
|
|
587
|
+
export declare const RUNTIME_ERROR_CLASSES: ReadonlyMap<string, {
|
|
588
|
+
lib: string;
|
|
589
|
+
kind: number;
|
|
590
|
+
base: string | null;
|
|
591
|
+
}>;
|
|
592
|
+
/** The runtime-provided node:events EventEmitter class (ScrEmitter /
|
|
593
|
+
* scr_emitter_*, scr_events_emitter.c — link-gated by moduleUsesEmitter,
|
|
594
|
+
* so unlike the error classes its def rides a module only when the
|
|
595
|
+
* program touches the surface). The '%' name keeps it clear of user
|
|
596
|
+
* identifiers, exactly like the error classes. Backends emit no struct/
|
|
597
|
+
* RC/vtable for it; user subclasses embed the ScrEmitter prefix (the
|
|
598
|
+
* registry pointer and the display-name slot, stamped by the emitted
|
|
599
|
+
* allocation) and main() stamps the runtime vtable's preorder interval.
|
|
600
|
+
* The emitter hierarchy is UNCONDITIONALLY cycle-capable: the registry
|
|
601
|
+
* owns listener closures, whatever the subclass fields say. */
|
|
602
|
+
export declare const RUNTIME_EMITTER_CLASS = "%EventEmitter";
|
|
603
|
+
/** The runtime-provided node:stream classes (ScrStream / scr_stream_*,
|
|
604
|
+
* scr_stream.c — link-gated by moduleUsesStream). They root at the
|
|
605
|
+
* emitter class (base chains below), so the emitter method surface and
|
|
606
|
+
* upcasts apply unchanged; every instance shares ONE runtime layout (the
|
|
607
|
+
* ScrEmitter prefix plus a lazily-allocated stream-state pointer), so a
|
|
608
|
+
* Duplex upcast to Readable is the usual pointer reinterpret. `sides`
|
|
609
|
+
* names which halves the class carries — the lowering admits readable
|
|
610
|
+
* members on "r"-siders, writable members on "w"-siders. User `extends`
|
|
611
|
+
* compiles (phase 2): subclass structs embed the full ScrStream prefix
|
|
612
|
+
* (registry, display name, state pointer — one slot past the emitter
|
|
613
|
+
* prefix), construction runs the emitted allocation then a stream .init
|
|
614
|
+
* libCall at super(options), and overridden underscore methods bind as
|
|
615
|
+
* synthesized wrapper closures dispatching through the vtable; main()
|
|
616
|
+
* stamps each runtime vtable's preorder interval like the emitter's. */
|
|
617
|
+
export declare const RUNTIME_STREAM_CLASSES: ReadonlyMap<string, {
|
|
618
|
+
lib: string;
|
|
619
|
+
base: string;
|
|
620
|
+
sides: "r" | "w" | "rw";
|
|
621
|
+
}>;
|
|
622
|
+
export interface IrRecordShape {
|
|
623
|
+
/** Frontend-assigned shape id (`r0`, `r1`, ...). */
|
|
624
|
+
id: string;
|
|
625
|
+
/** Sorted by field name (canonical order). Types are never void. */
|
|
626
|
+
fields: {
|
|
627
|
+
name: string;
|
|
628
|
+
type: IrType;
|
|
629
|
+
}[];
|
|
630
|
+
/** A TUPLE shape (`[string, number]`): fields are exactly "0".."n-1" —
|
|
631
|
+
* one per position, arity = fields.length. Same struct/RC/trace emission
|
|
632
|
+
* as any record; the flag changes the SURFACE (literal-index access,
|
|
633
|
+
* constant length, JSON as an array with exact-arity validation) and is
|
|
634
|
+
* part of the shape's interned identity, keeping tuples distinct from
|
|
635
|
+
* numeric-keyed object records (which serialize as objects). */
|
|
636
|
+
tuple?: true;
|
|
637
|
+
/** A STRING INDEX SIGNATURE's value type (`{ input?: string;
|
|
638
|
+
* [key: string]: unknown }`, `Record<string, string>`): the shape is a
|
|
639
|
+
* HYBRID — declared fields keep their static struct slots (field access
|
|
640
|
+
* stays a struct read), and undeclared keys live in an OVERFLOW map the
|
|
641
|
+
* struct embeds (string-keyed, insertion-ordered, values uniformly this
|
|
642
|
+
* type). Part of the interned identity: `{a: string}` with and without
|
|
643
|
+
* an index signature are distinct shapes. `unknown` values are `dyn`
|
|
644
|
+
* (the ONE position besides locals/params where dyn rides a container —
|
|
645
|
+
* internal to the shape, reads surface it as an ordinary dyn value);
|
|
646
|
+
* otherwise the supported value kinds mirror map values. Never combined
|
|
647
|
+
* with `tuple`. dynCheck against such a shape CAPTURES undeclared keys
|
|
648
|
+
* into the overflow (width tolerance becomes width capture — see
|
|
649
|
+
* dynCheck), and JSON serialization appends overflow entries after the
|
|
650
|
+
* declared fields in insertion order. */
|
|
651
|
+
indexValue?: IrType;
|
|
652
|
+
/** Field names in FIRST-SEEN declaration order (the checker's property
|
|
653
|
+
* order of the first ts.Type interned to this shape) — metadata, NOT
|
|
654
|
+
* part of the interned identity: a later structurally-equal type with a
|
|
655
|
+
* different member order shares the shape and the first one's order.
|
|
656
|
+
* JSON.stringify, Object.keys/values/entries, record→DOM conversion,
|
|
657
|
+
* and util.inspect all emit this order; JS's per-object insertion order
|
|
658
|
+
* matches it whenever objects are constructed in declaration order
|
|
659
|
+
* (SEMANTICS.md 36 documents the divergence when they are not).
|
|
660
|
+
* Absent on tuples (positional by construction). Names the shape's
|
|
661
|
+
* fields carry that declaredOrder OMITS are internal '%'-fields (Dirent's
|
|
662
|
+
* %dtype) — hidden from every key-order surface, JSON included. */
|
|
663
|
+
declaredOrder?: string[];
|
|
664
|
+
}
|
|
665
|
+
/** Object-literal ACCESSOR properties (`{ get x() {...}, set x(v) {...} }`)
|
|
666
|
+
* live on the shape as reserved '%'-fields holding closures: `%get:x` a
|
|
667
|
+
* `() => T` invoked once per property READ (side effects and all — JS's
|
|
668
|
+
* evaluation), `%set:x` a `(v: T) => void` invoked per WRITE. The property
|
|
669
|
+
* name itself has NO data slot. Like every '%'-field the slots stay out of
|
|
670
|
+
* declaredOrder — and because the slot types are funcs, accessor-carrying
|
|
671
|
+
* shapes are never JSON-safe or dyn-convertible; the enumeration surfaces
|
|
672
|
+
* Node would answer differently (Object.keys includes accessor names,
|
|
673
|
+
* values/entries and spread invoke the getters) fence by name at their
|
|
674
|
+
* lowerings. */
|
|
675
|
+
export declare function accessorSlotProp(fieldName: string): {
|
|
676
|
+
kind: "get" | "set";
|
|
677
|
+
prop: string;
|
|
678
|
+
} | null;
|
|
679
|
+
/** True when the shape carries at least one accessor slot (see
|
|
680
|
+
* accessorSlotProp) — the predicate behind every enumeration-surface
|
|
681
|
+
* fence. */
|
|
682
|
+
export declare function shapeHasAccessorSlots(shape: IrRecordShape): boolean;
|
|
683
|
+
export interface IrUnionDef {
|
|
684
|
+
/** Frontend-assigned union id (`u0`, `u1`, ...). */
|
|
685
|
+
id: string;
|
|
686
|
+
/** ≥2 pairwise-distinct arm types in canonical (typeKey-sorted) order;
|
|
687
|
+
* an arm's index here is its runtime tag. Never void/func/union; the
|
|
688
|
+
* unit kinds (undefinedT/nullT) are payload-less arms. */
|
|
689
|
+
arms: IrType[];
|
|
690
|
+
}
|
|
691
|
+
export interface IrFunction {
|
|
692
|
+
/** Original TS name (mangling is a backend concern). Lifted lambdas get
|
|
693
|
+
* synthetic '%'-prefixed names ('%' can't appear in a TS identifier). */
|
|
694
|
+
name: string;
|
|
695
|
+
params: IrParam[];
|
|
696
|
+
returnType: IrType;
|
|
697
|
+
/** All locals including params, pre-collected and scope-flat: ids are
|
|
698
|
+
* unique per function ("x.0", "x.1" for shadowing). The frontend resolves
|
|
699
|
+
* lexical scoping; backends and future SSA both want exactly this. */
|
|
700
|
+
locals: IrLocal[];
|
|
701
|
+
/** Present on lifted functions that capture enclosing bindings: the boxed
|
|
702
|
+
* variables received through the closure environment, in caps[] order.
|
|
703
|
+
* Each is also listed in `locals` (with boxed: true); it is NOT a param. */
|
|
704
|
+
captures?: IrParam[];
|
|
705
|
+
/** Async: the body runs on a fiber; `returnType` is the INNER type T (a
|
|
706
|
+
* `return v` fulfills with v) while call sites receive Promise<T>. */
|
|
707
|
+
async?: true;
|
|
708
|
+
/** Generator (`function*`): the body runs on a fiber created SUSPENDED
|
|
709
|
+
* (nothing runs until the first `.next()`); `returnType` is the
|
|
710
|
+
* generator's TReturn (VOID when it carries no value — `return;`
|
|
711
|
+
* completes with the undefined arm) while call sites receive the
|
|
712
|
+
* generator type `{ yieldT, retT: returnType, nextT }` from an emitted
|
|
713
|
+
* spawn wrapper that only allocates. `yieldT` is what `yield e` sends
|
|
714
|
+
* out, `nextT` what `.next(v)` sends in (the yield expression's result
|
|
715
|
+
* type). Mutually exclusive with `async` (async generators are fenced). */
|
|
716
|
+
generator?: {
|
|
717
|
+
yieldT: IrType;
|
|
718
|
+
nextT: IrType;
|
|
719
|
+
};
|
|
720
|
+
body: IrStmt[];
|
|
721
|
+
loc: SrcLoc;
|
|
722
|
+
}
|
|
723
|
+
export interface IrParam {
|
|
724
|
+
localId: string;
|
|
725
|
+
name: string;
|
|
726
|
+
type: IrType;
|
|
727
|
+
}
|
|
728
|
+
export interface IrGlobal {
|
|
729
|
+
/** "%g.<qualifier>.<name>" — distinct namespace from local ids. */
|
|
730
|
+
id: string;
|
|
731
|
+
name: string;
|
|
732
|
+
type: IrType;
|
|
733
|
+
mutable: boolean;
|
|
734
|
+
}
|
|
735
|
+
export interface IrLocal {
|
|
736
|
+
id: string;
|
|
737
|
+
name: string;
|
|
738
|
+
type: IrType;
|
|
739
|
+
mutable: boolean;
|
|
740
|
+
/** Captured by a nested function: the variable lives in a refcounted box
|
|
741
|
+
* (a shared binding — mutations are visible through every capture). All
|
|
742
|
+
* access, including in the declaring function, goes through the box. */
|
|
743
|
+
boxed?: true;
|
|
744
|
+
/** A forward-captured const (a function declared BEFORE the const it
|
|
745
|
+
* captures): the box is allocated TDZ-empty at scope entry (a `varDecl`
|
|
746
|
+
* with `init: null`) so earlier closures can capture it, and the source
|
|
747
|
+
* declaration initializes it via `assign`. Every read tests the box —
|
|
748
|
+
* empty throws JS's catchable ReferenceError ("Cannot access 'name'
|
|
749
|
+
* before initialization"), exactly Node's temporal dead zone. Always
|
|
750
|
+
* paired with `boxed`; restricted to pointer-backed types (the NULL slot
|
|
751
|
+
* IS the TDZ sentinel). Capture entries inherit the flag. */
|
|
752
|
+
tdz?: true;
|
|
753
|
+
}
|
|
754
|
+
export type IrStmt =
|
|
755
|
+
/** First initialization of a local at its source position. `init: null`
|
|
756
|
+
* means "declared, uninitialized" (`let x: number;`) — the local must be
|
|
757
|
+
* `mutable`. SOUNDNESS: tsc strict-mode definite-assignment analysis
|
|
758
|
+
* (TS2454 "used before being assigned") rejects any READ before an
|
|
759
|
+
* assignment on every path, so backends never need a runtime
|
|
760
|
+
* initialized-check; refcounted locals simply stay NULL until the first
|
|
761
|
+
* `assign`. */
|
|
762
|
+
{
|
|
763
|
+
kind: "varDecl";
|
|
764
|
+
localId: string;
|
|
765
|
+
init: IrExpr | null;
|
|
766
|
+
loc: SrcLoc;
|
|
767
|
+
} | {
|
|
768
|
+
kind: "assign";
|
|
769
|
+
localId: string;
|
|
770
|
+
value: IrExpr;
|
|
771
|
+
loc: SrcLoc;
|
|
772
|
+
} | {
|
|
773
|
+
kind: "exprStmt";
|
|
774
|
+
expr: IrExpr;
|
|
775
|
+
loc: SrcLoc;
|
|
776
|
+
} | {
|
|
777
|
+
kind: "if";
|
|
778
|
+
cond: IrExpr;
|
|
779
|
+
then: IrStmt[];
|
|
780
|
+
else_: IrStmt[] | null;
|
|
781
|
+
loc: SrcLoc;
|
|
782
|
+
}
|
|
783
|
+
/** `labels` (here and on doWhile/for/forOf/switch/block): the JS label
|
|
784
|
+
* names of the enclosing `lbl:` statements, outermost first — the targets
|
|
785
|
+
* a labeled `break lbl`/`continue lbl` names. A statement without labels
|
|
786
|
+
* omits the field. The frontend attaches labels only to constructs a
|
|
787
|
+
* labeled jump can bind to (loops, switch, and the block wrapper it puts
|
|
788
|
+
* around every other labeled statement form); label RESOLUTION is done by
|
|
789
|
+
* matching a jump's `label` against the innermost enclosing statement
|
|
790
|
+
* whose `labels` contains it (names are unique per nesting chain — tsc
|
|
791
|
+
* rejects duplicate labels). */
|
|
792
|
+
| {
|
|
793
|
+
kind: "while";
|
|
794
|
+
cond: IrExpr;
|
|
795
|
+
body: IrStmt[];
|
|
796
|
+
labels?: string[];
|
|
797
|
+
loc: SrcLoc;
|
|
798
|
+
}
|
|
799
|
+
/** `do { body } while (cond)`: body executes at least once; the condition
|
|
800
|
+
* (bool-typed, truthiness pre-wrapped like while) evaluates after each
|
|
801
|
+
* pass. `continue` jumps to the CONDITION, not the top of the body. */
|
|
802
|
+
| {
|
|
803
|
+
kind: "doWhile";
|
|
804
|
+
body: IrStmt[];
|
|
805
|
+
cond: IrExpr;
|
|
806
|
+
labels?: string[];
|
|
807
|
+
loc: SrcLoc;
|
|
808
|
+
}
|
|
809
|
+
/** JS-exact switch. The discriminant evaluates exactly once; case `test`
|
|
810
|
+
* expressions evaluate lazily IN SOURCE ORDER (a test after the matching
|
|
811
|
+
* one never evaluates), compared against the discriminant with strict
|
|
812
|
+
* equality (f64/bool: `===`; string: content equality). `test: null` is
|
|
813
|
+
* the default clause — it may appear in any position: it is entered only
|
|
814
|
+
* after every test misses, but execution FALLS THROUGH case bodies in
|
|
815
|
+
* source order (default's included) until a `break` or the end. The whole
|
|
816
|
+
* case-body sequence is ONE lexical scope (a `let` in one case is visible
|
|
817
|
+
* in later cases). `break` inside binds to the switch; `continue` binds to
|
|
818
|
+
* the enclosing loop. Discriminant and tests share one IR kind:
|
|
819
|
+
* f64, string, or bool. */
|
|
820
|
+
| {
|
|
821
|
+
kind: "switch";
|
|
822
|
+
disc: IrExpr;
|
|
823
|
+
cases: {
|
|
824
|
+
test: IrExpr | null;
|
|
825
|
+
body: IrStmt[];
|
|
826
|
+
}[];
|
|
827
|
+
labels?: string[];
|
|
828
|
+
loc: SrcLoc;
|
|
829
|
+
} | {
|
|
830
|
+
kind: "for";
|
|
831
|
+
init: IrStmt | null;
|
|
832
|
+
cond: IrExpr | null;
|
|
833
|
+
update: IrStmt | null;
|
|
834
|
+
body: IrStmt[];
|
|
835
|
+
labels?: string[];
|
|
836
|
+
loc: SrcLoc;
|
|
837
|
+
}
|
|
838
|
+
/** Element write `a[i] = v` — statement-only, like `assign`. Valid indices
|
|
839
|
+
* are [0, length]; i == length appends (JS would create a hole past that —
|
|
840
|
+
* scriptc traps instead, see SEMANTICS.md). Ownership of a refcounted
|
|
841
|
+
* value MOVES into the array; the replaced element is released. */
|
|
842
|
+
| {
|
|
843
|
+
kind: "arraySet";
|
|
844
|
+
arr: IrExpr;
|
|
845
|
+
index: IrExpr;
|
|
846
|
+
value: IrExpr;
|
|
847
|
+
loc: SrcLoc;
|
|
848
|
+
}
|
|
849
|
+
/** Typed-array element write `b[i] = v` — arraySet's sibling for bytes
|
|
850
|
+
* receivers: statement-only, receiver and index like bytesIntrinsic
|
|
851
|
+
* `get` (any invalid index TRAPS — JS would ignore the write, a
|
|
852
|
+
* documented divergence), value an f64 coerced per the element kind
|
|
853
|
+
* (ToUint8/ToUint32 modular truncation, double→float rounding). Unlike
|
|
854
|
+
* arraySet there is NO append at i == len: typed arrays are
|
|
855
|
+
* fixed-length. */
|
|
856
|
+
| {
|
|
857
|
+
kind: "bytesSet";
|
|
858
|
+
arr: IrExpr;
|
|
859
|
+
index: IrExpr;
|
|
860
|
+
value: IrExpr;
|
|
861
|
+
loc: SrcLoc;
|
|
862
|
+
}
|
|
863
|
+
/** `for (const x of arr)`: iterates by ascending index, re-reading the
|
|
864
|
+
* length each iteration (JS-exact for arrays). `localId` is a fresh const
|
|
865
|
+
* binding per iteration holding the element (for refcounted elements: an
|
|
866
|
+
* owned +1 reference, released when the iteration's scope exits). */
|
|
867
|
+
| {
|
|
868
|
+
kind: "forOf";
|
|
869
|
+
localId: string;
|
|
870
|
+
iterable: IrExpr;
|
|
871
|
+
body: IrStmt[];
|
|
872
|
+
labels?: string[];
|
|
873
|
+
loc: SrcLoc;
|
|
874
|
+
} | {
|
|
875
|
+
kind: "return";
|
|
876
|
+
value: IrExpr | null;
|
|
877
|
+
loc: SrcLoc;
|
|
878
|
+
}
|
|
879
|
+
/** Field write `obj.f = v` — statement-only, like `assign`/`arraySet`.
|
|
880
|
+
* Evaluation order: obj, then value. The old value is released; ownership
|
|
881
|
+
* of a refcounted new value MOVES into the object. */
|
|
882
|
+
| {
|
|
883
|
+
kind: "fieldSet";
|
|
884
|
+
obj: IrExpr;
|
|
885
|
+
className: string;
|
|
886
|
+
field: string;
|
|
887
|
+
value: IrExpr;
|
|
888
|
+
loc: SrcLoc;
|
|
889
|
+
}
|
|
890
|
+
/** Record field write `r.f = v` — mirrors `fieldSet` exactly (evaluation
|
|
891
|
+
* order obj then value; old value released; refcounted new value moved
|
|
892
|
+
* in), with a shape id in place of a class name. */
|
|
893
|
+
| {
|
|
894
|
+
kind: "recordSet";
|
|
895
|
+
obj: IrExpr;
|
|
896
|
+
shapeId: string;
|
|
897
|
+
field: string;
|
|
898
|
+
value: IrExpr;
|
|
899
|
+
loc: SrcLoc;
|
|
900
|
+
}
|
|
901
|
+
/** Dynamic-keyed record write `r[k] = v` — index-signature shapes only.
|
|
902
|
+
* `value` has the index signature's value type (dyn included). Declared
|
|
903
|
+
* keys write THROUGH to the struct slot: a dyn value validates against
|
|
904
|
+
* the field's type first (the dynCheck walker — a mismatched write
|
|
905
|
+
* throws the catchable TypeError instead of corrupting the slot; JS
|
|
906
|
+
* would store anything, a documented divergence), non-dyn values store
|
|
907
|
+
* directly (their type equals the field's by the index-signature
|
|
908
|
+
* consistency rule). Undeclared keys insert/replace in the overflow map
|
|
909
|
+
* (insertion order preserved, exactly Map). Evaluation order: obj, key,
|
|
910
|
+
* value. Ownership of a refcounted value MOVES in; replaced values are
|
|
911
|
+
* released. MAY THROW when the shape has dyn-valued declared fields to
|
|
912
|
+
* validate (the emitted helper is in the may-throw seed set then).
|
|
913
|
+
* `overflowOnly` (a LITERAL key naming no declared field): a pure
|
|
914
|
+
* overflow insert — no declared collision exists, so no validation, no
|
|
915
|
+
* throw, and declared fields need not take the index-value type. */
|
|
916
|
+
| {
|
|
917
|
+
kind: "recordKeySet";
|
|
918
|
+
obj: IrExpr;
|
|
919
|
+
shapeId: string;
|
|
920
|
+
key: IrExpr;
|
|
921
|
+
value: IrExpr;
|
|
922
|
+
overflowOnly?: true;
|
|
923
|
+
loc: SrcLoc;
|
|
924
|
+
}
|
|
925
|
+
/** Statement-position `delete obj[k]` on a PURE index-signature shape
|
|
926
|
+
* (no declared fields — the frontend fences hybrids: a struct slot
|
|
927
|
+
* cannot be removed): drop the overflow entry, releasing its key and
|
|
928
|
+
* value — exactly a Map delete, insertion order of survivors kept.
|
|
929
|
+
* Deleting an absent key is a no-op, like JS. Evaluation order: obj,
|
|
930
|
+
* key; both borrowed. Never throws. */
|
|
931
|
+
| {
|
|
932
|
+
kind: "recordKeyDelete";
|
|
933
|
+
obj: IrExpr;
|
|
934
|
+
shapeId: string;
|
|
935
|
+
key: IrExpr;
|
|
936
|
+
loc: SrcLoc;
|
|
937
|
+
}
|
|
938
|
+
/** Unlabeled: `break` binds to the innermost enclosing loop OR switch
|
|
939
|
+
* (labeled BLOCK targets are skipped); `continue` to the innermost
|
|
940
|
+
* enclosing loop, skipping any switches in between (validated). With
|
|
941
|
+
* `label`: the jump binds to the innermost enclosing statement whose
|
|
942
|
+
* `labels` contains it — any labeled loop/switch/block for `break`, a
|
|
943
|
+
* labeled loop for `continue` (`continue` re-enters at the loop's own
|
|
944
|
+
* continue point: the condition for while/doWhile, the update for
|
|
945
|
+
* for/forOf). The frontend guarantees the label resolves (tsc validates
|
|
946
|
+
* label targets); the validator re-checks. */
|
|
947
|
+
| {
|
|
948
|
+
kind: "break";
|
|
949
|
+
label?: string;
|
|
950
|
+
loc: SrcLoc;
|
|
951
|
+
} | {
|
|
952
|
+
kind: "continue";
|
|
953
|
+
label?: string;
|
|
954
|
+
loc: SrcLoc;
|
|
955
|
+
}
|
|
956
|
+
/** A bare lexical block `{ ... }` — its own scope. `labels` makes it a
|
|
957
|
+
* labeled-break target (`lbl: { ... break lbl; ... }` and the wrapper
|
|
958
|
+
* the frontend puts around labeled non-loop statements). */
|
|
959
|
+
| {
|
|
960
|
+
kind: "block";
|
|
961
|
+
body: IrStmt[];
|
|
962
|
+
labels?: string[];
|
|
963
|
+
loc: SrcLoc;
|
|
964
|
+
}
|
|
965
|
+
/** `throw v`. Any non-void value type can be thrown; ownership of a
|
|
966
|
+
* refcounted value MOVES into the runtime's exception cell. Terminates
|
|
967
|
+
* the path like `return`: control unwinds to the innermost enclosing
|
|
968
|
+
* tryCatch handler, or out of the function (backends release the frames
|
|
969
|
+
* and scopes the unwind exits — exactly the release-on-jump discipline). */
|
|
970
|
+
| {
|
|
971
|
+
kind: "throw";
|
|
972
|
+
value: IrExpr;
|
|
973
|
+
loc: SrcLoc;
|
|
974
|
+
}
|
|
975
|
+
/** A DEFERRED compile fence (JavaScript sources only): the statement's
|
|
976
|
+
* construct has no static lowering, and JS carries no annotations to
|
|
977
|
+
* change that — so the fence fires when the statement RUNS instead of
|
|
978
|
+
* failing the build (the JS-input design: inference gaps land where
|
|
979
|
+
* `any` lands — honest fences, never silent misbehavior). Executing it
|
|
980
|
+
* throws a catchable Error whose message names the construct and whose
|
|
981
|
+
* `code` carries the SC diagnostic code; unwinds exactly like `throw`.
|
|
982
|
+
* TypeScript sources produce it only as the tsc-unreachable fallthrough
|
|
983
|
+
* trap (appendImplicitUndefinedReturn's SC9002) — their construct fences
|
|
984
|
+
* stay compile errors. */
|
|
985
|
+
| {
|
|
986
|
+
kind: "runtimeFence";
|
|
987
|
+
code: string;
|
|
988
|
+
message: string;
|
|
989
|
+
loc: SrcLoc;
|
|
990
|
+
}
|
|
991
|
+
/** Rethrow of a catch binding (`throw e` where e is the binding):
|
|
992
|
+
* re-raises the SAVED exception exactly — kind and payload preserved,
|
|
993
|
+
* payload retained (the binding stays live until its scope exits).
|
|
994
|
+
* Terminates the path like `throw`. */
|
|
995
|
+
| {
|
|
996
|
+
kind: "rethrow";
|
|
997
|
+
localId: string;
|
|
998
|
+
loc: SrcLoc;
|
|
999
|
+
}
|
|
1000
|
+
/** `try { } catch (e)? { } finally { }`. At least one of
|
|
1001
|
+
* catchBody/finallyBody is present. `catchBody` runs iff the try body
|
|
1002
|
+
* raised; entering it TAKES the exception (the pending flag clears).
|
|
1003
|
+
* With `catchLocalId` null (bindingless `catch { }`) the payload is
|
|
1004
|
+
* discarded; with a binding, the payload MOVES into a fresh caught
|
|
1005
|
+
* snapshot box bound to that local (declared in `locals` with the
|
|
1006
|
+
* `caught` type), scoped to the catch body. `finallyBody` runs on normal
|
|
1007
|
+
* completion AND on the exception path (after catch, or with the
|
|
1008
|
+
* exception still pending when there is no catch — it keeps propagating
|
|
1009
|
+
* after the finally completes; a throw inside the finally replaces it).
|
|
1010
|
+
* A `return` inside tryBody/catchBody additionally runs the finally on
|
|
1011
|
+
* its way out (the backend's PENDING-RETURN path: the value is computed
|
|
1012
|
+
* and snapshotted FIRST, every crossed finally runs inner-to-outer, then
|
|
1013
|
+
* the function returns — finally mutations of returned locals are
|
|
1014
|
+
* invisible, Node-exact; a throw inside such a finally replaces the
|
|
1015
|
+
* pending return, releasing the snapshot). The frontend still rejects
|
|
1016
|
+
* break/continue crossing a try-with-finally and ANY jump out of a
|
|
1017
|
+
* finally body, so normal, exception, and pending-return are the only
|
|
1018
|
+
* completions a finally sees; plain try/catch has no such restriction
|
|
1019
|
+
* (jumps out release the try scopes like any other jump). Each body is
|
|
1020
|
+
* its own lexical scope. */
|
|
1021
|
+
| {
|
|
1022
|
+
kind: "tryCatch";
|
|
1023
|
+
tryBody: IrStmt[];
|
|
1024
|
+
catchBody: IrStmt[] | null;
|
|
1025
|
+
catchLocalId: string | null;
|
|
1026
|
+
finallyBody: IrStmt[] | null;
|
|
1027
|
+
loc: SrcLoc;
|
|
1028
|
+
};
|
|
1029
|
+
/** The complete array method/property surface (mirrors ambient/scriptc.d.ts).
|
|
1030
|
+
* `map`/`filter`/`forEach` are NOT here: the frontend desugars them to
|
|
1031
|
+
* synthetic loop functions over existing nodes (see docs/ir.md). */
|
|
1032
|
+
/** `slice` is JS-exact shallow copy (ToIntegerOrInfinity indices, negatives
|
|
1033
|
+
* from the end, clamping; omitted args omitted from `args` — backends fill
|
|
1034
|
+
* 0 / +Infinity, the strIntrinsic convention); ref elements retain into
|
|
1035
|
+
* the fresh array. */
|
|
1036
|
+
export type IrArrIntrinsicMethod = "length" | "push" | "pushSpread" | "pop" | "indexOf" | "includes" | "join" | "slice" | "shift" | "splice";
|
|
1037
|
+
/** The Map method/property surface (mirrors ambient/scriptc.d.ts) plus the
|
|
1038
|
+
* iteration primitives behind the forEach desugar. `forEach` itself is NOT
|
|
1039
|
+
* here — like array map/filter/forEach it desugars in the frontend to a
|
|
1040
|
+
* synthetic loop function whose body walks the dense entries array with
|
|
1041
|
+
* `iterCount`/`iterLive`/`iterKey`/`iterValue` (indices stay stable under
|
|
1042
|
+
* callback mutation because the runtime never compacts between
|
|
1043
|
+
* `iterEnter`/`iterExit` — live-iteration semantics, Node-exact). The iter*
|
|
1044
|
+
* members are compiler-internal: no ambient declaration reaches them. */
|
|
1045
|
+
export type IrMapIntrinsicMethod = "get" | "set" | "has" | "delete" | "size" | "clear" | "iterCount" | "iterLive" | "iterKey" | "iterValue" | "iterEnter" | "iterExit";
|
|
1046
|
+
/** The Set method/property surface — Map's minus get/set/iterValue (there
|
|
1047
|
+
* is no value slot; `add` fills set's role) plus `add`. `forEach` desugars
|
|
1048
|
+
* in the frontend exactly like Map's, over the same iteration primitives —
|
|
1049
|
+
* iterKey doubles as the element read (JS's Set forEach passes the element
|
|
1050
|
+
* as both `value` and `key`). */
|
|
1051
|
+
export type IrSetIntrinsicMethod = "add" | "has" | "delete" | "size" | "clear" | "iterCount" | "iterLive" | "iterKey" | "iterEnter" | "iterExit"
|
|
1052
|
+
/** `[...set]` and friends: drain the live entries into a FRESH elem[]
|
|
1053
|
+
* in insertion order (tombstones skipped — the same walk the forEach
|
|
1054
|
+
* desugar does, folded into one runtime call; no user code runs during
|
|
1055
|
+
* the drain, so live-iteration rules are moot). Receiver borrowed;
|
|
1056
|
+
* the array is owned (+1), string elements retained into it. */
|
|
1057
|
+
| "toArray";
|
|
1058
|
+
/** The complete string method/property surface (mirrors ambient/scriptc.d.ts).
|
|
1059
|
+
* toLowerCase/toUpperCase are the one lre-backed pair (ECMA Default Case
|
|
1060
|
+
* Conversion via libunicode's tables — scr_regex.c): their presence sets
|
|
1061
|
+
* the regex LINK flag like a regex literal does (moduleUsesRegex).
|
|
1062
|
+
* `split` is the STRING-separator form (regex separators are
|
|
1063
|
+
* regexIntrinsic), no limit: args[0] the separator, result a fresh +1
|
|
1064
|
+
* string[] — the empty separator splits per UTF-16 code unit (astral
|
|
1065
|
+
* halves become U+FFFD, divergence 2). `padStart`/`padEnd` take (target
|
|
1066
|
+
* length, fill) — the frontend completes an omitted fill to " ", Node's
|
|
1067
|
+
* default. `trimStart`/`trimEnd` are trim's one-sided halves. */
|
|
1068
|
+
export type IrStrIntrinsicMethod = "length" | "charCodeAt" | "charAt" | "indexOf" | "includes" | "startsWith" | "endsWith" | "slice" | "substring" | "repeat" | "trim" | "trimStart" | "trimEnd" | "split" | "padStart" | "padEnd" | "toLowerCase" | "toUpperCase" | "isWellFormed" | "toWellFormed" | "cpAt";
|
|
1069
|
+
/** The typed-array/Buffer method surface (bytesIntrinsic). Receiver/arg
|
|
1070
|
+
* conventions (validated): `length`/`byteLength` are property reads → f64;
|
|
1071
|
+
* `get` takes one f64 index → f64 (trap on any invalid index, like
|
|
1072
|
+
* arrayGet — the write side is the bytesSet STATEMENT); `slice` takes
|
|
1073
|
+
* 0–2 f64 relative indices (omitted args are OMITTED from `args`, like
|
|
1074
|
+
* strIntrinsic — backends fill start 0 / end +Infinity) → a fresh
|
|
1075
|
+
* same-elem bytes COPY (`subarray` lowers here too: copying is the
|
|
1076
|
+
* documented divergence); `setFrom` (`dst.set(src, offset?)`) takes a
|
|
1077
|
+
* same-elem bytes src and an optional f64 offset (omitted = 0) → void,
|
|
1078
|
+
* THROWS Node's RangeError on overflow (may-throw seed); `toString` takes
|
|
1079
|
+
* one string encoding arg (the frontend completes an omitted one to
|
|
1080
|
+
* "utf8" and fences non-literal / unsupported encodings; u8 receivers
|
|
1081
|
+
* only) → owned +1 string, never throws; the numeric families (u8
|
|
1082
|
+
* receivers only) carry their KIND as args[0], always a strLit the
|
|
1083
|
+
* backend maps to the runtime's tag: `readNum` [kind, offset] /
|
|
1084
|
+
* `writeNum` [kind, value, offset] cover the fixed widths (kind "u8",
|
|
1085
|
+
* "i8", then "u16be"/"u16le"-style width+endian tokens through "f64le");
|
|
1086
|
+
* `readNumVar` [kind, offset, byteLength] / `writeNumVar` [kind, value,
|
|
1087
|
+
* offset, byteLength] are the variable-width read/writeUIntLE family
|
|
1088
|
+
* (kind "ube"/"ule"/"ibe"/"ile"). All four THROW Node's RangeErrors on
|
|
1089
|
+
* bad values/offsets/byteLengths (may-throw seeds); writes return
|
|
1090
|
+
* offset + width. Receivers and args are BORROWED; refcounted
|
|
1091
|
+
* results are owned (+1).
|
|
1092
|
+
*
|
|
1093
|
+
* The DataView surface rides the same node (DataView maps to bytes<u8> —
|
|
1094
|
+
* at runtime a borrowed VIEW aliasing its owner's storage, so no aliasing
|
|
1095
|
+
* divergence exists): `byteOffset` is a property read → f64 (0 for owners,
|
|
1096
|
+
* the view's offset for a DataView); `dataViewNew` (`new
|
|
1097
|
+
* DataView(x.buffer, byteOffset?, byteLength?)`) takes the BYTES value x
|
|
1098
|
+
* as the receiver (the frontend peels the syntactic `.buffer`) and 0–2
|
|
1099
|
+
* f64 args (omitted args OMITTED, like slice) → a fresh bytes<u8> view
|
|
1100
|
+
* retaining x's owner, THROWS Node's RangeErrors on bad indices; the
|
|
1101
|
+
* `dvGet*` getters take one f64 byte offset plus, on the multi-byte kinds,
|
|
1102
|
+
* an optional bool littleEndian (omitted = big-endian, the JS default) →
|
|
1103
|
+
* f64, THROWING Node's constant "Offset is outside the bounds of the
|
|
1104
|
+
* DataView" RangeError on any bad offset. `dvGetBigUint64Number`/
|
|
1105
|
+
* `dvGetBigInt64Number` are the COMPOSED `Number(view.getBigUint64(...))`
|
|
1106
|
+
* lowerings — the bare bigint-returning calls are fenced, the wrapped
|
|
1107
|
+
* form converts the 8-byte integer to double exactly as Number(bigint). */
|
|
1108
|
+
export type IrBytesIntrinsicMethod = "length" | "byteLength" | "get" | "slice" | "setFrom" | "toString" | "readNum" | "writeNum" | "readNumVar" | "writeNumVar"
|
|
1109
|
+
/** The comparison/search/mutation surface (u8 receivers only; see the
|
|
1110
|
+
* runtime contract): `equals` [bytes] → bool (never throws);
|
|
1111
|
+
* `compareBuf` [bytes, 0-4 f64 index args — omitted args OMITTED,
|
|
1112
|
+
* Node skips their validation] → f64, THROWS; `indexOf`/`lastIndexOf`
|
|
1113
|
+
* [bytes needle, f64 align (2 = utf16le's even-offset stride), f64
|
|
1114
|
+
* byteOffset?] → f64 and `includes` → bool, never throw (byteOffset
|
|
1115
|
+
* coerces; omitted = Node's search-everything default); the *Num
|
|
1116
|
+
* flavors take [f64 value, f64 byteOffset?] (the value wraps & 0xFF);
|
|
1117
|
+
* `fill` [bytes pattern, 0-2 f64s] / `fillNum`
|
|
1118
|
+
* [f64, 0-2 f64s] / `fillStr` [string, strLit enc, 0-2 f64s] → the
|
|
1119
|
+
* RECEIVER (+1, chaining), THROW; `copy` [bytes target, 0-3 f64s] →
|
|
1120
|
+
* f64 copied count, THROWS; `swap16/32/64` [] → the receiver (+1,
|
|
1121
|
+
* in-place), THROW; `writeStr` [string, strLit enc, f64 offset, f64
|
|
1122
|
+
* length?] → f64 bytes written, THROWS. */
|
|
1123
|
+
| "equals" | "compareBuf" | "indexOf" | "lastIndexOf" | "includes" | "indexOfNum" | "lastIndexOfNum" | "includesNum" | "fill" | "fillNum" | "fillStr" | "copy" | "swap16" | "swap32" | "swap64" | "writeStr" | "byteOffset" | "dataViewNew" | "dvGetUint8" | "dvGetInt8" | "dvGetUint16" | "dvGetInt16" | "dvGetUint32" | "dvGetInt32" | "dvGetFloat32" | "dvGetFloat64" | "dvGetBigUint64Number" | "dvGetBigInt64Number";
|
|
1124
|
+
/** The bytesIntrinsic methods that can raise a catchable error — backends'
|
|
1125
|
+
* may-throw analyses seed on these exactly like MAY_THROW_LIB_FNS. */
|
|
1126
|
+
export declare const MAY_THROW_BYTES_METHODS: ReadonlySet<IrBytesIntrinsicMethod>;
|
|
1127
|
+
/** The regex operation surface. Receiver/arg conventions (validated):
|
|
1128
|
+
* `test` takes a regex receiver and one string arg (bool result); `source`
|
|
1129
|
+
* and `flags` are property reads on a regex receiver (owned string result);
|
|
1130
|
+
* `replace`/`replaceAll`/`split` take a STRING receiver with args[0] the
|
|
1131
|
+
* regex and (for the replaces) args[1] the replacement template — string
|
|
1132
|
+
* replacements only, function replacements are checker-rejected (the
|
|
1133
|
+
* ambient overloads accept only strings). `replaceAll` THROWS Node's
|
|
1134
|
+
* TypeError when the regex lacks /g and `split` THROWS on a pattern with
|
|
1135
|
+
* capture groups (JS would splice the captured values into the result) —
|
|
1136
|
+
* both catchable: backends' may-throw analyses must seed on these two
|
|
1137
|
+
* methods like a `throw`. */
|
|
1138
|
+
/** `match` takes a STRING receiver with args[0] the regex (non-g/y — the
|
|
1139
|
+
* frontend fences literal g/y flags; a g-flagged value reaching the
|
|
1140
|
+
* runtime aborts like test()) and produces the PROGRAM-DEPENDENT
|
|
1141
|
+
* `string[] | null` union: the matched slice [whole, ...captures] wrapped
|
|
1142
|
+
* into the array arm, or the interned null-arm instance for no match. A
|
|
1143
|
+
* NONPARTICIPATING capture holds "" where Node's slot is undefined
|
|
1144
|
+
* (SEMANTICS.md divergence). Never throws. */
|
|
1145
|
+
export type IrRegexIntrinsicMethod = "test" | "match"
|
|
1146
|
+
/** `s.matchAll(re)` — every match as its honest string[] slice (match's
|
|
1147
|
+
* rule), drained EAGERLY into a fresh string[][]: the lazy iterator is
|
|
1148
|
+
* unobservable across the lowered surface (strings are immutable; the
|
|
1149
|
+
* spec clones the regex at the call, so lastIndex games can't reach the
|
|
1150
|
+
* drain either). Non-global regexes THROW Node's exact TypeError
|
|
1151
|
+
* (catchable — replaceAll's stance). */
|
|
1152
|
+
| "matchAll"
|
|
1153
|
+
/** matchAll's companion-index form (the for-of-over-matchAll desugar):
|
|
1154
|
+
* args[1] is a number[] the drain ALSO fills with each match's UTF-16
|
|
1155
|
+
* start index — the row's `.index`, always present (every drained row
|
|
1156
|
+
* matched). Same result and throw contract as matchAll. */
|
|
1157
|
+
| "matchAllInto"
|
|
1158
|
+
/** `s.search(re)` — the first match's UTF-16 index, or -1. Symbol.search
|
|
1159
|
+
* neither reads nor writes lastIndex (a fresh exec from position 0), so
|
|
1160
|
+
* no g/y fence applies: /g is irrelevant and /y anchors at 0 — exactly
|
|
1161
|
+
* Node. Never throws. */
|
|
1162
|
+
| "search" | "source" | "flags" | "replace" | "replaceAll" | "split";
|
|
1163
|
+
/** The complete standard-library surface (mirrors ambient/scriptc.d.ts: the
|
|
1164
|
+
* `process` and `JSON` globals and `declare module "node:fs"`). A closed
|
|
1165
|
+
* union — every member has a signature in the validator's LIB_FN_SIGS and a
|
|
1166
|
+
* scr_* implementation in the runtime (scr_lib.c / scr_json.c). fs.*
|
|
1167
|
+
* failures and json.parse syntax errors THROW (catchable, via the runtime
|
|
1168
|
+
* exception cell); process.* members never throw. JSON.stringify is NOT a
|
|
1169
|
+
* libCall — it lowers to the type-directed `jsonStringify` node below.
|
|
1170
|
+
* island.eval (the internal __island_eval testing hook) exists only in
|
|
1171
|
+
* --dynamic builds — the frontend rejects it otherwise, so backends may
|
|
1172
|
+
* assume the island runtime is linked when they see it; island exceptions
|
|
1173
|
+
* bridge into the exception cell as catchable strings (may-throw). */
|
|
1174
|
+
export type IrLibFn = "island.eval"
|
|
1175
|
+
/** Load an embedded npm package's runtime entry in the island (cached by
|
|
1176
|
+
* the engine's module registry) and take one export: args are the entry
|
|
1177
|
+
* KEY (an embedded module's key, from IrModule.embedded) and the export
|
|
1178
|
+
* name — "default" for default imports, "*" for the namespace object.
|
|
1179
|
+
* --dynamic only, like island.eval; result is an owned jsval. May throw
|
|
1180
|
+
* (a package's top-level code can), bridged catchably. */
|
|
1181
|
+
| "island.import"
|
|
1182
|
+
/** Dynamic `import(spec)`: load a module through the island's module
|
|
1183
|
+
* system — an embedded module's key or a builtin shim's "node:x" key —
|
|
1184
|
+
* and answer an ENGINE promise of its namespace object (always a
|
|
1185
|
+
* promise, never a throw: load and evaluation failures REJECT it,
|
|
1186
|
+
* Node's shape). The frontend wraps the result in jsBridgePromise, so
|
|
1187
|
+
* awaiting parks the fiber and a rejection crosses catchably. --dynamic
|
|
1188
|
+
* only; result is an owned jsval holding the engine promise. */
|
|
1189
|
+
| "island.importDyn"
|
|
1190
|
+
/** A checked cast the boundary can never satisfy, DEFERRED to runtime:
|
|
1191
|
+
* `islandValue as Promise<T>` — the value is an ENGINE promise and T
|
|
1192
|
+
* has no validated exit (Node-typed async APIs put class-shaped
|
|
1193
|
+
* interfaces there), so instead of refusing the build the cast throws a
|
|
1194
|
+
* catchable TypeError AT THE CAST naming the target type (args: the
|
|
1195
|
+
* island value — evaluated, borrowed — and the type name). The result
|
|
1196
|
+
* type is the cast's mapped target (a typed dummy; the exception is
|
|
1197
|
+
* pending). Documented divergence: JS `as` never checks — like the dyn
|
|
1198
|
+
* boundary, a conversion that cannot happen throws instead of lying.
|
|
1199
|
+
* --dynamic only. */
|
|
1200
|
+
| "island.castFail" | "json.parse"
|
|
1201
|
+
/** Keyed WRITE on a dyn DOM value — `h.onDone = cb` / `h["k"] = v` on a
|
|
1202
|
+
* checked-dynamic object (args: receiver, key string, value — all
|
|
1203
|
+
* borrowed; the runtime copies the key and retains the value in). An
|
|
1204
|
+
* OBJ receiver sets the member (later writes win, insertion order
|
|
1205
|
+
* preserved — JS exactly); undefined/null throws Node's catchable
|
|
1206
|
+
* "Cannot set properties of undefined (setting 'k')"; every other kind
|
|
1207
|
+
* throws Node's STRICT-mode "Cannot create property 'k' on <kind>"
|
|
1208
|
+
* (sloppy mode would silently ignore — suite tests are 'use strict';
|
|
1209
|
+
* SEMANTICS.md notes the sloppy divergence: loud, never silent). Void
|
|
1210
|
+
* result; in the may-throw seed set. */
|
|
1211
|
+
| "dyn.keySet"
|
|
1212
|
+
/** Object.defineProperties over DOM values (args: target, descriptors —
|
|
1213
|
+
* both borrowed dyn; result: the target, +1 — JS's return value).
|
|
1214
|
+
* Value descriptors become plain own properties on OBJ and FUNC targets
|
|
1215
|
+
* (writable/enumerable/configurable accepted and IGNORED — DOM
|
|
1216
|
+
* properties are plain data properties, SEMANTICS.md); get/set
|
|
1217
|
+
* descriptors and non-object targets/descriptors throw catchably
|
|
1218
|
+
* (Node's TypeError texts; accessors the loud unsupported Error). In
|
|
1219
|
+
* the may-throw seed set. */
|
|
1220
|
+
| "dyn.defineProps"
|
|
1221
|
+
/** Bare `typeof v` on a dyn value AS A STRING (arg: the dyn value,
|
|
1222
|
+
* borrowed; result: an owned string) — the DOM kind's JS answer:
|
|
1223
|
+
* undefined→"undefined", null/object/array/bytes→"object" (JS's oldest
|
|
1224
|
+
* wart preserved), boolean/number/string by kind, function→"function".
|
|
1225
|
+
* Never throws. */
|
|
1226
|
+
| "dyn.typeof"
|
|
1227
|
+
/** toString() on a checked-dynamic receiver: runtime kind dispatch
|
|
1228
|
+
* (bytes decode per the literal encoding — utf8 default; strings,
|
|
1229
|
+
* numbers, booleans, arrays, objects answer JS-exactly; undefined and
|
|
1230
|
+
* null throw the catchable TypeError). */
|
|
1231
|
+
| "dyn.toString" | "fs.readFileSync"
|
|
1232
|
+
/** readFileSync(path) — the Buffer read (+1 bytes); throws catchably
|
|
1233
|
+
* like the utf8 form. */
|
|
1234
|
+
| "fs.readFileSyncBuf"
|
|
1235
|
+
/** readFileSync(path, enc) with a RUNTIME encoding (an untyped JS
|
|
1236
|
+
* parameter): undefined/null answer Buffers, utf8 a string, other real
|
|
1237
|
+
* encodings fence loudly, unknown names throw ERR_UNKNOWN_ENCODING. */
|
|
1238
|
+
| "fs.readFileSyncDyn" | "fs.writeFileSync" | "fs.appendFileSync" | "fs.existsSync" | "fs.mkdirSync" | "fs.rmSync" | "fs.rmdirSync" | "fs.readdirSync"
|
|
1239
|
+
/** node:path (scr_path.c ports BOTH of Node's implementations
|
|
1240
|
+
* function-by-function): the `path.*` family is posix, the
|
|
1241
|
+
* `path.win32*` family is Node v24's path.win32 byte-for-byte — the
|
|
1242
|
+
* frontend binds the bare module to the TARGET platform's family
|
|
1243
|
+
* (Node on Windows IS path.win32) and the path.posix / path.win32
|
|
1244
|
+
* namespaces to their own family everywhere. join and resolve take ONE
|
|
1245
|
+
* string[] arg — the frontend packs the variadic call's arguments into
|
|
1246
|
+
* an array literal. basename always receives its suffix (the frontend
|
|
1247
|
+
* completes an omitted one with "", a Node no-op). toNamespacedPath is
|
|
1248
|
+
* the posix identity and the win32 \\?\-prefixer. None of these throw;
|
|
1249
|
+
* the resolves consult the process cwd like Node's. */
|
|
1250
|
+
| "path.join" | "path.resolve" | "path.normalize" | "path.dirname" | "path.basename" | "path.extname" | "path.isAbsolute" | "path.relative" | "path.toNamespacedPath" | "path.win32Join" | "path.win32Resolve" | "path.win32Normalize" | "path.win32Dirname" | "path.win32Basename" | "path.win32Extname" | "path.win32IsAbsolute" | "path.win32Relative" | "path.win32ToNamespacedPath"
|
|
1251
|
+
/** node:os: homedir is $HOME else getpwuid(3); tmpdir is Node's env
|
|
1252
|
+
* cascade ($TMPDIR/$TMP/$TEMP else /tmp, one trailing slash trimmed).
|
|
1253
|
+
* os.platform() lowers to process.platform — one implementation. */
|
|
1254
|
+
| "os.homedir"
|
|
1255
|
+
/** os.release(): uname(2)'s release field — Node's own implementation
|
|
1256
|
+
* (the kernel version string, e.g. "24.6.0" on macOS 15). Interned; +1
|
|
1257
|
+
* per read. Never throws. */
|
|
1258
|
+
| "os.release"
|
|
1259
|
+
/** The os.userInfo() field trio (uv_os_get_passwd's slices): pw_name,
|
|
1260
|
+
* pw_shell, pw_dir — the PASSWD homedir, not os.homedir's $HOME-first
|
|
1261
|
+
* cascade (Node's own split). The frontend assembles the UserInfo
|
|
1262
|
+
* record from these plus getuid/getgid. +1 fresh strings; a passwd
|
|
1263
|
+
* lookup failure aborts (Node throws a system error there — no
|
|
1264
|
+
* compiled program path reaches it for the running uid). */
|
|
1265
|
+
| "os.userName" | "os.userShell" | "os.userHomedir" | "os.tmpdir"
|
|
1266
|
+
/** os.networkInterfaces(): getifaddrs(3) → the Dict<NetworkInterfaceInfo[]>
|
|
1267
|
+
* record, built inline by the emitter from a runtime snapshot (scr_lib.c).
|
|
1268
|
+
* The result type is the CALL SITE's mapped @types/node shape — a pure
|
|
1269
|
+
* index-signature record whose value is `Info[] | undefined`, Info a
|
|
1270
|
+
* two-record union (IPv4: scopeid `number | undefined` holding undefined;
|
|
1271
|
+
* IPv6: scopeid number) — verified structurally by the frontend. Rows
|
|
1272
|
+
* match libuv's filter (IFF_UP && IFF_RUNNING, AF_INET/AF_INET6; loopback
|
|
1273
|
+
* = internal; MACs from the interface's link-level sibling entry, zeros
|
|
1274
|
+
* when absent; cidr from the netmask's contiguous prefix, the null arm
|
|
1275
|
+
* when it is missing or non-contiguous). Key/row order follows the OS's
|
|
1276
|
+
* getifaddrs enumeration — Node itself does not guarantee an order.
|
|
1277
|
+
* Fresh +1 record; never throws (a getifaddrs failure yields {}). */
|
|
1278
|
+
| "os.networkInterfaces"
|
|
1279
|
+
/** `Math.max(...xs)` / `Math.min(...xs)` over one spread number[]
|
|
1280
|
+
* (scr_number.c): the JS fold exactly — any NaN element poisons the
|
|
1281
|
+
* result, ±0 order by the JS comparison (max prefers +0, min prefers
|
|
1282
|
+
* -0), and the empty array yields -Infinity / +Infinity like the
|
|
1283
|
+
* zero-argument calls. Borrows the array; never throws. */
|
|
1284
|
+
| "math.maxArr" | "math.minArr"
|
|
1285
|
+
/** `fs.readdirSync(path, { withFileTypes: true })` — Dirent rows over
|
|
1286
|
+
* one readdir pass (scr_lib.c's scandir snapshot; DT_UNKNOWN falls back
|
|
1287
|
+
* to lstat, Node's getDirents rule). The result type is the call site's
|
|
1288
|
+
* interned Dirent record array (name, parentPath, hidden %dtype in
|
|
1289
|
+
* libuv's UV_DIRENT encoding) — verified by the frontend; the emitter
|
|
1290
|
+
* assembles the rows from the snapshot. OS order, no "."/"..". Throws
|
|
1291
|
+
* Node's scandir errno error (may-throw seed set); fresh +1 array. */
|
|
1292
|
+
| "fs.readdirTypesSync"
|
|
1293
|
+
/** `Math.floor(x)` — C floor() IS the JS operation (NaN/±0/±Infinity
|
|
1294
|
+
* pass through bit-exactly). Never throws. */
|
|
1295
|
+
| "math.floor"
|
|
1296
|
+
/** `Math.min(a, b)` / `Math.max(a, b)` — the two-argument scalar forms
|
|
1297
|
+
* (scr_lib.c), JS-exact like the Arr folds: NaN poisons, max prefers +0
|
|
1298
|
+
* over -0 (min the reverse). C fmin/fmax are NOT these (they drop NaN).
|
|
1299
|
+
* Never throw. */
|
|
1300
|
+
| "math.min" | "math.max"
|
|
1301
|
+
/** `Math.random()` — a uniform double in [0,1) with the spec's 53-bit
|
|
1302
|
+
* granularity, drawn from arc4random_buf (the CSPRNG behind the crypto
|
|
1303
|
+
* lowerings). Same distribution as Node, NECESSARILY different sequence
|
|
1304
|
+
* (SEMANTICS.md 62 — no seeded sequence exists to match). Never throws. */
|
|
1305
|
+
| "math.random"
|
|
1306
|
+
/** Math.abs (C fabs — IS the JS operation) and Math.round (scr_lib.c:
|
|
1307
|
+
* ECMA half-toward-+Infinity with the exact-fraction comparison — C
|
|
1308
|
+
* round() is half-away-from-zero and floor(x+0.5) drifts at the
|
|
1309
|
+
* epsilon boundary). Borrow nothing; never throw. */
|
|
1310
|
+
| "math.abs" | "math.round"
|
|
1311
|
+
/** The static global parsers/tests (scr_string.c). num.parseInt is
|
|
1312
|
+
* ECMA-262 19.2.5 exactly — JS whitespace, sign, ToInt32 radix (the
|
|
1313
|
+
* frontend completes an omitted radix to 0 = the spec's "undefined":
|
|
1314
|
+
* base 10 with the 0x hex escape), longest digit prefix, and the exact
|
|
1315
|
+
* mathematical value correctly rounded (u64 fast path, bignum beyond —
|
|
1316
|
+
* overflow is ±Infinity). num.isNaN is the NaN self-test on an
|
|
1317
|
+
* already-number argument (tsc pins the argument to number, so no
|
|
1318
|
+
* ToNumber coercion exists to model). Borrow; never throw. */
|
|
1319
|
+
| "num.parseInt" | "num.isNaN"
|
|
1320
|
+
/** ES parseFloat (scr_string.c): the longest StrDecimalLiteral prefix
|
|
1321
|
+
* of the trimmed input (no hex, "Infinity" exact-case), NaN when none —
|
|
1322
|
+
* ECMA-262 19.2.4 over a string argument (non-string arguments keep the
|
|
1323
|
+
* fence: Node would ToNumber-coerce). Borrows; never throws. */
|
|
1324
|
+
| "num.parseFloat" | "num.fromString"
|
|
1325
|
+
/** The static URI component codecs (scr_string.c), ECMA-262 Encode/
|
|
1326
|
+
* Decode with the component sets over the runtime's UTF-8 strings.
|
|
1327
|
+
* str.encodeUriComponent percent-encodes every byte outside the
|
|
1328
|
+
* unreserved component set (ALPHA/DIGIT/- _ . ! ~ * ' ( )) as uppercase
|
|
1329
|
+
* %XX — the spec's per-code-point UTF-8 encoding IS a byte scan here —
|
|
1330
|
+
* and never throws (the spec's URIError case is an unpaired surrogate,
|
|
1331
|
+
* which cannot exist in well-formed UTF-8). str.decodeUriComponent
|
|
1332
|
+
* decodes %XX escapes bytewise (raw non-escape bytes copy through) and
|
|
1333
|
+
* requires the escaped bytes to form strictly valid UTF-8 (overlong
|
|
1334
|
+
* forms, surrogate code points, and >U+10FFFF refused, per UTF8-decode
|
|
1335
|
+
* without replacement); bad hex or an invalid sequence THROWS the
|
|
1336
|
+
* spec's URIError ("URI malformed"), catchable. Borrow; results +1. */
|
|
1337
|
+
| "str.encodeUriComponent" | "str.decodeUriComponent"
|
|
1338
|
+
/** RegExp.escape (ES2025): per-code-point EncodeForRegExpEscape —
|
|
1339
|
+
* leading ASCII alphanumeric hex-escapes, syntax characters and '/'
|
|
1340
|
+
* take a backslash, other punctuators/whitespace/line terminators
|
|
1341
|
+
* hex-escape, the rest passes through. Total; borrows; result +1. */
|
|
1342
|
+
| "regexp.escape"
|
|
1343
|
+
/** encodeURI: the same Encode() keeping the reserved set and '#'
|
|
1344
|
+
* unescaped — total like the component encoder. Borrow; result +1. */
|
|
1345
|
+
| "str.encodeUri"
|
|
1346
|
+
/** The WHATWG base64 globals (scr_string.c), Node-global since v16.
|
|
1347
|
+
* Arguments are borrowed DOM values — WebIDL ToString runs in the
|
|
1348
|
+
* runtime over the DOM kind (String(null) is "null": the html spec's
|
|
1349
|
+
* coercion, which Node's atob(null) exercises). str.atob decodes
|
|
1350
|
+
* forgiving-base64 (ASCII whitespace stripped, %4==0 strips up to two
|
|
1351
|
+
* '=', %4==1 refuses, leftover bits discarded) into the latin1 code
|
|
1352
|
+
* points as a string; a malformed input THROWS the catchable
|
|
1353
|
+
* DOMException InvalidCharacterError ("The string to be decoded is not
|
|
1354
|
+
* correctly encoded."). str.btoa encodes the string's code points as
|
|
1355
|
+
* base64; any code point over U+00FF THROWS InvalidCharacterError
|
|
1356
|
+
* ("Invalid character"). str.b64Missing is the zero-argument call of
|
|
1357
|
+
* either: always throws Node's TypeError [ERR_MISSING_ARGS] "The
|
|
1358
|
+
* \"input\" argument must be specified". Results +1. */
|
|
1359
|
+
| "str.atob" | "str.btoa" | "str.b64Missing"
|
|
1360
|
+
/** The fraction-digits-free Number.prototype formatters (scr_lib.c),
|
|
1361
|
+
* JS-exact: num.toExponential is toExponential() with the spec's
|
|
1362
|
+
* "as many digits as necessary" — the shortest correctly-rounded
|
|
1363
|
+
* mantissa, d[.ddd]e±X with no exponent zero-padding ("7e+0"); NaN and
|
|
1364
|
+
* ±Infinity answer their texts. num.toFixed0 is toFixed() at 0 digits —
|
|
1365
|
+
* the spec's closest-integer pick with ties toward +∞ on the magnitude
|
|
1366
|
+
* ("-2.5" → "-3"), |x| ≥ 1e21 falling back to ToString, and the "-0"
|
|
1367
|
+
* result for negative fractions rounding to zero. The explicit-digits
|
|
1368
|
+
* forms keep their island lowering. Results +1; never throw. */
|
|
1369
|
+
| "num.toExponential" | "num.toFixed0"
|
|
1370
|
+
/** `delete process.env[NAME]` — unsetenv(3): the mutation is visible to
|
|
1371
|
+
* every later read (process.envGet asks getenv fresh) and inherited by
|
|
1372
|
+
* spawned children, exactly Node. Statement position only (JS's boolean
|
|
1373
|
+
* result is constant true there). Borrows the name; never throws. */
|
|
1374
|
+
| "process.envUnset"
|
|
1375
|
+
/** node:url + the URL class (scr_url.c). url.new parses one absolute
|
|
1376
|
+
* URL string into an immutable URL value (+1) — invalid input THROWS a
|
|
1377
|
+
* catchable TypeError ("Invalid URL"), like Node's constructor. The
|
|
1378
|
+
* getters (borrowed receiver, +1 string) never throw; url.href doubles
|
|
1379
|
+
* as toString(). fileURLToPath has one libFn per receiver form (URL
|
|
1380
|
+
* value / string) — both THROW Node's TypeErrors on non-file schemes,
|
|
1381
|
+
* encoded slashes, and non-empty hosts. url.pathToFileURL resolves the
|
|
1382
|
+
* path (getcwd) and never throws. */
|
|
1383
|
+
| "url.new" | "url.protocol" | "url.host" | "url.hostname" | "url.pathname" | "url.href" | "url.fileURLToPathUrl" | "url.fileURLToPathStr" | "url.pathToFileURL"
|
|
1384
|
+
/** pathToFileURL under a win32 TARGET: the same scr_url_from_path call
|
|
1385
|
+
* (the runtime selects the win32 arm by _WIN32), but a distinct IR name
|
|
1386
|
+
* because that arm THROWS for malformed UNC inputs — may-throw seeds on
|
|
1387
|
+
* it while posix pathToFileURL emission stays byte-identical. */
|
|
1388
|
+
| "url.pathToFileURLWin32"
|
|
1389
|
+
/** URLSearchParams (scr_url.c — always linked with the url unit).
|
|
1390
|
+
* Construction: sp.new (empty), sp.parse (one borrowed init string —
|
|
1391
|
+
* a single leading '?' strips, Node's constructor), sp.copy (snapshot
|
|
1392
|
+
* of another list), sp.fromPairs (a string[][] value — THROWS Node's
|
|
1393
|
+
* ERR_INVALID_TUPLE TypeError on a non-[name, value] row; the one
|
|
1394
|
+
* throwing entry in the family), sp.with (the record-literal init
|
|
1395
|
+
* desugar: append one pair, answer the same list +1 — chains fold
|
|
1396
|
+
* `new URLSearchParams({...})` into nested calls). url.searchParams
|
|
1397
|
+
* answers the URL's LIVE cached view (+1, one identity per URL);
|
|
1398
|
+
* url.search is the WHATWG search getter ("" for no/empty query).
|
|
1399
|
+
* Methods mirror the WHATWG surface: sp.get answers +1-or-NULL (the
|
|
1400
|
+
* sym.desc union pattern, null arm), sp.getAll a fresh string[];
|
|
1401
|
+
* sp.append/sp.set/sp.delete/sp.deleteValue/sp.sort mutate and
|
|
1402
|
+
* re-serialize a live view's URL query; sp.has/sp.hasValue answer
|
|
1403
|
+
* bools; sp.size/sp.toString are pure reads. sp.keyAt/sp.valAt are
|
|
1404
|
+
* the for-of/forEach desugar's index reads (live — the loop re-reads
|
|
1405
|
+
* sp.size each pass). */
|
|
1406
|
+
| "sp.new" | "sp.parse" | "sp.copy" | "sp.fromPairs" | "sp.with" | "url.searchParams" | "url.search" | "sp.get" | "sp.getAll" | "sp.append" | "sp.set" | "sp.delete" | "sp.deleteValue" | "sp.has" | "sp.hasValue" | "sp.sort" | "sp.size" | "sp.toString" | "sp.keyAt" | "sp.valAt"
|
|
1407
|
+
/** ES Symbol values (scr_symbol.c — link-gated by moduleUsesSymbol).
|
|
1408
|
+
* sym.new: `Symbol(desc)` — a fresh runtime-unique identity (+1) whose
|
|
1409
|
+
* one arg is the description string (borrowed); sym.newAnon is the
|
|
1410
|
+
* description-less `Symbol()` form. sym.for: the Symbol.for global
|
|
1411
|
+
* registry — one interned symbol per key (borrowed), +1 on every call.
|
|
1412
|
+
* sym.toString: "Symbol(desc)" (+1 string; "Symbol()" when absent).
|
|
1413
|
+
* sym.desc / sym.keyFor answer the interned `string | undefined` union
|
|
1414
|
+
* (the runtime returns +1-or-NULL; the backend builds the union arms —
|
|
1415
|
+
* the child.stdout pattern). None of these throw. */
|
|
1416
|
+
| "sym.new" | "sym.newAnon" | "sym.for" | "sym.keyFor" | "sym.desc" | "sym.toString"
|
|
1417
|
+
/** fs.statSync → a Stats value (may throw, like the other sync fs
|
|
1418
|
+
* calls); the stats.* getters are pure reads on it. */
|
|
1419
|
+
| "fs.statSync" | "stats.isFile" | "stats.isDirectory" | "stats.size"
|
|
1420
|
+
/** child_process.spawnSync (scr_child.c): posix_spawn + waitpid + piped
|
|
1421
|
+
* utf8 capture — cmd borrowed, args one borrowed string[] (the frontend
|
|
1422
|
+
* completes an omitted list to an empty literal), result an owned (+1)
|
|
1423
|
+
* spawnRes. NEVER throws: spawn failure (nonexistent binary, EACCES) is
|
|
1424
|
+
* data, like Node's error property — status null and empty outputs
|
|
1425
|
+
* (SEMANTICS.md documents the divergence from Node's null stdout).
|
|
1426
|
+
* The getters are pure reads: status is the interned `number | null`
|
|
1427
|
+
* union (null = spawn failure or signal death, type-directed
|
|
1428
|
+
* construction in the backend like process.envGet); stdout/stderr are
|
|
1429
|
+
* +1 strings. */
|
|
1430
|
+
| "cp.spawnSync" | "spawnRes.status" | "spawnRes.stdout" | "spawnRes.stderr"
|
|
1431
|
+
/** Node's spawn-failure carrier `error?: Error`: a fresh +1 %Error
|
|
1432
|
+
* ("spawnSync <file> ENOENT", `code` stamped) when the spawn itself
|
|
1433
|
+
* failed, the interned undefined arm otherwise — the result type is the
|
|
1434
|
+
* call site's `Error | undefined` union, constructed type-directedly in
|
|
1435
|
+
* the backend (the envGet convention). Never throws. */
|
|
1436
|
+
| "spawnRes.error"
|
|
1437
|
+
/** child_process.spawn (scr_child.c + the scr_async.c loop): posix_spawnp
|
|
1438
|
+
* with stdio "ignore" (all three fds on /dev/null — the only supported
|
|
1439
|
+
* stdio; "pipe"/"inherit" are frontend-fenced), the child registered
|
|
1440
|
+
* with the event loop, which polls waitpid(WNOHANG) at quiescence like
|
|
1441
|
+
* timers (kqueue is the follow-up; SEMANTICS.md documents the polling).
|
|
1442
|
+
* NEVER throws: spawn failure defers to the "error" event, Node-exact
|
|
1443
|
+
* (the error message is Node's "spawn <cmd> <ERRNO-NAME>"; an "error"
|
|
1444
|
+
* event with no listener prints it and exits 1 like an EventEmitter).
|
|
1445
|
+
* cmd/args borrowed; result an owned (+1) child handle. The loop will
|
|
1446
|
+
* not exhaust while any spawned child is unreaped — Node's keep-alive.
|
|
1447
|
+
*
|
|
1448
|
+
* child.onExit / child.onError — `child.on("exit"|"error", cb)`: the
|
|
1449
|
+
* receiver is borrowed, the CALLBACK MOVES into the child's listener
|
|
1450
|
+
* registry (released after the terminal event fires, or at reap for
|
|
1451
|
+
* the event that never fires). Both are void (chaining is fenced).
|
|
1452
|
+
* onExit's third emitted ingredient is an ADAPTER the backend interns
|
|
1453
|
+
* per callback shape: the runtime invokes adapter(cb, has_code, code)
|
|
1454
|
+
* and the adapter builds the `number | null` union (tags are program-
|
|
1455
|
+
* dependent) or ignores the code for a zero-param callback. onError's
|
|
1456
|
+
* adapters are runtime-provided (zero-param, or the %Error one-param
|
|
1457
|
+
* shape — scr_error_new needs no program types). "exit" fires once
|
|
1458
|
+
* with the code (f64 arm) or null (signal death); "error" fires only
|
|
1459
|
+
* for spawn failure, exactly Node's split. */
|
|
1460
|
+
| "cp.spawn" | "child.onExit" | "child.onError"
|
|
1461
|
+
/** The ChildProcess lifecycle members (scr_child.c), Node's shapes
|
|
1462
|
+
* exactly (SEMANTICS.md has the pinned matrix). child.pid is the
|
|
1463
|
+
* checker's `number | undefined` (undefined = spawn failure) and
|
|
1464
|
+
* child.exitCode its `number | null` (null while running and after a
|
|
1465
|
+
* signal death; -errno once a spawn failure settled) — both unions are
|
|
1466
|
+
* type-directed constructions in the backend over a has/get runtime
|
|
1467
|
+
* pair, the spawnRes.status pattern. child.killed is Node's
|
|
1468
|
+
* sent-a-signal flag. child.kill sends while the child is un-reaped
|
|
1469
|
+
* (false after — Node's null-handle answer) and THROWS the
|
|
1470
|
+
* Unknown-signal TypeError on bad names (may-throw); killNum passes
|
|
1471
|
+
* numbers through (0 probes; never throws). child.unref drops the
|
|
1472
|
+
* child from the loop's keep-alive set — it is still reaped while the
|
|
1473
|
+
* loop runs for other reasons, and one the loop never reaps is left to
|
|
1474
|
+
* the OS at exit. All receivers borrowed. */
|
|
1475
|
+
| "child.pid" | "child.exitCode" | "child.killed" | "child.kill" | "child.killNum" | "child.unref"
|
|
1476
|
+
/** The piped-output streams (stdio mode 3 — scr_child.c's stream
|
|
1477
|
+
* slice). child.stdout/child.stderr answer the checker's
|
|
1478
|
+
* `Readable | null` union (type-directed construction in the backend
|
|
1479
|
+
* over the +1-or-NULL runtime pair — the child.pid pattern with a ref
|
|
1480
|
+
* arm). stream.onData/onEnd register 'data'/'end' listeners (receiver
|
|
1481
|
+
* borrowed, CALLBACK MOVES, trailing once-flag, void — chaining
|
|
1482
|
+
* fenced): 'data' fires one Buffer chunk per read (zero-param and
|
|
1483
|
+
* Buffer-param adapters are runtime-provided; a union-param listener —
|
|
1484
|
+
* ngrok's `Buffer | string` — gets a compiler-emitted adapter wrapping
|
|
1485
|
+
* the chunk at its Buffer arm), 'end' fires once at EOF, always BEFORE
|
|
1486
|
+
* the child's 'exit' (the pinned ordering). A flowing stream keeps the
|
|
1487
|
+
* loop alive: usesTimers. */
|
|
1488
|
+
| "child.stdout" | "child.stderr" | "stream.onData" | "stream.onEnd"
|
|
1489
|
+
/** The first-class WritableStream write (`output.write(line)` — the
|
|
1490
|
+
* prefixStream idiom): the receiver IS the fd scalar (process.stdout/
|
|
1491
|
+
* stderr reads mint 1/2), dispatched onto the exact stdoutWrite/
|
|
1492
|
+
* stderrWrite paths so buffering and ordering stay identical. Data
|
|
1493
|
+
* borrowed; the bool is Node's always-true backpressure signal. */
|
|
1494
|
+
| "procStream.write"
|
|
1495
|
+
/** node:net (scr_net.c — linked, and scr_net_install() emitted, only
|
|
1496
|
+
* when one of these appears on the IR; moduleUsesNet is the switch).
|
|
1497
|
+
* Receivers are borrowed; CALLBACKS MOVE into the handle's listener
|
|
1498
|
+
* registry and are released at settlement (the child.onExit story).
|
|
1499
|
+
* All listener registrations carry a trailing BOOL once-flag (`on` vs
|
|
1500
|
+
* `once`) and are void — chaining is fenced. None of these throw:
|
|
1501
|
+
* listen/connect failures are the async 'error' event, like Node.
|
|
1502
|
+
*
|
|
1503
|
+
* net.createServer's optional connection handler and the
|
|
1504
|
+
* serverOnConnection listeners take the runtime-provided adapters
|
|
1505
|
+
* (zero-param, or the one-param socket shape); sockOnData's adapters
|
|
1506
|
+
* are the stdin pair's shapes (zero-param / bytes chunk); the error
|
|
1507
|
+
* events reuse the child %Error adapters. net.listen/net.listenCb bind
|
|
1508
|
+
* NOW and defer 'listening' to the next loop turn (Node's next-tick
|
|
1509
|
+
* emit); net.serverPort is the composed `server.address().port` read.
|
|
1510
|
+
* net.connect's host argument is a string ("localhost" pins to
|
|
1511
|
+
* 127.0.0.1 — SEMANTICS.md); the connect callback is once('connect'). */
|
|
1512
|
+
| "net.createServer" | "net.createServerCb" | "net.listen" | "net.listenCb"
|
|
1513
|
+
/** listen({ port, host, ipv6Only }[, cb]) — the explicit-interface bind
|
|
1514
|
+
* (portless's listenOnProxyInterface): args [server, port, host,
|
|
1515
|
+
* ipv6Only]. host is an IP literal string ("" = the host-less
|
|
1516
|
+
* dual-stack any default); ipv6Only sets IPV6_V6ONLY before the bind.
|
|
1517
|
+
* Failures are the async 'error', message in Node's listen shape with
|
|
1518
|
+
* the requested host. Never throws. */
|
|
1519
|
+
| "net.listenOpts" | "net.listenOptsCb" | "net.serverPort"
|
|
1520
|
+
/** server.address() as the full AddressInfo record (the dgram.address
|
|
1521
|
+
* materialization pattern: the emitter builds the record from the three
|
|
1522
|
+
* runtime reads; the frontend pinned the shape). Never throws — before
|
|
1523
|
+
* listen it answers the any-form defaults with port 0 where Node
|
|
1524
|
+
* answers null (the serverPort stance). */
|
|
1525
|
+
| "net.serverAddress" | "net.serverClose" | "net.serverCloseCb"
|
|
1526
|
+
/** The close-override pair (the portless close-proxy idiom).
|
|
1527
|
+
* serverCloseBind is `wrapper.close.bind(wrapper)` as a VALUE: a
|
|
1528
|
+
* compiler-emitted closure over the server whose invocation runs the
|
|
1529
|
+
* REAL close (scr_net_server_close_direct — never the override), so
|
|
1530
|
+
* the override body's `origClose(cb)` cannot recurse; its callback
|
|
1531
|
+
* argument (the `((err?: Error) => void) | undefined` union) registers
|
|
1532
|
+
* as a once-'close' listener, a one-param callback wrapped by an
|
|
1533
|
+
* emitted zero-arg trampoline firing the undefined arm (a clean close
|
|
1534
|
+
* carries no error). serverSetCloseOverride is `wrapper.close = fn`:
|
|
1535
|
+
* the override MOVES in behind an emitted zero-arg wrapper (it invokes
|
|
1536
|
+
* the user function with the undefined-arm callback — tags are program
|
|
1537
|
+
* data), and server.close() consults it before closing. */
|
|
1538
|
+
| "net.serverCloseBind" | "net.serverSetCloseOverride" | "net.serverOnError" | "net.serverOnClose" | "net.serverOnConnection"
|
|
1539
|
+
/** 'secureConnection' — the TLS server's deferred 'connection' list
|
|
1540
|
+
* (handshake-completion timing); on a server without deferred
|
|
1541
|
+
* connections (a plain net server) the registration never fires,
|
|
1542
|
+
* exactly Node's split. */
|
|
1543
|
+
| "net.serverOnSecureConnection" | "net.connect" | "net.connectCb"
|
|
1544
|
+
/** connect({ port, host, autoSelectFamily: true, lookup }) — the
|
|
1545
|
+
* caller-resolver dial (portless's createLoopbackConnection): args
|
|
1546
|
+
* [port, host, lookup]. The runtime creates the (connecting) socket
|
|
1547
|
+
* handle, invokes the lookup as Node does — lookup(hostname, options,
|
|
1548
|
+
* callback), options crossing as the dyn undefined — and the answer
|
|
1549
|
+
* closure (an emitter-synthesized per-shape thunk over a boxed socket,
|
|
1550
|
+
* the SNI-answer pattern) dials the answered addresses IN ORDER: each
|
|
1551
|
+
* connect failure tries the next, the LAST failure's message is the
|
|
1552
|
+
* socket's 'error' (Node's autoSelectFamily aggregate is a documented
|
|
1553
|
+
* divergence), and a lookup error surfaces as the deferred socket
|
|
1554
|
+
* 'error'. A synchronous throw INSIDE the lookup propagates out of the
|
|
1555
|
+
* connect call (may-throw seed). */
|
|
1556
|
+
| "net.connectLookup" | "net.sockWrite" | "net.sockWriteBytes" | "net.sockEnd" | "net.sockEndStr" | "net.sockEndBytes"
|
|
1557
|
+
/** write/end with a CHECKED-DYNAMIC chunk (an untyped JS payload into a
|
|
1558
|
+
* typed socket): the runtime dispatches STR/BYTES and throws Node's
|
|
1559
|
+
* ERR_INVALID_ARG_TYPE chunk TypeError on any other kind. */
|
|
1560
|
+
| "net.sockWriteDyn" | "net.sockEndDyn" | "net.sockDestroy" | "net.sockPipe"
|
|
1561
|
+
/** socket.pipe(res) — raw socket chunks into a ServerResponse body
|
|
1562
|
+
* (the extended-CONNECT bridge leg): each chunk is a body write (the
|
|
1563
|
+
* response's own framing applies); source EOF end()s the response,
|
|
1564
|
+
* pipe's default. Borrows both. Never throws. */
|
|
1565
|
+
| "net.sockPipeRes" | "net.sockOnData" | "net.sockOnEnd" | "net.sockOnClose" | "net.sockOnError" | "net.sockOnConnect"
|
|
1566
|
+
/** node:dgram + node:dns (scr_dgram.c — linked, and
|
|
1567
|
+
* scr_dgram_install() emitted, only when one of these appears on the
|
|
1568
|
+
* IR; moduleUsesDgram is the switch — dns.lookup rides the same unit).
|
|
1569
|
+
* The net listener discipline verbatim: receivers borrowed, CALLBACKS
|
|
1570
|
+
* MOVE into the handle's registry and release at settlement, `on` vs
|
|
1571
|
+
* `once` is the trailing bool, registrations are void. bind/connect
|
|
1572
|
+
* bind NOW and defer 'listening'/'connect' to the next loop turn (the
|
|
1573
|
+
* net.listen story); their optional-host completions are ""
|
|
1574
|
+
* (bind → 0.0.0.0) and "127.0.0.1" (connect — udp4's Node default).
|
|
1575
|
+
* bind/connect/send/close/address THROW Node's state errors ("Socket
|
|
1576
|
+
* is already bound", "Already connected", "Not running") — may-throw
|
|
1577
|
+
* seeded. dgram.address returns the AddressInfo RECORD (the frontend
|
|
1578
|
+
* pins the {address, family, port} shape; the emitter builds it from
|
|
1579
|
+
* runtime parts). onMessage adapters are emitted per rinfo record
|
|
1580
|
+
* shape (the child.onExit precedent); onError reuses the child %Error
|
|
1581
|
+
* adapters. dns.lookup resolves via getaddrinfo AT CALL TIME and
|
|
1582
|
+
* defers the callback to the next turn (SEMANTICS.md documents the
|
|
1583
|
+
* blocking divergence); its per-union adapter builds the
|
|
1584
|
+
* `Error | null` first argument. */
|
|
1585
|
+
| "dgram.createSocket" | "dgram.bind" | "dgram.bindCb" | "dgram.connect" | "dgram.connectCb" | "dgram.sendStr" | "dgram.sendBytes" | "dgram.address" | "dgram.close" | "dgram.closeCb" | "dgram.unref" | "dgram.ref" | "dgram.onMessage" | "dgram.onError" | "dgram.onListening" | "dgram.onClose" | "dgram.onConnect" | "dns.lookup"
|
|
1586
|
+
/** node:test (scr_test.c — linked only when one of these appears on
|
|
1587
|
+
* the IR; moduleUsesNodeTest is the switch, and the main epilogue asks
|
|
1588
|
+
* scr_test_exit_code() for the process's exit status). Strings are
|
|
1589
|
+
* BORROWED, callbacks MOVE. register/suite/hook attach to the runner
|
|
1590
|
+
* tree (register: name, mode 0|1|2 run/skip/todo, directive message ""
|
|
1591
|
+
* = none, cb or absent via registerEmpty, flags 1 async | 2 takes-ctx
|
|
1592
|
+
* | 4 only, "file:line:col"); suite runs its body AT registration
|
|
1593
|
+
* (Node's collection phase). sub is t.test — runs the subtest INLINE
|
|
1594
|
+
* on the runner fiber and returns the settled promise the await
|
|
1595
|
+
* consumes. ctxSkip/ctxTodo mark the running test; ctxDiagnostic
|
|
1596
|
+
* queues an ℹ line; ctxName reads t.name. Every registration keeps
|
|
1597
|
+
* the loop-run emitted (usesTimers) so the runner fiber drains. */
|
|
1598
|
+
| "test.register" | "test.registerEmpty" | "test.suite" | "test.hook" | "test.sub" | "test.subEmpty" | "test.ctxSkip" | "test.ctxTodo" | "test.ctxDiagnostic" | "test.ctxName"
|
|
1599
|
+
/** node:http, the server slice (scr_http.c over scr_net.c — linked
|
|
1600
|
+
* only when these appear on the IR; moduleUsesHttpServer is the
|
|
1601
|
+
* switch, and any http.* libCall also counts as net use so scr_net.c
|
|
1602
|
+
* links and installs). http.createServer's handler MOVES in and takes
|
|
1603
|
+
* the runtime adapters for its (req, res) / (req) / () shapes; req
|
|
1604
|
+
* body listeners follow the net.sockOnData story (bytes chunks, once
|
|
1605
|
+
* flags); reqHeader answers the interned `string | undefined` union
|
|
1606
|
+
* exactly like process.envGet; the res writers are borrowed-argument
|
|
1607
|
+
* voids with Node's framing decided in the runtime (Content-Length
|
|
1608
|
+
* for end-before-head, chunked after an explicit writeHead/write). */
|
|
1609
|
+
| "http.createServer"
|
|
1610
|
+
/** http.createServer() / http.Server() with no handler — the
|
|
1611
|
+
* on("request") route; createServerOpts is the (options[, listener])
|
|
1612
|
+
* overload's twin carrying the two lowered parser flags
|
|
1613
|
+
* (requireHostHeader: false is already this parser's behavior;
|
|
1614
|
+
* joinDuplicateHeaders joins repeated request-header reads ", "). */
|
|
1615
|
+
| "http.createServerEmpty" | "http.serverJoinDupHeaders"
|
|
1616
|
+
/** server.on("listening", cb) — the deferred listen-callback list. */
|
|
1617
|
+
| "net.serverOnListening"
|
|
1618
|
+
/** The ServerResponse member surface: statusCode/statusMessage reads
|
|
1619
|
+
* and assignments (Node's writable properties), the header CRUD trio
|
|
1620
|
+
* (getHeader answers `string | undefined` like reqHeader), and
|
|
1621
|
+
* end(cb)'s finish slot (resOnFinish registers, the end call follows —
|
|
1622
|
+
* the callback fires deferred, Node's 'finish' emit). writeHead's
|
|
1623
|
+
* statusMessage forms compose in interned helpers: resStatusMsgSet
|
|
1624
|
+
* then the ordinary writeHead entry. */
|
|
1625
|
+
| "http.resStatusGet" | "http.resStatusSet" | "http.resStatusMsgGet" | "http.resStatusMsgSet" | "http.resGetHeader" | "http.resHasHeader" | "http.resRemoveHeader" | "http.resOnFinish" | "http.reqUrl" | "http.reqMethod" | "http.reqHeader" | "http.reqOnData" | "http.reqOnEnd" | "http.resSetHeader" | "http.resWriteHead" | "http.resWriteHeadN" | "http.resWrite" | "http.resWriteBytes" | "http.resEnd" | "http.resEndStr" | "http.resEndBytes"
|
|
1626
|
+
/** The checked-dynamic chunk twins (the net.sockWriteDyn story). */
|
|
1627
|
+
| "http.resWriteDyn" | "http.resEndDyn" | "http.resHeadersSent"
|
|
1628
|
+
/** The server-surface member follow-ups: reqStatusCode answers the
|
|
1629
|
+
* interned `number | undefined` union (negative = the undefined arm —
|
|
1630
|
+
* a SERVER request, where Node's statusCode is undefined; every client
|
|
1631
|
+
* response carries a real status); reqSocket is the underlying
|
|
1632
|
+
* connection (+1, the same handle net.connect would give);
|
|
1633
|
+
* sockRemoteAddress answers `string | undefined` (NULL after the fd
|
|
1634
|
+
* closed, Node's destroyed-socket undefined; a dual-stack accept of an
|
|
1635
|
+
* IPv4 peer reads "::ffff:a.b.c.d" like Node). reqResume/reqDestroy and
|
|
1636
|
+
* the req error/close listener slots complete the IncomingMessage
|
|
1637
|
+
* surface portless's client responses use; resDestroy/resOnClose and
|
|
1638
|
+
* resWriteHeadPairs ([k0,v0,k1,v1,...] — the env.pairs helper's flat
|
|
1639
|
+
* shape) complete ServerResponse. sockSetTimeout arms the idle
|
|
1640
|
+
* EVFILT_TIMER ('timeout' fires after ms of inactivity, once per idle
|
|
1641
|
+
* period, never destroying the socket — Node's semantics). */
|
|
1642
|
+
| "http.reqStatusCode" | "http.reqSocket" | "http.reqResume"
|
|
1643
|
+
/** req.rawHeaders — [name, value, name, value, ...] in arrival order,
|
|
1644
|
+
* names in their ORIGINAL case (Node's shape); a fresh string[] per
|
|
1645
|
+
* read. reqStatusMessage answers the interned `string | undefined`
|
|
1646
|
+
* union — the reason phrase on client responses ("" when the status
|
|
1647
|
+
* line carried none), the undefined arm on server requests (the
|
|
1648
|
+
* statusCode split). sockDestroyed is socket.destroyed — true once the
|
|
1649
|
+
* fd is gone (destroy() or full close). */
|
|
1650
|
+
| "http.reqRawHeaders" | "http.reqStatusMessage"
|
|
1651
|
+
/** The `{ ...req.headers }` snapshot feed: [lowercased name, value,
|
|
1652
|
+
* ...] pairs in arrival order — the interned %headers.snapshot helper
|
|
1653
|
+
* builds the record over it, exactly the process.envPairs pattern. */
|
|
1654
|
+
| "http.reqHeaderPairs" | "net.sockDestroyed"
|
|
1655
|
+
/** socket.writable — the write half is open: no end() yet, no FIN sent,
|
|
1656
|
+
* fd alive (connecting sockets answer true; writes queue). Node's
|
|
1657
|
+
* stream flag. Borrows; never throws. */
|
|
1658
|
+
| "net.sockWritable"
|
|
1659
|
+
/** The 'upgrade' events, both sides (SEMANTICS.md — the WebSocket
|
|
1660
|
+
* proxying surface): serverOnUpgrade registers (req, socket, head)
|
|
1661
|
+
* listeners fired INSTEAD of 'request' for Connection: upgrade
|
|
1662
|
+
* requests (the parser steps aside; the socket is raw; `head` carries
|
|
1663
|
+
* bytes past the request head; no listener = the socket destroys,
|
|
1664
|
+
* Node's default). clientOnUpgrade is the client twin: a 101 response
|
|
1665
|
+
* fires (res, socket, head) INSTEAD of 'response'. */
|
|
1666
|
+
| "http.serverOnUpgrade" | "http.clientOnUpgrade"
|
|
1667
|
+
/** server.on("connect", ...) — HTTP CONNECT tunneling, the 'upgrade'
|
|
1668
|
+
* machinery's twin: (req, socket, head) fired INSTEAD of 'request' for
|
|
1669
|
+
* CONNECT-method requests (no listener = the socket destroys, Node's
|
|
1670
|
+
* default). The h2 compat server's 'connect' (portless's RFC 8441
|
|
1671
|
+
* handler) only ever sees the HTTP/1.1 arm under the allowHTTP1
|
|
1672
|
+
* lowering, so a listener whose second parameter is a UNION with a
|
|
1673
|
+
* netSocket arm takes the socket wrapped at that arm (an emitted
|
|
1674
|
+
* per-shape adapter — the tags are program data). */
|
|
1675
|
+
| "http.serverOnConnect"
|
|
1676
|
+
/** req.pipe(dest) — the IncomingMessage body streaming into a
|
|
1677
|
+
* ServerResponse (the proxy's response leg), a ClientRequest (the
|
|
1678
|
+
* request-body forward), or a raw socket (the upgrade-rejection leg);
|
|
1679
|
+
* chunk-for-chunk, natural end ends the destination (Node's pipe
|
|
1680
|
+
* default; no backpressure — divergence 54's stream model). */
|
|
1681
|
+
| "http.reqPipeRes" | "http.reqPipeClient" | "http.reqPipeSock" | "http.reqDestroy" | "http.reqOnError" | "http.reqOnClose" | "http.reqOnAborted" | "http.reqHttpVersion" | "http.reqHttpVersionMajor" | "http.reqHttpVersionMinor" | "http.reqAborted" | "http.reqComplete" | "http.resDestroy" | "http.resOnClose" | "http.resWriteHeadPairs"
|
|
1682
|
+
/** writeHead(status, headers) with a checked-dynamic headers value —
|
|
1683
|
+
* the runtime OBJ walk (string/number values; loud fences otherwise;
|
|
1684
|
+
* may throw). */
|
|
1685
|
+
| "http.resWriteHeadDyn" | "net.sockSetTimeout"
|
|
1686
|
+
/** setEncoding('utf8') — 'data' delivers strings inside the chunk-encoding window; other real encodings fence loudly, unknown names throw ERR_UNKNOWN_ENCODING (may throw). */
|
|
1687
|
+
| "net.sockSetEncoding" | "http.reqSetEncoding" | "net.sockOnTimeout" | "net.sockRemoteAddress"
|
|
1688
|
+
/** The paused-mode demux surface (portless's first-byte TLS peek:
|
|
1689
|
+
* once('readable') + read(1) + unshift + emit('connection')).
|
|
1690
|
+
* sockOnReadable registers a zero-param listener (a consumer: arrived
|
|
1691
|
+
* bytes buffer instead of flowing, and EOF announces too); sockRead
|
|
1692
|
+
* answers `Buffer | null` (exactly n buffered bytes, or null — Node's
|
|
1693
|
+
* less-than-n answer; n <= 0 drains everything); sockUnshift returns
|
|
1694
|
+
* bytes to the front of the stream; serverEmitConnection routes a
|
|
1695
|
+
* socket into another server's protocol layer (a TLS target's
|
|
1696
|
+
* 'connection' waits for its handshake). */
|
|
1697
|
+
| "net.sockOnReadable" | "net.sockRead" | "net.sockUnshift" | "net.serverEmitConnection"
|
|
1698
|
+
/** node:http, the CLIENT slice (http.request/http.get over the net
|
|
1699
|
+
* client machinery): request/requestCb take (host, port, path, method,
|
|
1700
|
+
* timeoutMs, headerPairs, autoEnd[, responseCb]) — headerPairs is the
|
|
1701
|
+
* flat [k0,v0,...] array (empty for none), autoEnd true is http.get's
|
|
1702
|
+
* eager end(). The handle owns one dialed connection (NO pooling — the
|
|
1703
|
+
* wire still carries Node's exact head: user headers, then Host,
|
|
1704
|
+
* Connection: keep-alive, and the framing header; the socket closes
|
|
1705
|
+
* when the response completes). The response delivered to responseCb /
|
|
1706
|
+
* 'response' listeners IS an httpReq (IncomingMessage), status and
|
|
1707
|
+
* headers parsed from the wire, body via reqOnData/reqOnEnd. Errors are
|
|
1708
|
+
* Node-shaped ('connect ECONNREFUSED ip:port', 'socket hang up') and
|
|
1709
|
+
* fire 'error' then 'close'; an unhandled 'error' exits 1 like every
|
|
1710
|
+
* net handle. clientWrite before end commits to chunked framing unless
|
|
1711
|
+
* the caller set content-length; clientEnd(data) before any write sends
|
|
1712
|
+
* Content-Length exactly like Node. */
|
|
1713
|
+
| "http.request" | "http.requestCb"
|
|
1714
|
+
/** The createConnection form (the proxy's own dialer): args are
|
|
1715
|
+
* (connCb, path, method, timeout, headers, autoEnd[, cb]) — connCb is
|
|
1716
|
+
* a `() => net.Socket` closure the runtime invokes ONCE, synchronously
|
|
1717
|
+
* (Node's onSocket timing); everything else matches http.request. The
|
|
1718
|
+
* Host header defaults to "localhost" — a headers.host entry wins
|
|
1719
|
+
* verbatim, the proxy shape. */
|
|
1720
|
+
| "http.requestConn" | "http.requestConnCb"
|
|
1721
|
+
/** node:tls + node:https (scr_tls.c over scr_net.c/scr_http.c, with
|
|
1722
|
+
* the vendored mbedTLS archive — linked only when one of these appears
|
|
1723
|
+
* on the IR; moduleUsesTls is the switch, and every tls/https libCall
|
|
1724
|
+
* also counts as net AND http use so both units link and install).
|
|
1725
|
+
* tls.createServer takes (cert, key[, handler]) — cert/key are PEM
|
|
1726
|
+
* strings or Buffers (the emitter passes data+len for either); the
|
|
1727
|
+
* handler is Node's 'secureConnection' (fires post-handshake with a
|
|
1728
|
+
* socket that behaves exactly like a net socket, the same adapters as
|
|
1729
|
+
* net.createServer). https.createServer is (cert, key, handler) with
|
|
1730
|
+
* the http request-handler adapters. https.request/requestCb extend
|
|
1731
|
+
* the http client row with (…, rejectUnauthorized: bool, ca: PEM
|
|
1732
|
+
* string/Buffer — "" for none) and default port 443; everything else
|
|
1733
|
+
* (write/end/destroy/events, the response surface) IS the http client
|
|
1734
|
+
* surface — the handles are the same kinds. */
|
|
1735
|
+
| "tls.createServer" | "tls.createServerCb"
|
|
1736
|
+
/** RUNTIME options records (the divergence-66 stance): the *Dyn
|
|
1737
|
+
* creators take a checked-dynamic (dyn) options value whose members
|
|
1738
|
+
* read at runtime — cert/key extract like the literal path, members
|
|
1739
|
+
* whose literal forms fence THROW the catchable fence at runtime, and
|
|
1740
|
+
* undocumented keys drop like Node drops them. tls.pemDyn is the
|
|
1741
|
+
* literal walk's runtime-valued cert/key extraction: (value, whatLit)
|
|
1742
|
+
* → PEM bytes (strings/Buffers/one-element arrays of those) or the
|
|
1743
|
+
* thrown fence. All of them may throw. */
|
|
1744
|
+
| "tls.pemDyn" | "tls.createServerDyn" | "tls.createServerDynCb" | "https.createServerDyn" | "https.createServerDynCb"
|
|
1745
|
+
/** tls.connect — the TLS client socket: (port, host, opts[, cb]) where
|
|
1746
|
+
* port -1 reads options.port, host "" reads options.host, and opts is
|
|
1747
|
+
* the runtime (dyn) options record (rejectUnauthorized/ca/servername
|
|
1748
|
+
* implemented; other documented members throw the runtime fence). The
|
|
1749
|
+
* callback fires post-handshake — Node's secureConnect timing. */
|
|
1750
|
+
| "tls.connect" | "tls.connectCb"
|
|
1751
|
+
/** The TLSSocket member surface on the socket kind: authorized (bool —
|
|
1752
|
+
* Node's verify verdict), authorizationError (the verify-failure CODE
|
|
1753
|
+
* STRING or null), the 'secureConnect' registration (a TLS socket's
|
|
1754
|
+
* conn list fires at establishment; plain sockets never fire it), and
|
|
1755
|
+
* the 'session' registration (fires once with the serialized session —
|
|
1756
|
+
* a Buffer; the received-ticket event). */
|
|
1757
|
+
| "tls.sockAuthorized" | "tls.sockAuthError" | "tls.sockOnSecureConnect" | "tls.sockOnSession"
|
|
1758
|
+
/** tls.createSecureContext({ cert, key }) — parses the PEM pair into an
|
|
1759
|
+
* opaque SecureContext handle (secureCtx kind) for SNI callbacks to
|
|
1760
|
+
* answer with; cert/key are PEM strings or Buffers like createServer's. */
|
|
1761
|
+
| "tls.createSecureContext" | "https.createServer" | "https.request" | "https.requestCb"
|
|
1762
|
+
/** A call through a `const requestFn = tls ? https.request :
|
|
1763
|
+
* http.request` binding — the module-function-as-value ternary between
|
|
1764
|
+
* the two known clients: the https.request row with a leading `secure`
|
|
1765
|
+
* bool that picks the dial at RUNTIME (true = the TLS client, exactly
|
|
1766
|
+
* https.request; false = the plain client, exactly http.request —
|
|
1767
|
+
* rejectUnauthorized/ca ignored there like Node ignores TLS options on
|
|
1768
|
+
* http.request). The "https." prefix keeps the TLS unit linked. */
|
|
1769
|
+
| "https.requestFn" | "https.requestFnCb"
|
|
1770
|
+
/** node:http2, the compatibility slice (SEMANTICS.md divergence 57):
|
|
1771
|
+
* createSecureServer is the https server WITHOUT an eager handler —
|
|
1772
|
+
* the same scr_https_create_server with a NULL closure (ALPN
|
|
1773
|
+
* advertises http/1.1 only; every connection serves HTTP/1.1).
|
|
1774
|
+
* serverOnRequest installs 'request' listeners after creation (the
|
|
1775
|
+
* http adapters pick the (req, res)/(req)/() shape; a once flag rides
|
|
1776
|
+
* along; on a server with no HTTP parser the registration is dead
|
|
1777
|
+
* weight, like Node's never-fired 'request' on a net server).
|
|
1778
|
+
* serverOnSessionError evaluates and releases its callback — no h2
|
|
1779
|
+
* session ever exists, so the event NEVER fires. */
|
|
1780
|
+
| "http2.createSecureServer"
|
|
1781
|
+
/** createSecureServer with an SNI callback: args are (cert, key, sniCb)
|
|
1782
|
+
* where sniCb is the JS SNICallback — a `(servername, cb) => void`
|
|
1783
|
+
* closure, or the `SNICallback | undefined` union from the conditional-
|
|
1784
|
+
* spread spelling (`...(x ? { SNICallback: x } : {})`; the emitter
|
|
1785
|
+
* unwraps the union — the undefined arm means "no callback", exactly
|
|
1786
|
+
* the no-SNI server). The runtime parses each connection's ClientHello
|
|
1787
|
+
* for the server_name extension BEFORE the TLS handshake begins, calls
|
|
1788
|
+
* the callback with (servername, answer-closure), and resumes the
|
|
1789
|
+
* handshake when the answer arrives — cb(err) tears the socket down
|
|
1790
|
+
* silently (Node's 'tlsClientError' default), cb(null, ctx) serves
|
|
1791
|
+
* ctx's cert/key, cb(null, undefined) serves the default pair. */
|
|
1792
|
+
| "http2.createSecureServerSni"
|
|
1793
|
+
/** The REAL h2-over-TLS server (createSecureServer WITHOUT allowHTTP1):
|
|
1794
|
+
* scr_http2_create_secure_server — the h2c session machinery behind an
|
|
1795
|
+
* mbedTLS handshake whose ALPN advertises h2 alone (an http/1.1-only
|
|
1796
|
+
* client fails the handshake with no_application_protocol, Node's
|
|
1797
|
+
* h2-only split). args are (cert, key) — PEM strings or Buffers. */
|
|
1798
|
+
| "http2.createSecureServerH2" | "http.serverOnRequest" | "http2.serverOnSessionError"
|
|
1799
|
+
/** The guarded h2-only stream call (`req.stream?.on(...)`): stream is
|
|
1800
|
+
* undefined on every connection the allowHTTP1 lowering accepts, so
|
|
1801
|
+
* the optional chain short-circuits — a VOID no-op the emitter drops
|
|
1802
|
+
* (statement position enforced by the frontend). */
|
|
1803
|
+
| "http2.streamNoop"
|
|
1804
|
+
/** The UNGUARDED h2-only stream call (`req.stream.on(...)`): stream is
|
|
1805
|
+
* undefined on every connection the allowHTTP1 lowering accepts — and
|
|
1806
|
+
* on every HTTP/1.1 connection of Node's own allowHTTP1 server — so the
|
|
1807
|
+
* call IS Node's member read on undefined: throws the exact catchable
|
|
1808
|
+
* TypeError ("Cannot read properties of undefined (reading 'on')").
|
|
1809
|
+
* One arg: the read member's name (a string literal). Never returns. */
|
|
1810
|
+
| "http2.streamUndefCall"
|
|
1811
|
+
/** node:http2, the REAL h2c surface (scr_http2.c — frame codec + HPACK
|
|
1812
|
+
* over the net loop; the design note atop that file has the story).
|
|
1813
|
+
* Sessions and streams are first-class handle kinds; 'stream'/'response'
|
|
1814
|
+
* payloads cross as flat [name, value, ...] pairs arrays and an EMITTED
|
|
1815
|
+
* adapter closure builds the program-side headers record (the response
|
|
1816
|
+
* :status rides separately as a number). */
|
|
1817
|
+
| "http2.createServer" | "http2.createServerReq" | "http2.serverOnStream" | "http2.serverOnSession"
|
|
1818
|
+
/** connect(authority[, listener]) — h2c prior knowledge; the listener
|
|
1819
|
+
* closure (if any) is the 'connect' once-listener. */
|
|
1820
|
+
| "http2.connect" | "http2.connectCb"
|
|
1821
|
+
/** session.request(pairs?, endStream) — endStream is a tri-state f64:
|
|
1822
|
+
* -1 the method's payload-meaningless default, 0/1 explicit. */
|
|
1823
|
+
| "http2.sessionRequest" | "http2.sessionClose" | "http2.sessionCloseCb" | "http2.sessionDestroy" | "http2.sessionOnClose" | "http2.sessionOnError" | "http2.sessionOnConnect" | "http2.sessionOnStream" | "http2.sessionOnGoaway" | "http2.sessionSettings0" | "http2.sessionSettings" | "http2.sessionSettingsDynCb" | "http2.sessionSettingsCb0" | "http2.sessionOnSettingsDyn" | "http2.sessionOnSettings0" | "http2.sessionSettingsGet" | "http2.sessionPendingSettingsAck" | "http2.getDefaultSettings" | "http2.sessionClosed" | "http2.sessionDestroyed" | "http2.sessionEncrypted" | "http2.sessionType" | "http2.sessionAlpn" | "http2.sessionSocket"
|
|
1824
|
+
/** stream.respond(pairs?, endStream) — the server answer. */
|
|
1825
|
+
| "http2.streamRespond" | "http2.streamWrite" | "http2.streamWriteBytes" | "http2.streamEnd" | "http2.streamEndStr" | "http2.streamEndBytes" | "http2.streamClose" | "http2.streamCloseCb" | "http2.streamDestroy" | "http2.streamSetEncoding" | "http2.streamSetEncodingRet" | "http2.streamResume" | "http2.streamPause" | "http2.streamOnData" | "http2.streamOnEnd" | "http2.streamOnClose" | "http2.streamOnAborted" | "http2.streamOnError" | "http2.streamOnResponse" | "http2.streamId" | "http2.streamRstCode" | "http2.streamDestroyed" | "http2.streamClosed" | "http2.streamAborted" | "http2.streamPending" | "http2.streamSession"
|
|
1826
|
+
/** socket.encrypted — `boolean | undefined`: the true arm iff the
|
|
1827
|
+
* socket carries a TLS transport (Node types `encrypted: true` on
|
|
1828
|
+
* TLSSocket; plain sockets answer undefined — the proxy.ts isEncrypted
|
|
1829
|
+
* idiom reads it through a cast). */
|
|
1830
|
+
| "net.sockEncrypted" | "http.clientWrite" | "http.clientWriteBytes" | "http.clientEnd" | "http.clientEndStr" | "http.clientEndBytes"
|
|
1831
|
+
/** The checked-dynamic chunk twins (the net.sockWriteDyn story). */
|
|
1832
|
+
| "http.clientWriteDyn" | "http.clientEndDyn"
|
|
1833
|
+
/** request/get with a URL-STRING first argument: the runtime parses it
|
|
1834
|
+
* (WHATWG) and dials — throws catchably on an unparsable input or a
|
|
1835
|
+
* non-http scheme. */
|
|
1836
|
+
| "http.requestUrl" | "http.requestUrlCb" | "http.clientDestroy" | "http.clientDestroyed" | "http.clientOnResponse" | "http.clientOnError" | "http.clientOnTimeout" | "http.clientOnClose"
|
|
1837
|
+
/** fs/promises (scr_lib.c over scr_async.c's settled minting): the SAME
|
|
1838
|
+
* sync syscalls, wrapped in an ALREADY-SETTLED promise — failure
|
|
1839
|
+
* REJECTS (catchable at the await) instead of throwing, so none of
|
|
1840
|
+
* these are in the may-throw seed. readFile is utf8-fenced like
|
|
1841
|
+
* readFileSync. The non-interleaving divergence is documented in
|
|
1842
|
+
* SEMANTICS.md. */
|
|
1843
|
+
/** node:crypto, the string-producing slice: randomUUID (never throws)
|
|
1844
|
+
* and the COMPOSED randomBytes(n).toString("hex"|"base64") — one
|
|
1845
|
+
* libCall, the Buffer never escapes (bare randomBytes is fenced).
|
|
1846
|
+
* randomBytesToString THROWS Node's RangeError on out-of-range sizes. */
|
|
1847
|
+
| "crypto.randomUUID" | "crypto.randomBytesToString"
|
|
1848
|
+
/** The COMPOSED hash chain createHash(alg).update(data).digest(enc)
|
|
1849
|
+
* fused into one call — the Hash handle never materializes. Args are
|
|
1850
|
+
* (alg, data, enc); alg is "sha256" | "sha1" and enc "hex" | "base64",
|
|
1851
|
+
* both compile-time literals (frontend-fenced). Strings hash their
|
|
1852
|
+
* UTF-8 bytes (Node's default input encoding); the bytes form hashes a
|
|
1853
|
+
* Buffer/typed array's bytes. Pure; never throw. */
|
|
1854
|
+
| "crypto.hashDigestStr" | "crypto.hashDigestBytes"
|
|
1855
|
+
/** crypto.randomBytes(n) → a real u8 Buffer (+1). THROWS Node's
|
|
1856
|
+
* RangeError on out-of-range sizes, exactly like the composed
|
|
1857
|
+
* randomBytesToString (which keeps its one-libCall lowering — the two
|
|
1858
|
+
* coexist: the composed form never materializes the Buffer). */
|
|
1859
|
+
| "crypto.randomBytes"
|
|
1860
|
+
/** The Buffer statics with fixed (always-u8) signatures. fromStr is
|
|
1861
|
+
* `Buffer.from(string, enc)` — the frontend completes an omitted
|
|
1862
|
+
* encoding to "utf8" and fences non-literal/unsupported ones; hex and
|
|
1863
|
+
* base64 decode Node-leniently, so it never throws. concat takes ONE
|
|
1864
|
+
* bytes<u8>[] arg (the list) and returns a fresh copy. `Buffer.from(u8)`
|
|
1865
|
+
* and `Buffer.alloc(n)` need no libFn — they lower to bytesNew. */
|
|
1866
|
+
| "buffer.fromStr" | "buffer.concat"
|
|
1867
|
+
/** Buffer.byteLength(string, enc) — enc a NORMALIZED literal like
|
|
1868
|
+
* fromStr's — and Buffer.isEncoding(name) over a runtime string
|
|
1869
|
+
* (case-insensitive against Node's alias set). Pure; never throw. */
|
|
1870
|
+
| "buffer.byteLenStr" | "buffer.isEncoding"
|
|
1871
|
+
/** Buffer.concat(list, totalLength): the concatenation truncated or
|
|
1872
|
+
* zero-padded to the total. THROWS Node's 'length' RangeError on a
|
|
1873
|
+
* negative/non-integer total (may-throw seed). */
|
|
1874
|
+
| "buffer.concatLen"
|
|
1875
|
+
/** The Buffer forms of the fs quartet: readFileSync(path) with NO
|
|
1876
|
+
* encoding → bytes<u8> (+1), writeFileSync(path, bytes), and the
|
|
1877
|
+
* fs/promises readFile(path) no-encoding form (an already-settled
|
|
1878
|
+
* promise, rejecting on failure like the other fsp members). The sync
|
|
1879
|
+
* pair THROWS catchably on failure exactly like the utf8 forms. */
|
|
1880
|
+
| "fs.readFileSyncBytes" | "fs.writeFileSyncBytes" | "fsp.readFileBytes"
|
|
1881
|
+
/** node:zlib (scr_zlib.c — cc.ts compiles/links it ONLY when these
|
|
1882
|
+
* appear on the IR, the regex/libcurl gating precedent): deflateSync/
|
|
1883
|
+
* inflateSync over u8 bytes with Node's default options. deflate never
|
|
1884
|
+
* throws (OOM aborts); inflate of corrupt input THROWS Node's error
|
|
1885
|
+
* catchably. */
|
|
1886
|
+
| "zlib.deflateSync" | "zlib.inflateSync"
|
|
1887
|
+
/** The Buffer overloads of the raw stream writes — same streams and
|
|
1888
|
+
* buffering as process.stdoutWrite/stderrWrite, constantly true. */
|
|
1889
|
+
| "process.stdoutWriteBytes" | "process.stderrWriteBytes" | "fsp.readFile" | "fsp.writeFile" | "fsp.mkdir"
|
|
1890
|
+
/** The fs/promises option/member tail the certs pipeline uses: mkdir's
|
|
1891
|
+
* literal { recursive?, mode? } options (the mkdirSync matrix behind
|
|
1892
|
+
* settled promises), unlink, chmod. Failures REJECT (catchable at the
|
|
1893
|
+
* await), like the rest of the fsp family. */
|
|
1894
|
+
| "fsp.mkdirMode" | "fsp.mkdirRecursive" | "fsp.mkdirRecursiveMode" | "fsp.unlink" | "fsp.chmod" | "fsp.readdir" | "fsp.rm" | "fsp.stat" | "process.argv" | "process.platform"
|
|
1895
|
+
/** getenv(3): one string key arg → the interned `string | undefined`
|
|
1896
|
+
* union (present: +1 string wrapped into the string arm; absent: the
|
|
1897
|
+
* interned undefined-arm instance). BOTH source forms — `process.env.FOO`
|
|
1898
|
+
* and `process.env[expr]` — lower here. Purely static; never throws. */
|
|
1899
|
+
| "process.envGet"
|
|
1900
|
+
/** setenv(3): (name, value) string args → void. Later envGet reads and
|
|
1901
|
+
* spawned children observe the write, like Node (values are strings —
|
|
1902
|
+
* the frontend fences non-string RHS). Never throws. */
|
|
1903
|
+
| "process.envSet"
|
|
1904
|
+
/** The whole environment as alternating [k0, v0, k1, v1, ...] strings in
|
|
1905
|
+
* environ order — the raw material of the process.env SNAPSHOT record
|
|
1906
|
+
* (the frontend's interned %env.snapshot helper keyed-writes the pairs
|
|
1907
|
+
* into a fresh `{ [k: string]: string | undefined }` record). Fresh +1
|
|
1908
|
+
* array; never throws. */
|
|
1909
|
+
| "process.envPairs" | "process.exit" | "process.cwd"
|
|
1910
|
+
/** getpid(2) / getuid(2): zero args → f64. POSIX-only target, so both
|
|
1911
|
+
* always answer (the checker's `getuid?` optionality covers Windows —
|
|
1912
|
+
* `process.getuid?.()` lowers as the plain call). Never throw. */
|
|
1913
|
+
| "process.pid" | "process.getuid" | "process.getgid"
|
|
1914
|
+
/** The ambient receiver — JS `this` in a plain (non-method) function
|
|
1915
|
+
* body: the innermost binding the current firing/dispatch window
|
|
1916
|
+
* pushed (Node's listener receiver, a dyn OBJ method's object, an
|
|
1917
|
+
* apply/call thisArg), or the undefined DOM singleton with none bound
|
|
1918
|
+
* (the strict-mode plain-call answer, the old constant). Zero args →
|
|
1919
|
+
* dyn (+1). Never throws. */
|
|
1920
|
+
| "dyn.this"
|
|
1921
|
+
/** process.execPath: the compiled binary's own resolved absolute path
|
|
1922
|
+
* (one interned string, +1 per read) — the honest answer where Node's
|
|
1923
|
+
* is the node executable's (SEMANTICS.md divergence 12). Never throws. */
|
|
1924
|
+
| "process.execPath"
|
|
1925
|
+
/** process.arch: the compiled binary's OWN architecture ("arm64",
|
|
1926
|
+
* "x64") — Node's answer for its own build on the same machine.
|
|
1927
|
+
* Interned; +1 per read. Never throws. */
|
|
1928
|
+
| "process.arch"
|
|
1929
|
+
/** process.versions.node: the runtime's Node COMPATIBILITY TARGET —
|
|
1930
|
+
* there is no Node under the binary, so this reports the version whose
|
|
1931
|
+
* semantics the runtime implements (SEMANTICS.md divergence 60, the
|
|
1932
|
+
* execPath stance). Interned; +1 per read. Never throws. */
|
|
1933
|
+
| "process.versionsNode" | "process.versionsOpenssl"
|
|
1934
|
+
/** umask(2): arg < 0 reads without setting (umask has no read-only form
|
|
1935
|
+
* — set 0, restore); otherwise sets and answers the PREVIOUS mask.
|
|
1936
|
+
* Never throws. */
|
|
1937
|
+
| "process.umask"
|
|
1938
|
+
/** chdir(2) — throws Node's fs-shaped error (ENOENT/EACCES/ENOTDIR,
|
|
1939
|
+
* syscall "chdir") on failure. */
|
|
1940
|
+
| "process.chdir"
|
|
1941
|
+
/** process._exiting: true once the exit sequence began (exit listeners
|
|
1942
|
+
* running) — the runtime flag scr_run_exit_listeners/process.exit set.
|
|
1943
|
+
* Never throws. */
|
|
1944
|
+
| "process.exiting"
|
|
1945
|
+
/** os.type(): uname(2)'s sysname ("Darwin", "Linux"; "Windows_NT" on
|
|
1946
|
+
* win32) — Node's uv_os_uname answer. Interned per call; never throws. */
|
|
1947
|
+
| "os.type"
|
|
1948
|
+
/** os.totalmem(): total physical memory in bytes. Never throws. */
|
|
1949
|
+
| "os.totalmem"
|
|
1950
|
+
/** net's process-wide happy-eyeballs attempt budget (Node's default
|
|
1951
|
+
* 250ms): one runtime double in the core unit, so reading/writing it
|
|
1952
|
+
* never forces the net unit into the link. Never throw. */
|
|
1953
|
+
| "net.getAutoSelTimeout" | "net.setAutoSelTimeout"
|
|
1954
|
+
/** realpath(3) with Node's error shape (syscall "lstat" in the message,
|
|
1955
|
+
* Node's own spelling for realpathSync failures). +1 fresh string. */
|
|
1956
|
+
| "fs.realpathSync"
|
|
1957
|
+
/** kill(2) with Node's exact semantics and error shapes: the pid must be
|
|
1958
|
+
* an int32 (else the ERR_INVALID_ARG_TYPE TypeError text), the named
|
|
1959
|
+
* form resolves Node's signal-name table (unknown names throw the
|
|
1960
|
+
* ERR_UNKNOWN_SIGNAL TypeError), an omitted signal completes to
|
|
1961
|
+
* "SIGTERM" in the frontend, signal 0 probes, and a kill(2) failure
|
|
1962
|
+
* throws Node's `kill ESRCH`/`kill EPERM` Error. Result is Node's
|
|
1963
|
+
* constant true. */
|
|
1964
|
+
| "process.kill" | "process.killNum"
|
|
1965
|
+
/** execFileSync/execSync as ONE entry (args: cmd, argv, shell, input,
|
|
1966
|
+
* cwd, hasEnv, envPairs, timeoutMs, stdoutMode, stderrMode — see
|
|
1967
|
+
* scr_runtime.h). Throws Node's exact errors: "Command failed: <cmd>"
|
|
1968
|
+
* (+ captured stderr) on non-zero exit or signal death, "spawnSync
|
|
1969
|
+
* <file> ENOENT" on spawn failure, "spawnSync <file> ETIMEDOUT" after
|
|
1970
|
+
* the SIGTERM timeout. Result is the captured utf8 stdout (+1). */
|
|
1971
|
+
| "cp.execSync"
|
|
1972
|
+
/** The promisified-execFile capture (args: cmd, argv, cwd, hasEnv,
|
|
1973
|
+
* envPairs, timeoutMs): the same exec core in the async shape — both
|
|
1974
|
+
* streams captured, no echo, Node's ASYNC messages on the throw paths
|
|
1975
|
+
* ("Command failed: <cmd>\n<stderr>" with the unconditional newline,
|
|
1976
|
+
* "spawn <file> ENOENT" with .code, timeouts reporting as ordinary
|
|
1977
|
+
* SIGTERM command failures — never ETIMEDOUT). Result reuses the
|
|
1978
|
+
* ScrSpawnRes container (+1; stdout/stderr strings, status unused).
|
|
1979
|
+
* Called only from the frontend's interned %execFileAsync ASYNC helper,
|
|
1980
|
+
* whose fiber turns the throw into the rejection. */
|
|
1981
|
+
| "cp.execCapture"
|
|
1982
|
+
/** The raw byte writes: one borrowed string arg → bool (constantly true
|
|
1983
|
+
* — Node's backpressure signal never fires on these synchronous writes).
|
|
1984
|
+
* stdoutWrite shares console.log's stream AND buffer, so interleaved
|
|
1985
|
+
* output keeps source order; stderrWrite is unbuffered like Node's
|
|
1986
|
+
* stderr. No newline, no formatting, never throws. */
|
|
1987
|
+
| "process.stdoutWrite" | "process.stderrWrite" | "timers.setTimeout"
|
|
1988
|
+
/** The repeating timer pair. setInterval takes (callback, ms) like
|
|
1989
|
+
* setTimeout and RETURNS the f64 handle the fallback declarations
|
|
1990
|
+
* promise (ids start at 1, so truthiness narrowing works); the loop
|
|
1991
|
+
* owns the callback until clearInterval removes the entry (eagerly — a
|
|
1992
|
+
* live interval keeps the loop alive, a cleared one releases it, like
|
|
1993
|
+
* Node). Neither throws; a throw ESCAPING an interval callback ends the
|
|
1994
|
+
* program like a setTimeout throw. */
|
|
1995
|
+
| "timers.setInterval" | "timers.clearInterval"
|
|
1996
|
+
/** setTimeout WITH a clear handle (the f64 id) — the clearable/unref-able
|
|
1997
|
+
* one-shot; clearTimeout cancels it, .unref() drops it from loop
|
|
1998
|
+
* liveness. The plain timers.setTimeout stays the handle-less
|
|
1999
|
+
* fire-and-forget. */
|
|
2000
|
+
| "timers.setTimeoutHandle" | "timers.clearTimeout"
|
|
2001
|
+
/** Timeout.unref()/ref()/hasRef() — loop-liveness bookkeeping over the
|
|
2002
|
+
* handle id. unref/ref RETURN the handle (f64) for chaining; hasRef
|
|
2003
|
+
* returns bool. */
|
|
2004
|
+
| "timers.unref" | "timers.ref" | "timers.hasRef"
|
|
2005
|
+
/** Timeout.refresh() — re-arm to now + the original delay (from the
|
|
2006
|
+
* heap or from inside the firing callback; a one-shot that fired on an
|
|
2007
|
+
* earlier turn is gone and no-ops — documented divergence). Returns
|
|
2008
|
+
* the handle for chaining like unref/ref. */
|
|
2009
|
+
| "timers.refresh"
|
|
2010
|
+
/** setImmediate/clearImmediate — Node's check phase: callbacks run
|
|
2011
|
+
* once per loop turn AFTER due timers, FIFO, and immediates queued
|
|
2012
|
+
* mid-phase wait for the next turn. setImmediate returns the f64
|
|
2013
|
+
* handle (its own id space — clearTimeout of an Immediate no-ops,
|
|
2014
|
+
* like Node); the Immediate ref trio mirrors the Timeout one (an
|
|
2015
|
+
* unref'd pending immediate neither keeps the loop alive nor fires
|
|
2016
|
+
* once nothing reffed remains). */
|
|
2017
|
+
| "timers.setImmediate" | "timers.clearImmediate" | "timers.immediateUnref" | "timers.immediateRef" | "timers.immediateHasRef"
|
|
2018
|
+
/** queueMicrotask (scr_async.c): the callback enters the SAME FIFO
|
|
2019
|
+
* promise continuations ride — one microtask order, like V8's queue —
|
|
2020
|
+
* and a throw is an UNCAUGHT exception (never a rejection).
|
|
2021
|
+
* timers.queueMicrotask takes an owned zero-param closure and never
|
|
2022
|
+
* throws; the Dyn form (checked-dynamic arguments — the mustCall
|
|
2023
|
+
* wrapper, the suite's invalid-input probes) throws Node's
|
|
2024
|
+
* ERR_INVALID_ARG_TYPE synchronously on a non-function value and calls
|
|
2025
|
+
* the function with zero arguments at drain. */
|
|
2026
|
+
| "timers.queueMicrotask" | "timers.queueMicrotaskDyn"
|
|
2027
|
+
/** The tolerated non-handle clear (`clearTimeout(null)`,
|
|
2028
|
+
* `clearInterval({})`, zero-argument forms): Node silently ignores
|
|
2029
|
+
* anything that is not a live handle — a VOID no-op the emitter drops
|
|
2030
|
+
* (only syntactically side-effect-free arguments take this path). */
|
|
2031
|
+
| "timers.clearNoop"
|
|
2032
|
+
/** process.nextTick(cb, ...args) — the user tick queue. args: [cb
|
|
2033
|
+
* (() => void; trailing call arguments ride the timer surface's
|
|
2034
|
+
* interned dyn thunk)]. Ticks drain BEFORE promise jobs at every loop
|
|
2035
|
+
* checkpoint, to joint exhaustion with them (Node's tick-then-
|
|
2036
|
+
* microtask order); ticks enqueued by station listeners run at the
|
|
2037
|
+
* NEXT checkpoint (the stream-tick station divergence, SEMANTICS.md).
|
|
2038
|
+
* Pending ticks are always-ready work — the loop neither sleeps nor
|
|
2039
|
+
* exits while any exist; ticks scheduled from 'exit' listeners never
|
|
2040
|
+
* run (Node). The enqueue itself never throws. */
|
|
2041
|
+
| "process.nextTick"
|
|
2042
|
+
/** The process introspection statics. uptime: seconds since the
|
|
2043
|
+
* binary's own start (fractional — a load-time monotonic anchor).
|
|
2044
|
+
* availableMemory/constrainedMemory: libuv's numbers (free-ish bytes;
|
|
2045
|
+
* the cgroup cap or 0). cpuUser/cpuSystem (+ threadCpu twins): the
|
|
2046
|
+
* process/thread CPU clocks in microseconds — the frontend composes
|
|
2047
|
+
* the {user, system} records. The *Diff forms answer current − prev
|
|
2048
|
+
* for one field; cpuPrevValidate throws Node's ERR_INVALID_ARG_VALUE
|
|
2049
|
+
* RangeError for negative/non-finite prev fields (user first, then
|
|
2050
|
+
* system — Node's order; MAY THROW). rusage(idx): one
|
|
2051
|
+
* process.resourceUsage() field by canonical index (Node's units).
|
|
2052
|
+
* activeResources: the loop's own bookkeeping — 'Timeout' per armed
|
|
2053
|
+
* (or firing, uncleared) timer, 'Immediate' per queued unfired
|
|
2054
|
+
* immediate; unmodeled resource kinds are absent (SEMANTICS.md). */
|
|
2055
|
+
| "process.uptime" | "process.availableMemory" | "process.constrainedMemory" | "process.cpuUser" | "process.cpuSystem" | "process.cpuUserDiff" | "process.cpuSystemDiff" | "process.threadCpuUser" | "process.threadCpuSystem" | "process.threadCpuUserDiff" | "process.threadCpuSystemDiff" | "process.cpuPrevValidate" | "process.rusage" | "process.activeResources"
|
|
2056
|
+
/** Process signal events — process.on/once/off("SIGINT" | "SIGTERM").
|
|
2057
|
+
* args: [signo f64 (the frontend bakes the POSIX number), cb, once
|
|
2058
|
+
* bool] for on; [signo, cb] for off (cb borrowed, removed by pointer
|
|
2059
|
+
* identity — Node's removeListener contract). Handlers run as
|
|
2060
|
+
* macrotasks at loop turns; watching replaces the default disposition
|
|
2061
|
+
* and removing the last listener restores it; signal listeners never
|
|
2062
|
+
* keep the loop alive (Node). Zero-param callbacks only (the ambient
|
|
2063
|
+
* shape). Never throw. */
|
|
2064
|
+
| "process.onSignal" | "process.offSignal"
|
|
2065
|
+
/** The process 'exit' event — process.on/once/off("exit"). args: [cb,
|
|
2066
|
+
* once bool] / [cb]. Listeners run SYNCHRONOUSLY at termination
|
|
2067
|
+
* (normal exit, process.exit(), the uncaught/unhandled exit-1 paths)
|
|
2068
|
+
* with the exit code; anything they schedule never runs, like Node.
|
|
2069
|
+
* Callback shapes: () => void or (code: number) => void — the emitter
|
|
2070
|
+
* picks the runtime adapter. Never throw. */
|
|
2071
|
+
| "process.onExit" | "process.offExit"
|
|
2072
|
+
/** process.stdin listener registration — stdin.on/once("data" | "end" |
|
|
2073
|
+
* "error", cb). args: [cb, once bool]. data callbacks: () => void or
|
|
2074
|
+
* (chunk: Uint8Array) => void; end: () => void; error: () => void or
|
|
2075
|
+
* (err: Error) => void (the child error adapters are reused). While a
|
|
2076
|
+
* data listener (or a parked for-await chunk promise) exists, stdin
|
|
2077
|
+
* keeps the loop alive — Node's flowing-stdin keep-alive. Never
|
|
2078
|
+
* throw. */
|
|
2079
|
+
| "stdin.onData" | "stdin.onEnd" | "stdin.onError"
|
|
2080
|
+
/** The for-await chunk source over process.stdin: no args, result
|
|
2081
|
+
* Promise<Uint8Array> (+1). Fulfills with the next arrived chunk; the
|
|
2082
|
+
* EMPTY bytes value is the done sentinel (POSIX reads never deliver
|
|
2083
|
+
* empty data chunks), which the for-await desugar turns into loop
|
|
2084
|
+
* exit. Never throws itself; awaiting it re-throws nothing (stdin
|
|
2085
|
+
* errors surface through 'error' listeners, not the iterator). */
|
|
2086
|
+
| "stdin.nextChunk"
|
|
2087
|
+
/** The runtime-provided Error hierarchy's entry points (scr_error.c).
|
|
2088
|
+
* error.new: one borrowed string arg (the message), result an owned (+1)
|
|
2089
|
+
* builtin error instance — the result TYPE names which builtin class
|
|
2090
|
+
* (backends derive the runtime kind from it). error.ctor: the
|
|
2091
|
+
* super(message) call of an `extends Error` constructor — borrowed
|
|
2092
|
+
* receiver (already allocated by the derived class's new) + borrowed
|
|
2093
|
+
* message, void; the receiver's type names the builtin class whose name
|
|
2094
|
+
* field to stamp. error.toString: borrowed `%Error`-typed receiver, +1
|
|
2095
|
+
* string in Node's "name: message" shape. None of the three throws. */
|
|
2096
|
+
| "error.new"
|
|
2097
|
+
/** A read of a `declare`d const NOTHING defines (the bundler-define
|
|
2098
|
+
* pattern — __VERSION__): always throws the catchable ReferenceError
|
|
2099
|
+
* Node raises at the access ("<name> is not defined"). args[0] is the
|
|
2100
|
+
* name; the result type is the read's declared type (a typed dummy the
|
|
2101
|
+
* unwind abandons — the value never exists). */
|
|
2102
|
+
| "global.undefRead"
|
|
2103
|
+
/** `X.name` through a class VALUE (scr_object.c): args[0] is a borrowed
|
|
2104
|
+
* classval; the result is the class object's stored .name string,
|
|
2105
|
+
* retained (+1 — the string is an interned immortal, so the retain is a
|
|
2106
|
+
* no-op, kept for ownership uniformity). Never throws. A direct
|
|
2107
|
+
* `C.name` on the class name itself folds to a strLit instead. */
|
|
2108
|
+
| "class.name" | "error.ctor" | "error.toString"
|
|
2109
|
+
/** `new DOMException(message?, nameOrOptions?)` (scr_error.c): both args
|
|
2110
|
+
* are borrowed DOM values (the lowering passes the DOM undefined for an
|
|
2111
|
+
* absent argument, so WebIDL's optionality lives in one place). The
|
|
2112
|
+
* runtime ToStrings the message ("" for absent/undefined), resolves the
|
|
2113
|
+
* name — absent/undefined → "Error", a non-null object → ToString of its
|
|
2114
|
+
* `name` member plus the `cause` own-property record, anything else →
|
|
2115
|
+
* ToString — and stamps the legacy code from the WebIDL name table (0
|
|
2116
|
+
* off-table). Result is an owned (+1) %DOMException. Never throws (DOM
|
|
2117
|
+
* ToString is total). */
|
|
2118
|
+
| "error.newDom"
|
|
2119
|
+
/** DOMException's own read surface (scr_error.c; %DOMException receivers
|
|
2120
|
+
* only — borrowed). domCode: the legacy numeric code. domHasCause: the
|
|
2121
|
+
* options form's own-property record (`'cause' in e`). domCause: the
|
|
2122
|
+
* cause value, +1 (the DOM undefined when absent — matching Node's
|
|
2123
|
+
* undefined read). None throws. */
|
|
2124
|
+
| "error.domCode" | "error.domHasCause" | "error.domCause"
|
|
2125
|
+
/** structuredClone of a %DOMException receiver (scr_error.c): WebIDL
|
|
2126
|
+
* serialization — name/message copy, the legacy code re-derives, cause
|
|
2127
|
+
* does not serialize. args are the borrowed receiver and the borrowed
|
|
2128
|
+
* options DOM value (the DOM undefined when absent — the shared
|
|
2129
|
+
* validation throws Node's exact option errors; any non-empty transfer
|
|
2130
|
+
* list throws DataCloneError, nothing static is transferable). Result
|
|
2131
|
+
* +1 %DOMException. */
|
|
2132
|
+
| "error.domClone"
|
|
2133
|
+
/** `d instanceof TypeError` (and the other BUILTIN error classes) on a
|
|
2134
|
+
* checked-dynamic value (scr_json.c): the from_error cache holds the
|
|
2135
|
+
* DOM↔error identity edge, so the test resolves the runtime error and
|
|
2136
|
+
* asks its vtable's stamped preorder interval — exact for every error
|
|
2137
|
+
* that crossed the boundary. A DOM object that never came from an
|
|
2138
|
+
* error (a hand-built {%error} literal) answers false: subclass
|
|
2139
|
+
* identity is unknowable there (the root keeps dynTest's marker
|
|
2140
|
+
* answer). args are the borrowed dyn and the SCR_ERR_* kind literal.
|
|
2141
|
+
* Never throws. */
|
|
2142
|
+
| "dyn.errInstanceof"
|
|
2143
|
+
/** Object.keys/values/entries over a CHECKED-DYNAMIC receiver
|
|
2144
|
+
* (scr_json.c): the runtime walks the DOM node's own members in JS
|
|
2145
|
+
* own-key order (array-index keys ascending first, then insertion
|
|
2146
|
+
* order) and answers a DOM array (entries: an array of [key, value]
|
|
2147
|
+
* pairs; values RETAIN the member nodes — reference semantics, like
|
|
2148
|
+
* JS). Strings/arrays/bytes answer their index keys; other scalars an
|
|
2149
|
+
* empty array; null/undefined throw Node's catchable TypeError
|
|
2150
|
+
* ("Cannot convert undefined or null to object"). */
|
|
2151
|
+
| "dyn.objKeys" | "dyn.objValues" | "dyn.objEntries"
|
|
2152
|
+
/** structuredClone over the DOM (scr_json.c): the JSON-safe subset plus
|
|
2153
|
+
* bytes (a fresh copy — a Buffer clones as a plain Uint8Array, like
|
|
2154
|
+
* Node), deep. Functions and handle kinds throw the spec's catchable
|
|
2155
|
+
* DataCloneError; CYCLES throw the scriptc fence (the DOM cannot
|
|
2156
|
+
* represent them — Node clones cycles; documented divergence). The
|
|
2157
|
+
* options DOM value validates with Node's exact errors (dictionary
|
|
2158
|
+
* conversion, the transfer-sequence member; any non-empty transfer
|
|
2159
|
+
* list throws DataCloneError). dyn.cloneMissing is the zero-argument
|
|
2160
|
+
* call: always throws Node's TypeError [ERR_MISSING_ARGS] with Node's
|
|
2161
|
+
* own (verbatim, doubly-wrapped) message. */
|
|
2162
|
+
| "dyn.structuredClone" | "dyn.cloneMissing"
|
|
2163
|
+
/** `new RegExp(pattern, flags?)` (scr_regex.c): a heap regex over the
|
|
2164
|
+
* same libregexp engine the literals use. The pattern compiles EAGERLY
|
|
2165
|
+
* so an invalid pattern (or an unknown flag letter) throws Node's
|
|
2166
|
+
* catchable SyntaxError at construction — Node's message shape with
|
|
2167
|
+
* libregexp's detail text (approximate fidelity; e.name exact). An
|
|
2168
|
+
* empty pattern stores the spec's "(?:)" source. Both args borrowed
|
|
2169
|
+
* strings (the lowering completes an absent flags to ""); result +1.
|
|
2170
|
+
* The result TYPE is the regex kind, so the link switch pulls the
|
|
2171
|
+
* engine exactly like a literal. */
|
|
2172
|
+
| "regex.new"
|
|
2173
|
+
/** structuredClone with a NON-EMPTY transfer array of static values:
|
|
2174
|
+
* nothing static is transferable, so the call always throws Node's
|
|
2175
|
+
* catchable DataCloneError ("Found invalid value in transferList.") —
|
|
2176
|
+
* lowered directly (the list's values need no DOM representation to
|
|
2177
|
+
* fail). */
|
|
2178
|
+
| "dyn.cloneTransferFail"
|
|
2179
|
+
/** node:events EventEmitter (scr_events_emitter.c, link-gated by
|
|
2180
|
+
* moduleUsesEmitter). The receiver of every instance form is a borrowed
|
|
2181
|
+
* emitter-hierarchy object (`%EventEmitter` or a user subclass — the
|
|
2182
|
+
* backend reinterprets to ScrEmitter*, the identical prefix); event
|
|
2183
|
+
* names are borrowed strings (compile-time literals — the frontend
|
|
2184
|
+
* fences non-literals and unifies each event's argument tuple program-
|
|
2185
|
+
* wide). The chaining forms (on/off/removeAll/setMax) return the
|
|
2186
|
+
* receiver +1 typed as its static class, Node's `return this`.
|
|
2187
|
+
*
|
|
2188
|
+
* emitter.new: `new EventEmitter()` → a +1 bare emitter. emitter.ctor:
|
|
2189
|
+
* super() into the prefix of an emitted subclass (borrowed receiver,
|
|
2190
|
+
* void — allocation already initialized the prefix). emitter.on:
|
|
2191
|
+
* (recv, name, cb /moves/, once, prepend) — the backend synthesizes the
|
|
2192
|
+
* per-signature va_list invoke adapter from the cb's func type.
|
|
2193
|
+
* emitter.emit: (recv, name, ...tuple) — VARIADIC, the one libCall
|
|
2194
|
+
* whose arg count exceeds its signature; args are borrowed, result is
|
|
2195
|
+
* the had-listeners bool. emitter.emitError: emit('error', err) —
|
|
2196
|
+
* throws err when unhandled. count/countFn/names/listeners/getMax/
|
|
2197
|
+
* setMax/setDefaultMax/getDefaultMax are the introspection surface. */
|
|
2198
|
+
| "emitter.new" | "emitter.ctor" | "emitter.on" | "emitter.off" | "emitter.checkListener" | "emitter.onDyn" | "emitter.offDyn" | "emitter.removeAll" | "emitter.emit" | "emitter.emitError" | "emitter.count" | "emitter.countFn" | "emitter.names" | "emitter.listeners" | "emitter.setMax" | "emitter.getMax"
|
|
2199
|
+
/** Stream-'data' registration twins of emitter.on/onDyn (same args):
|
|
2200
|
+
* chosen at registration sites whose receiver is stream-rooted, so the
|
|
2201
|
+
* backend emits DATA thunks — the runtime's 'data' emission carries
|
|
2202
|
+
* BOTH payload slots (bytes, string; exactly one non-NULL — encoded
|
|
2203
|
+
* streams deliver strings), and the thunk unwraps the listener's
|
|
2204
|
+
* declared side (typed) or boxes by tag (dyn). emitter.emitData is the
|
|
2205
|
+
* user-emit form: (recv, name, chunk) with a bytes OR string chunk. */
|
|
2206
|
+
| "emitter.onData" | "emitter.onDataDyn" | "emitter.emitData" | "emitter.setDefaultMax" | "emitter.getDefaultMax"
|
|
2207
|
+
/** node:stream (scr_stream.c, link-gated by moduleUsesStream — which
|
|
2208
|
+
* implies the emitter unit: stream events dispatch through the embedded
|
|
2209
|
+
* ScrEmitter registry). Receivers are borrowed stream-class objects
|
|
2210
|
+
* (`%Readable`/`%Writable`/`%Duplex`/`%Transform`/`%PassThrough` — one
|
|
2211
|
+
* runtime layout, reinterpreted by side).
|
|
2212
|
+
*
|
|
2213
|
+
* Constructors (`readable.new` et al): args are [hwmR, hwmW, flags]
|
|
2214
|
+
* followed by the PRESENT user callbacks in canonical order (read,
|
|
2215
|
+
* write, final, destroy, transform, flush — the flags f64 is a bitmask
|
|
2216
|
+
* naming which follow; absent ones emit NULL). Every callback closure
|
|
2217
|
+
* MOVES and carries a leading `this` param (the stream), invoked
|
|
2218
|
+
* through compiler-emitted adapters. Results are +1.
|
|
2219
|
+
*
|
|
2220
|
+
* readable.push / readable.pushStr / readable.pushNull: Node's push —
|
|
2221
|
+
* buffers or delivers (bytes chunk borrowed; string converted utf8);
|
|
2222
|
+
* returns the below-hwm answer. readable.read: (recv, size — -1 for
|
|
2223
|
+
* absent) → Buffer|null union. pause/resume return recv +1 (`this`);
|
|
2224
|
+
* isPaused answers the flag. readable.pipe: (recv, dst, end) → dst +1,
|
|
2225
|
+
* fires 'pipe' on dst; readable.unpipe (recv[, dst]) → recv +1.
|
|
2226
|
+
* writable.write/writeStr: (recv, chunk[, cb]) → below-hwm bool (cb
|
|
2227
|
+
* MOVES when present, called after the user write completes).
|
|
2228
|
+
* writable.end: (recv, flags[, chunk][, cb]) → recv +1. cork/uncork are
|
|
2229
|
+
* void. stream.destroy/destroyErr: (recv[, err]) → recv +1.
|
|
2230
|
+
* stream.prop: (recv, name-literal) → the flag/number the name asks
|
|
2231
|
+
* for; stream.errored → Error|null union; readable.flowing →
|
|
2232
|
+
* bool|null union. All may leave a listener's exception pending
|
|
2233
|
+
* (dispatch runs user code synchronously, like emit). */
|
|
2234
|
+
| "readable.new" | "writable.new" | "duplex.new" | "transform.new" | "passthrough.new"
|
|
2235
|
+
/** Subclass initialization (`super(options?)` in a user `extends
|
|
2236
|
+
* Readable` constructor): same tail as the `.new` forms, prefixed with
|
|
2237
|
+
* the BORROWED receiver (the emitted subclass allocation — vtable and
|
|
2238
|
+
* display name stamped, state NULL until here). Overridden underscore
|
|
2239
|
+
* methods arrive as synthesized wrapper closures dispatching through
|
|
2240
|
+
* the vtable. Void result. */
|
|
2241
|
+
| "readable.init" | "writable.init" | "duplex.init" | "transform.init" | "passthrough.init"
|
|
2242
|
+
/** The dyn-options twins (a checked-dynamic options record — the JS
|
|
2243
|
+
* lane's `super(options)` forwarding and `new Readable(dynVar)`): the
|
|
2244
|
+
* option walk runs at RUNTIME with Node's reading rules. newDyn:
|
|
2245
|
+
* (optsDyn) → the fresh stream; initDyn: (recv, optsDyn, flags,
|
|
2246
|
+
* ...fallback wrapper closures in canonical order — the flags literal
|
|
2247
|
+
* names which ride, exactly the .init callback ABI). MAY THROW (a
|
|
2248
|
+
* consumed-but-unlowered option is the compile fence's runtime twin). */
|
|
2249
|
+
/** stream.finished(s, cb) — the callback form: the watcher fires once
|
|
2250
|
+
* at the terminal point with the finish status; the result is the +1
|
|
2251
|
+
* cleanup closure. stream.pipeline(count, s1..sn, cb): chains pipes,
|
|
2252
|
+
* propagates the first error by destroying the rest, calls cb after the
|
|
2253
|
+
* last 'close'; answers the destination +1. The Dyn twins take the
|
|
2254
|
+
* callback as a checked-dynamic VALUE (mustCall wrappers). */
|
|
2255
|
+
| "stream.finished" | "stream.finishedDyn" | "stream.pipeline" | "stream.pipelineDyn" | "readable.newDyn" | "writable.newDyn" | "duplex.newDyn" | "transform.newDyn" | "passthrough.newDyn" | "readable.initDyn" | "writable.initDyn" | "duplex.initDyn" | "transform.initDyn" | "passthrough.initDyn" | "readable.push" | "readable.pushStr" | "readable.pushNull" | "readable.pushU" | "readable.pushDyn" | "readable.unshift" | "readable.unshiftStr" | "readable.read" | "readable.pause" | "readable.resume" | "readable.setEncoding"
|
|
2256
|
+
/** for-await over a readable (the desugared loop's per-pass promise):
|
|
2257
|
+
* +1 promise of the next chunk — buffered content, the EOF sentinel
|
|
2258
|
+
* (empty Buffer / dyn undefined), or a rejection with the stream's
|
|
2259
|
+
* error. The Dyn twin boxes chunks by runtime tag (the JS lane).
|
|
2260
|
+
* readable.fromArr is Readable.from(array): a fully-seeded object-
|
|
2261
|
+
* entry stream (one whole chunk per element; strings per the flag). */
|
|
2262
|
+
| "readable.nextChunk" | "readable.nextChunkDyn" | "readable.fromArr" | "readable.isPaused" | "readable.pipe" | "readable.unpipe" | "readable.flowing" | "writable.write" | "writable.writeStr" | "writable.writeU" | "writable.writeDyn" | "writable.end" | "writable.cork" | "writable.uncork" | "stream.destroy" | "stream.destroyErr" | "stream.prop" | "stream.errored"
|
|
2263
|
+
/** The underscore-method assignment surface (`r._read = fn` after
|
|
2264
|
+
* construction — Node's own-property shadow of the prototype method):
|
|
2265
|
+
* args [stream receiver (borrowed), callback closure (+1 moves)]. The
|
|
2266
|
+
* runtime slot the matching option callback fills swaps its closure
|
|
2267
|
+
* and invoke thunk; the next dispatch uses it (Node's timing). The
|
|
2268
|
+
* setters themselves never throw. */
|
|
2269
|
+
| "stream.setRead" | "stream.setWrite" | "stream.setFinal" | "stream.setDestroy" | "stream.setTransform" | "stream.setFlush"
|
|
2270
|
+
/** NodeJS.ErrnoException's `.code` read: borrowed error-hierarchy
|
|
2271
|
+
* receiver → the interned `string | undefined` union (type-directed
|
|
2272
|
+
* construction in the backend, the process.envGet pattern) — the errno
|
|
2273
|
+
* name where a throw site stamped one (fs, exec spawn/timeout,
|
|
2274
|
+
* process.kill, the spawn 'error' event), the undefined arm everywhere
|
|
2275
|
+
* else. Never throws. */
|
|
2276
|
+
| "error.code"
|
|
2277
|
+
/** node:assert (scr_assert.c; assert.match in scr_regex.c — every call
|
|
2278
|
+
* site carries a regex value, so the regex link switch is already on).
|
|
2279
|
+
* Failures throw a catchable AssertionError — a runtime %Error whose
|
|
2280
|
+
* name is "AssertionError" and whose code slot is "ERR_ASSERTION" — so
|
|
2281
|
+
* `instanceof Error`, `.name`, `.message`, and `.code` all answer like
|
|
2282
|
+
* Node's. Generated messages are Node's assertion_error.js scalar forms
|
|
2283
|
+
* byte-exactly (the short `a !== b` form, the stacked `+ actual
|
|
2284
|
+
* - expected` diff with the string `^` indicator, the inline-vs-block
|
|
2285
|
+
* not-equal split); composite deep failures carry the header line
|
|
2286
|
+
* without the rendered inspect diff (documented divergence).
|
|
2287
|
+
*
|
|
2288
|
+
* assert.ok: (pass, message) — the frontend computed the truthiness AND
|
|
2289
|
+
* the full message (the user's, or the compile-time source-text form —
|
|
2290
|
+
* assert.fail lowers here too with pass=false). assert.eqF64/eqStr/
|
|
2291
|
+
* eqBool: (a, b, negated, deep, msg, hasMsg) — Object.is comparison,
|
|
2292
|
+
* covering strictEqual/notStrictEqual and the scalar deepStrictEqual
|
|
2293
|
+
* pair; msg is a typed dummy ("" literal) when hasMsg is false (Node
|
|
2294
|
+
* distinguishes an omitted message from an empty one per operator).
|
|
2295
|
+
* assert.deepResult: (equal, negated, msg, hasMsg) — the verdict of a
|
|
2296
|
+
* frontend-synthesized structural comparison, turned into Node's throw.
|
|
2297
|
+
* assert.sameValue: Object.is over doubles (the deep-equal helpers'
|
|
2298
|
+
* number leaf; never throws). assert.match: (s, regex, negated, msg,
|
|
2299
|
+
* hasMsg) — a fresh exec from index 0. assert.throwsNone: (rejection,
|
|
2300
|
+
* ename, hasEname, msg, hasMsg) — the "Missing expected
|
|
2301
|
+
* exception|rejection" throw of assert.throws/rejects whose callback
|
|
2302
|
+
* returned (fulfilled) normally, with Node's ` (${expected.name})`
|
|
2303
|
+
* detail when the expected class or shape carries a name.
|
|
2304
|
+
* assert.throwsMismatch: (expectedName, error) — the wrong-class throw
|
|
2305
|
+
* of the assert.throws(fn, ErrorClass) form. assert.eqSym:
|
|
2306
|
+
* (a, b, negated, deep, msg, hasMsg) — strict equality over symbol
|
|
2307
|
+
* values, pointer identity with v24's "Symbol(desc)" stacked-diff
|
|
2308
|
+
* messages (scr_symbol.c, the assert.match pattern — symbol-typed
|
|
2309
|
+
* slots already flip the symbol link switch). assert.eqDyn:
|
|
2310
|
+
* (a, b, negated, deep, msg, hasMsg) — the whole quartet over
|
|
2311
|
+
* checked-dynamic operands (both slots dyn; the frontend boxes a
|
|
2312
|
+
* static side with dynFrom first): SameValue for the strict pair over
|
|
2313
|
+
* the DOM kinds (boxed-closure identity for functions), the structural
|
|
2314
|
+
* DOM walk for the deep pair, with assertion_error.js's messages —
|
|
2315
|
+
* scalar forms byte-exact, composites rendered compact:false/sorted
|
|
2316
|
+
* through the DOM and diffed with the real myers line printer.
|
|
2317
|
+
*
|
|
2318
|
+
* The assert.throws(fn, {name/code/message}) shape check
|
|
2319
|
+
* (expectedException over the static error surface): shapeBegin
|
|
2320
|
+
* stashes the caught error, shapeStr/shapeRe add one expected key each
|
|
2321
|
+
* (key ids 0 code / 1 message / 2 name; shapeRe lives in scr_regex.c —
|
|
2322
|
+
* its regex argument flips the regex link switch — and tests eagerly
|
|
2323
|
+
* so scr_assert.c stays libregexp-free), then shapeEnd throws Node's
|
|
2324
|
+
* deep-equal Comparison diff BYTE-EXACTLY (the bounded key set makes
|
|
2325
|
+
* the rendering enumerable) or the custom message.
|
|
2326
|
+
* assert.throwsRegex: (regex, error, msg, hasMsg) — the
|
|
2327
|
+
* assert.throws(fn, /re/) check over String(error), Node's
|
|
2328
|
+
* regex-mismatch message. assert.regexErrTest: doesNotReject's silent
|
|
2329
|
+
* regex predicate over String(error) (never throws).
|
|
2330
|
+
* assert.unwantedRejection: (error, msg, hasMsg) — doesNotReject's
|
|
2331
|
+
* "Got unwanted rejection" throw.
|
|
2332
|
+
* assert.ifErrorErr/F64/Str/Bool: assert.ifError's per-type throws
|
|
2333
|
+
* ("ifError got unwanted exception: " + the error's message/name or
|
|
2334
|
+
* the value's inspection) — the frontend routes null/undefined to a
|
|
2335
|
+
* no-op and everything else here (Node throws for falsy values too).
|
|
2336
|
+
* All arguments are borrowed. */
|
|
2337
|
+
| "assert.ok" | "assert.eqF64" | "assert.eqStr" | "assert.eqBool" | "assert.eqSym" | "assert.eqDyn" | "assert.deepResult" | "assert.sameValue" | "assert.match" | "assert.throwsNone" | "assert.throwsMismatch" | "assert.throwsRegex" | "assert.shapeBegin" | "assert.shapeStr" | "assert.shapeRe" | "assert.shapeEnd" | "assert.regexErrTest" | "assert.unwantedRejection"
|
|
2338
|
+
/** Node's expectsError over an error-INSTANCE expected (assert.throws/
|
|
2339
|
+
* rejects second argument): walk the expected DOM error's keys (name,
|
|
2340
|
+
* message, code — the %error marker skipped) and deep-compare each
|
|
2341
|
+
* against the caught value's; a mismatch throws the deep-equal
|
|
2342
|
+
* AssertionError (scr_assert.c). MAY THROW by design. */
|
|
2343
|
+
| "assert.expectsErrDyn" | "assert.ifErrorErr" | "assert.ifErrorF64" | "assert.ifErrorStr" | "assert.ifErrorBool" | "assert.ifErrorDyn" | "assert.refEqBytes" | "assert.refEqFn" | "assert.bytesDeepEq"
|
|
2344
|
+
/** util.inspect (scr_inspect.c — its own link switch, moduleUsesInspect):
|
|
2345
|
+
* the runtime half of the static rendering. Scalar formatters return +1
|
|
2346
|
+
* strings (insp.f64: JS ToString except -0; insp.str: the quoting
|
|
2347
|
+
* ladder + line splitting; insp.regex: /source/flags; insp.buffer:
|
|
2348
|
+
* <Buffer aa ..>). insp.error renders the STACKLESS [Name: message]
|
|
2349
|
+
* form with the code slot as its one property. insp.dyn walks the
|
|
2350
|
+
* checked-dynamic DOM entirely in the runtime (its shape lives in the
|
|
2351
|
+
* value); insp.dynS is format's %s twin (dyn strings pass verbatim).
|
|
2352
|
+
* insp.jsval ([value, recurse, depth], --dynamic only) renders the
|
|
2353
|
+
* island scalars and THROWS a catchable TypeError on composites (the
|
|
2354
|
+
* may-throw seed set). begin/entry/moreItems/end drive the frame
|
|
2355
|
+
* engine from the compiler-synthesized per-type traversal helpers
|
|
2356
|
+
* (%util.insp.N — the deepStrictEqual precedent). */
|
|
2357
|
+
| "insp.f64"
|
|
2358
|
+
/** util.format %j over a checked-dynamic argument: the runtime DOM
|
|
2359
|
+
* walk (JS-exact stringify; root undefined/function prints
|
|
2360
|
+
* "undefined"; a handle in the tree throws the loud fence). */
|
|
2361
|
+
| "insp.jsonDyn" | "insp.str" | "insp.regex" | "insp.buffer" | "insp.error" | "insp.dyn" | "insp.dynS" | "insp.jsval" | "insp.begin" | "insp.entry" | "insp.key" | "insp.moreItems" | "insp.end"
|
|
2362
|
+
/** node:string_decoder's utf8 StringDecoder (scr_string.c): the decoder
|
|
2363
|
+
* value is a one-field record whose f64 PACKS the pending partial
|
|
2364
|
+
* sequence (count + up to 3 raw bytes — Node buffers at most 3 for
|
|
2365
|
+
* every encoding); the frontend's interned %strdec helpers thread it,
|
|
2366
|
+
* with the decoder's CANONICAL encoding name first, through these pure
|
|
2367
|
+
* functions. write: (enc, pending, chunk) → the decoded complete
|
|
2368
|
+
* prefix of pending+chunk (+1); next: (enc, pending, chunk) → the
|
|
2369
|
+
* packed NEW pending; end: (enc, pending) → the buffered partial's
|
|
2370
|
+
* flush (+1). Node-exact per encoding (oracle-pinned); none throws. */
|
|
2371
|
+
| "strdec.write" | "strdec.next" | "strdec.end"
|
|
2372
|
+
/** node:readline's question/close slice (scr_readline.c, linked under
|
|
2373
|
+
* the events gate — these fns imply moduleUsesProcessEvents). The
|
|
2374
|
+
* interface value is an f64 handle (the Timeout-id precedent).
|
|
2375
|
+
* rl.create: [] → f64 — createInterface({ input: process.stdin,
|
|
2376
|
+
* output: process.stdout }), registering the unit's shared stdin
|
|
2377
|
+
* consumer (an OPEN interface keeps the loop alive until close/EOF,
|
|
2378
|
+
* Node's semantics). rl.question: [handle, query, cb] — writes the
|
|
2379
|
+
* query to stdout (Node writes under pipes too) and delivers the next
|
|
2380
|
+
* line's text through a backend-picked adapter (zero-param or
|
|
2381
|
+
* (answer: string)); THROWS Node's "readline was closed" on a closed
|
|
2382
|
+
* interface (may-throw). rl.close: [handle] — fires 'close' listeners
|
|
2383
|
+
* SYNCHRONOUSLY (Node's inline emit) and detaches the consumer (the
|
|
2384
|
+
* loop stops waiting on fd 0). rl.onClose: [handle, cb] — a zero-arg
|
|
2385
|
+
* listener (moves); stdin EOF closes every open interface with the
|
|
2386
|
+
* buffered partial line DISCARDED, like Node. */
|
|
2387
|
+
| "rl.create" | "rl.question" | "rl.close" | "rl.onClose"
|
|
2388
|
+
/** node:timers/promises — the promisified pair (scr_async.c, beside
|
|
2389
|
+
* the timer heap they ride): tp.setTimeout: [ms] → a pending void
|
|
2390
|
+
* promise a one-shot heap timer fulfills (the loop's timer phase, FIFO
|
|
2391
|
+
* against equal deadlines like Node); tp.setImmediate: [] → the same
|
|
2392
|
+
* through the immediate queue (fires before due timers of later loop
|
|
2393
|
+
* turns, Node's check phase). Neither throws. */
|
|
2394
|
+
| "tp.setTimeout" | "tp.setImmediate"
|
|
2395
|
+
/** node:diagnostics_channel (scr_dc.c, linked when any dc.* appears —
|
|
2396
|
+
* the zlib gating precedent): a process-global name→channel registry;
|
|
2397
|
+
* channel values are f64 handles (types.ts maps Channel to F64, the
|
|
2398
|
+
* readline.Interface pattern). Subscribers are DOM function values —
|
|
2399
|
+
* identity-compared by unsubscribe, called (message, name) by publish
|
|
2400
|
+
* over a SNAPSHOT of the list (a subscriber unsubscribing itself
|
|
2401
|
+
* mid-publish still lets its siblings fire, Node's behavior). dc.publish
|
|
2402
|
+
* MAY THROW: a subscriber's throw propagates out of publish (catchable
|
|
2403
|
+
* there) where Node routes it to triggerUncaughtException — the
|
|
2404
|
+
* documented divergence. subscribe/unsubscribe throw Node's
|
|
2405
|
+
* ERR_INVALID_ARG_TYPE TypeError for non-function subscribers. */
|
|
2406
|
+
| "dc.channel" | "dc.subscribe" | "dc.unsubscribe" | "dc.hasSubscribers" | "dc.publish" | "dc.chanSubscribe" | "dc.chanUnsubscribe" | "dc.chanHasSubscribers" | "dc.chanName"
|
|
2407
|
+
/** TracingChannel (dc.tracingChannel): a registry entry of the five
|
|
2408
|
+
* event channels, an f64 handle like Channel (types.ts). tcSubscribe/
|
|
2409
|
+
* tcUnsubscribe walk a DOM handlers object's five event keys (truthy
|
|
2410
|
+
* non-function slots throw the per-channel ERR_INVALID_ARG_TYPE);
|
|
2411
|
+
* tcTraceSync/tcTraceCallback/tcTracePromise run Node's publish choreography in C over
|
|
2412
|
+
* DOM values (fn, ctx, thisArg, args-array) with thisArg bound as the
|
|
2413
|
+
* ambient receiver — the traced call's throw and any subscriber throw
|
|
2414
|
+
* both propagate (MAY THROW). tcTraceCallback wraps args[position] in a
|
|
2415
|
+
* native error/result + asyncStart/asyncEnd publisher and throws Node's
|
|
2416
|
+
* TypeError when that slot is not callable. tracingChannelOf is the
|
|
2417
|
+
* five-Channel collection form of the constructor. */
|
|
2418
|
+
/** setImmediate as a first-class DOM value (scr_async.c): a minted dyn
|
|
2419
|
+
* callable scheduling args[0](args[1..]) on the immediate queue — the
|
|
2420
|
+
* Node-suite traceCallback shape (`traceCallback(setImmediate, ...)`).
|
|
2421
|
+
* Calling it validates the callback (the dyn call machinery); minting
|
|
2422
|
+
* never throws. */
|
|
2423
|
+
| "timers.setImmediateFnValue"
|
|
2424
|
+
/** `new Promise(setImmediate)` (the Node-suite early-exit shape): a
|
|
2425
|
+
* fresh promise an immediate fulfills with the undefined DOM value —
|
|
2426
|
+
* the executor IS setImmediate, so resolve rides the immediate queue
|
|
2427
|
+
* (scr_async.c). Never throws. */
|
|
2428
|
+
| "timers.immediatePromise" | "dc.tracingChannel" | "dc.tracingChannelOf" | "dc.tcChannel" | "dc.tcHasSubscribers" | "dc.tcSubscribe" | "dc.tcUnsubscribe" | "dc.tcTraceSync" | "dc.tcTraceCallback"
|
|
2429
|
+
/** tracePromise (scr_dc.c): start publish, the traced call, a wrap of
|
|
2430
|
+
* non-promise results, the end publish, and a REACTION FIBER that
|
|
2431
|
+
* awaits the traced promise and publishes asyncStart/asyncEnd (error
|
|
2432
|
+
* first on rejection) before settling the returned promise<dyn> with
|
|
2433
|
+
* the passed-through outcome. MAY THROW (the traced call and the
|
|
2434
|
+
* synchronous publishes). */
|
|
2435
|
+
| "dc.tcTracePromise"
|
|
2436
|
+
/** AsyncLocalStorage (node:async_hooks — scr_async.c): stores are f64
|
|
2437
|
+
* handles; contexts are immutable fiber-carried snapshots (spawned
|
|
2438
|
+
* fibers inherit the spawner's — Node's init-time capture). run/exit
|
|
2439
|
+
* enter (or clear) the store, call the DOM function with forwarded
|
|
2440
|
+
* arguments, and restore (the finally); getStore answers the current
|
|
2441
|
+
* DOM value or undefined; enterWith installs with no restore point.
|
|
2442
|
+
* run/exit MAY THROW (the callback's own throws propagate). */
|
|
2443
|
+
/** `await v` over a checked-dynamic VALUE (scr_async.c): a DOM promise
|
|
2444
|
+
* adopts (rejections re-throw — MAY THROW), anything else takes JS's
|
|
2445
|
+
* one-microtask non-thenable await and answers itself. Only emitted
|
|
2446
|
+
* inside async bodies (the frontend's isAsync gate). */
|
|
2447
|
+
| "async.awaitDyn"
|
|
2448
|
+
/** The bare one-microtask hop (scr_await_hop): `await v` over a typed
|
|
2449
|
+
* NON-promise value — JS awaits non-thenables through exactly one
|
|
2450
|
+
* microtask turn and yields the value itself. Never throws. */
|
|
2451
|
+
| "async.hop" | "als.new" | "als.get" | "als.run" | "als.exitRun" | "als.enterWith" | "als.disable"
|
|
2452
|
+
/** Channel.bindStore/unbindStore/runStores (scr_dc.c): the
|
|
2453
|
+
* AsyncLocalStorage integration — set-semantics bindings per store,
|
|
2454
|
+
* runStores entering every bound store with transform(data) around the
|
|
2455
|
+
* publish and the callback (MAY THROW: transforms, subscribers, and
|
|
2456
|
+
* the callback all run). */
|
|
2457
|
+
| "dc.chanBindStore" | "dc.chanUnbindStore" | "dc.chanRunStores"
|
|
2458
|
+
/** process warnings (scr_lib.c): onWarning/offWarning register DOM
|
|
2459
|
+
* listeners; emitWarning applies Node's full argument grammar over the
|
|
2460
|
+
* call's DOM argument vector (ERR_INVALID_ARG_TYPE TypeErrors — MAY
|
|
2461
|
+
* THROW; a listener throw propagates too) and always prints Node's
|
|
2462
|
+
* stderr report. Emission is synchronous (SEMANTICS.md). */
|
|
2463
|
+
| "process.onWarning" | "process.offWarning" | "process.emitWarning"
|
|
2464
|
+
/** process.on('unhandledRejection', fn): registers a DOM listener the
|
|
2465
|
+
* loop-end report dispatches per never-observed rejection — (reason,
|
|
2466
|
+
* promise) — instead of printing and exiting 1 (scr_async.c). Throws
|
|
2467
|
+
* Node's ERR_INVALID_ARG_TYPE on a non-function. */
|
|
2468
|
+
| "process.onUnhandledRejection"
|
|
2469
|
+
/** The Number statics with a static C implementation (scr_lib.c): one
|
|
2470
|
+
* f64 arg → bool, JS-exact BY CONSTRUCTION — Number.isFinite/isNaN/
|
|
2471
|
+
* isInteger/isSafeInteger never coerce, and the frontend routes only
|
|
2472
|
+
* f64-typed arguments here (other static types fence). None throws. */
|
|
2473
|
+
| "number.isFinite" | "number.isNaN" | "number.isInteger" | "number.isSafeInteger"
|
|
2474
|
+
/** Date, the composed slice (scr_lib.c). Date VALUES have no
|
|
2475
|
+
* representation — exactly `Date.now()` and the composed
|
|
2476
|
+
* `new Date(ms?).toISOString()` forms lower. date.now is Node's integer
|
|
2477
|
+
* milliseconds since epoch (never throws); date.toISOString formats one
|
|
2478
|
+
* f64 millisecond time value with Node's exact rules (UTC,
|
|
2479
|
+
* YYYY-MM-DDTHH:mm:ss.sssZ, expanded ±YYYYYY years outside 0–9999,
|
|
2480
|
+
* ToInteger truncation of fractional ms) and THROWS Node's "Invalid
|
|
2481
|
+
* time value" RangeError on NaN / out-of-range input (may-throw seed).
|
|
2482
|
+
* Results: f64 / owned (+1) string. */
|
|
2483
|
+
| "date.now" | "date.toISOString"
|
|
2484
|
+
/** The composed `new Date(dateString).getTime()` read: one borrowed
|
|
2485
|
+
* string, f64 milliseconds since epoch. The parsed grammar is BOUNDED
|
|
2486
|
+
* (documented divergence — V8's parser accepts far more): the ASN.1
|
|
2487
|
+
* validity shape X509Certificate.validFrom/validTo answer ("Jul 1
|
|
2488
|
+
* 00:00:00 2026 GMT" — the portless cert-expiry read), and ECMA's own
|
|
2489
|
+
* date-time string format (YYYY-MM-DD[THH:mm[:ss[.sss]]][Z|±HH:MM] —
|
|
2490
|
+
* date-only forms are UTC, exactly the spec). Anything else is NaN,
|
|
2491
|
+
* Node's invalid-date getTime. Never throws. */
|
|
2492
|
+
| "date.parseGetTime"
|
|
2493
|
+
/** `Date.UTC(...)` — seven f64 arguments (the frontend completes the
|
|
2494
|
+
* spec's defaults for omitted trailing parts: month 0, date 1, time
|
|
2495
|
+
* parts 0), the spec's MakeDay/MakeTime/TimeClip exactly: 0–99 years
|
|
2496
|
+
* map to 1900+year, out-of-range months/dates roll over, non-finite
|
|
2497
|
+
* parts and out-of-range results answer NaN. Never throws. */
|
|
2498
|
+
| "date.utc"
|
|
2499
|
+
/** The fs option forms and friends (scr_lib.c), all throwing catchably
|
|
2500
|
+
* like the rest of sync fs. mkdirRecursiveSync is Node's recursive
|
|
2501
|
+
* algorithm (try mkdir, EEXIST-dir is fine, ENOENT creates the parent
|
|
2502
|
+
* first — errors report Node's errno at Node's path, EEXIST at a file
|
|
2503
|
+
* target, ENOTDIR at the full path past a file); the first-created-dir
|
|
2504
|
+
* return value has no lowering (statement position only, frontend-
|
|
2505
|
+
* fenced). rmOptsSync is rmSync with (recursive, force) bools: force
|
|
2506
|
+
* swallows ENOENT, recursive removes trees post-order, a directory
|
|
2507
|
+
* without recursive throws the EISDIR-worded error (divergence 13's
|
|
2508
|
+
* wording note). mkdtempSync appends the six X's and returns the
|
|
2509
|
+
* created path (+1). accessSync takes the F_OK/R_OK/W_OK/X_OK bits as
|
|
2510
|
+
* one f64 (the frontend bakes fs.constants.* as literals and completes
|
|
2511
|
+
* an omitted mode to 0). readFdSync/readFdSyncBytes are the
|
|
2512
|
+
* readFileSync(fd[, "utf8"]) forms — a read(2) loop to EOF on the fd
|
|
2513
|
+
* (the stdin path); errors carry Node's no-path message shape. */
|
|
2514
|
+
| "fs.mkdirRecursiveSync" | "fs.rmOptsSync"
|
|
2515
|
+
/** rmOptsSync's maxRetries/retryDelay form (path, recursive, force,
|
|
2516
|
+
* maxRetries, retryDelay): Node's linear-backoff retry on
|
|
2517
|
+
* EBUSY/EMFILE/ENFILE/ENOTEMPTY/EPERM — the tmpdir-harness shape
|
|
2518
|
+
* rmSync(p, { maxRetries: 3, recursive: true, force: true }). */
|
|
2519
|
+
| "fs.rmRetrySync" | "fs.mkdtempSync" | "fs.accessSync" | "fs.readFdSync" | "fs.readFdSyncBytes"
|
|
2520
|
+
/** isatty(3) over an fd literal (0/1/2 — process.stdin/stdout/stderr
|
|
2521
|
+
* .isTTY reads). A real boolean: false where Node's non-TTY streams
|
|
2522
|
+
* expose undefined (documented divergence). Never throws. */
|
|
2523
|
+
| "process.isTTY"
|
|
2524
|
+
/** process.stdin.destroy(): a deliberate no-op (no stream machinery
|
|
2525
|
+
* exists to tear down; documented in SEMANTICS.md). */
|
|
2526
|
+
| "process.stdinDestroy"
|
|
2527
|
+
/** process.stdin.setRawMode(mode) — one borrowed bool arg, void. On a
|
|
2528
|
+
* TTY stdin: termios raw mode on/off (libuv's UV_TTY_MODE_RAW flag set,
|
|
2529
|
+
* the mode Node's setRawMode(true) applies; false restores the entry
|
|
2530
|
+
* state). On a NON-TTY stdin Node's process.stdin has no such method at
|
|
2531
|
+
* all, so the call throws Node's exact catchable TypeError
|
|
2532
|
+
* ("process.stdin.setRawMode is not a function") — the may-throw seed
|
|
2533
|
+
* carries it. */
|
|
2534
|
+
| "process.stdinSetRawMode"
|
|
2535
|
+
/** Terminal width over an fd literal (1/2 — process.stdout/stderr
|
|
2536
|
+
* .columns): ioctl(TIOCGWINSZ). The result is the module's interned
|
|
2537
|
+
* `number | undefined` union — a non-TTY stream (or an ioctl refusal)
|
|
2538
|
+
* yields the undefined arm, exactly Node's missing `.columns`. Never
|
|
2539
|
+
* throws. */
|
|
2540
|
+
| "process.columns"
|
|
2541
|
+
/** String surface with scr_lib.c implementations. fromCharCode takes
|
|
2542
|
+
* ONE f64[] arg (the frontend packs plain arguments into an array
|
|
2543
|
+
* literal, or forwards a whole-array spread — the path.join
|
|
2544
|
+
* convention) and builds the string from UTF-16 code units: each code
|
|
2545
|
+
* goes through ToUint16, adjacent surrogate pairs combine into one
|
|
2546
|
+
* code point, and LONE surrogates become U+FFFD (divergence 1's
|
|
2547
|
+
* storage policy — printed output still matches Node byte-for-byte).
|
|
2548
|
+
* lastIndexOf is the one-argument form: the LAST occurrence as a
|
|
2549
|
+
* UTF-16 index (-1 when absent; the empty needle finds the length,
|
|
2550
|
+
* per spec). Borrowed args; +1 string / plain f64; neither throws. */
|
|
2551
|
+
| "string.fromCharCode" | "string.lastIndexOf"
|
|
2552
|
+
/** String.raw(template, ...subs): the raw literals array (a string[]
|
|
2553
|
+
* read off the template record) interleaved with the PRE-STRINGIFIED
|
|
2554
|
+
* substitutions (the frontend applies the static ToString and packs
|
|
2555
|
+
* them into one string[] literal) — extra substitutions drop, missing
|
|
2556
|
+
* ones skip, the spec's loop exactly (scr_array.c). Borrowed args;
|
|
2557
|
+
* +1 string; never throws. */
|
|
2558
|
+
| "string.raw"
|
|
2559
|
+
/** WHATWG TextDecoder.decode over u8 bytes (scr_bytes.c): utf-8 with
|
|
2560
|
+
* default options — the same maximal-subpart replacement decode as
|
|
2561
|
+
* Buffer.toString("utf8"), with the leading BOM stripped (the one
|
|
2562
|
+
* behavioral difference; ignoreBOM defaults to false). Only the
|
|
2563
|
+
* COMPOSED `new TextDecoder().decode(bytes)` form lowers — decoder
|
|
2564
|
+
* values have no representation. TextEncoder.encode needs no libFn:
|
|
2565
|
+
* `new TextEncoder().encode(s)` lowers to buffer.fromStr(s, "utf8")
|
|
2566
|
+
* (identical bytes — ScrStr storage is well-formed UTF-8). Borrowed
|
|
2567
|
+
* arg; owned (+1) string; never throws. */
|
|
2568
|
+
| "text.decode"
|
|
2569
|
+
/** The wider sync fs slice (scr_lib.c), all throwing catchably with
|
|
2570
|
+
* Node's errno message shapes and `.code` stamped like the rest of
|
|
2571
|
+
* sync fs. unlink/chmod/chown wrap the syscalls 1:1 (Node reports the
|
|
2572
|
+
* syscall's own name). copyFileSync copies contents into a fresh (or
|
|
2573
|
+
* truncated) destination carrying the SOURCE's mode (libuv's
|
|
2574
|
+
* uv_fs_copyfile behavior); its errors carry BOTH paths — Node's
|
|
2575
|
+
* "copyfile 'src' -> 'dest'". lstatSync is statSync without following
|
|
2576
|
+
* a trailing symlink (Node reports lstat); stats.isSymbolicLink /
|
|
2577
|
+
* stats.mtimeMs are pure reads on the widened snapshot (mtimeMs is
|
|
2578
|
+
* milliseconds with the nanosecond fraction, Node's arithmetic).
|
|
2579
|
+
* writeFileModeSync is writeFileSync(path, data, { mode }): the mode
|
|
2580
|
+
* applies at CREATION only (open(2) with O_CREAT, umask applying),
|
|
2581
|
+
* exactly Node — an existing file keeps its permissions. mkdirModeSync
|
|
2582
|
+
* / mkdirRecursiveModeSync are the mkdirSync option forms with an
|
|
2583
|
+
* explicit mode (the recursive walk passes it to every directory it
|
|
2584
|
+
* creates, like Node's). */
|
|
2585
|
+
| "fs.unlinkSync" | "fs.chmodSync" | "fs.chownSync" | "fs.copyFileSync" | "fs.lstatSync"
|
|
2586
|
+
/** fs.openSync(path, flags) → the raw fd as f64, and fs.closeSync(fd)
|
|
2587
|
+
* — the pair behind spawn's fd-stdio form. flags is Node's string
|
|
2588
|
+
* grammar ("r", "w", "a" and the +/x variants; unknown flags throw
|
|
2589
|
+
* Node's ERR_INVALID_ARG_VALUE TypeError text). Both throw Node-shaped
|
|
2590
|
+
* fs errors (openSync ENOENT/EACCES..., closeSync EBADF). */
|
|
2591
|
+
| "fs.openSync" | "fs.readSync" | "fs.closeSync"
|
|
2592
|
+
/** fs.watch(path, listener?) → an FSWatcher handle (scr_watch.c —
|
|
2593
|
+
* linked, and scr_watch_install() emitted, only when these appear on
|
|
2594
|
+
* the IR; moduleUsesFsWatch is the switch). The path opens NOW —
|
|
2595
|
+
* failure throws Node's fs error synchronously ("ENOENT: ..., watch
|
|
2596
|
+
* 'x'", the polling-fallback catch shape) — and the unit's kqueue
|
|
2597
|
+
* (EVFILT_VNODE) delivers "rename"/"change" through the loop's watch
|
|
2598
|
+
* hook. The callback (nullable) MOVES in with an adapter per listener
|
|
2599
|
+
* shape (zero-param, or the (eventType: string) form — runtime-
|
|
2600
|
+
* provided); an open watcher keeps the loop alive until watcher.close()
|
|
2601
|
+
* (idempotent, receiver borrowed, statement position only). */
|
|
2602
|
+
| "fs.watch" | "fs.watchCb" | "watcher.close"
|
|
2603
|
+
/** The composed `new crypto.X509Certificate(data).fingerprint` read
|
|
2604
|
+
* (scr_lib.c — no certificate handle exists): the SHA-1 of the DER,
|
|
2605
|
+
* uppercase colon-separated, over PEM or raw-DER Buffer input; other
|
|
2606
|
+
* inputs throw Node's ERR_OSSL_PEM_NO_START_LINE Error (may-throw). */
|
|
2607
|
+
| "crypto.x509Fingerprint" | "crypto.x509FingerprintStr"
|
|
2608
|
+
/** The certificate's Validity window (validFrom / validTo reads —
|
|
2609
|
+
* scr_lib.c's minimal ASN.1 walk to the TBSCertificate validity
|
|
2610
|
+
* SEQUENCE): UTCTime and GeneralizedTime render in Node's exact
|
|
2611
|
+
* ASN1_TIME_print shape ("Jul 1 00:00:00 2026 GMT" — %2d space-padded
|
|
2612
|
+
* day). Same input contract and PEM error as the fingerprint pair
|
|
2613
|
+
* (may-throw). */
|
|
2614
|
+
| "crypto.x509ValidFrom" | "crypto.x509ValidFromStr" | "crypto.x509ValidTo" | "crypto.x509ValidToStr" | "stats.isSymbolicLink" | "stats.mtimeMs" | "fs.writeFileModeSync" | "fs.mkdirModeSync" | "fs.mkdirRecursiveModeSync"
|
|
2615
|
+
/** spawnSync with options (scr_child.c): the cp.spawnSync core plus the
|
|
2616
|
+
* option slice portless-class CLIs pass — timeout (killSignal fires at
|
|
2617
|
+
* the deadline and the result carries error: ETIMEDOUT + the signal,
|
|
2618
|
+
* Node's shape), killSignal (a signal NAME; "" = the SIGTERM default),
|
|
2619
|
+
* and per-fd stdio modes (in: 0 /dev/null, 1 ignore, 2 inherit; out/
|
|
2620
|
+
* err: 0 capture, 1 ignore → "", 2 inherit → ""). NEVER throws — spawn
|
|
2621
|
+
* failure and timeout are data on the result, like Node's error
|
|
2622
|
+
* property. spawnRes.signal is the result's termination signal as the
|
|
2623
|
+
* call site's `Signals | null` union (null = exited normally or spawn
|
|
2624
|
+
* failure), constructed type-directedly like spawnRes.status. */
|
|
2625
|
+
| "cp.spawnSyncOpts"
|
|
2626
|
+
/** cp.spawnSyncOpts with the stdio carried as a RUNTIME string —
|
|
2627
|
+
* "pipe" | "ignore" | "inherit", proven by the call site's TYPE (the
|
|
2628
|
+
* defaultRunner idiom `stdio: options?.stdio ?? "pipe"`); the runtime
|
|
2629
|
+
* maps the value to the three modes. Args (cmd, argv, timeout,
|
|
2630
|
+
* killSignal, stdio). Never throws, like the other spawnSync forms. */
|
|
2631
|
+
| "cp.spawnSyncStdioStr" | "spawnRes.signal"
|
|
2632
|
+
/** spawn with options (scr_child.c): the cp.spawn core plus PER-SLOT
|
|
2633
|
+
* stdio — args are (cmd, argv, inMode, outMode, errMode, outFd, errFd,
|
|
2634
|
+
* detached, hasEnv, envPairs, cwd); modes 0 ignore (/dev/null), 1
|
|
2635
|
+
* inherit, 2 fd (out/err only — the fd dup2s into the child's slot,
|
|
2636
|
+
* Node's stdio fd form; the daemon-log idiom ["ignore", logFd, logFd]).
|
|
2637
|
+
* detached is POSIX_SPAWN_SETSID (the child gets its own session and
|
|
2638
|
+
* process group, Node's semantics), env is a REPLACEMENT ([k,v,...]
|
|
2639
|
+
* pairs like cp.execSync's), cwd ""=inherit. Same event/loop story as
|
|
2640
|
+
* cp.spawn. */
|
|
2641
|
+
| "cp.spawnOpts"
|
|
2642
|
+
/** Atomics.wait(int32Array, idx, expected, timeoutMs) → "not-equal"
|
|
2643
|
+
* when the element differs from `expected`, else a real nanosleep for
|
|
2644
|
+
* the timeout and "timed-out" (scr_lib.c). scriptc has no threads —
|
|
2645
|
+
* no other agent can ever notify, so for every compilable program this
|
|
2646
|
+
* IS the spec's behavior, and "ok" is unreachable; the frontend
|
|
2647
|
+
* REQUIRES the timeout argument (an infinite wait here is a certain
|
|
2648
|
+
* deadlock, fenced). The SharedArrayBuffer the lib types demand exists
|
|
2649
|
+
* only syntactically (new Int32Array(new SharedArrayBuffer(n)) lowers
|
|
2650
|
+
* to a plain i32 typed array — sharing is unobservable without
|
|
2651
|
+
* threads; SEMANTICS.md documents the stance). Never throws; +1 string
|
|
2652
|
+
* result. */
|
|
2653
|
+
| "atomics.wait";
|
|
2654
|
+
/** Numeric binary ops. The bitwise six (`&`/`|`/`^`/`<<`/`>>`/`>>>`) have
|
|
2655
|
+
* JS ToInt32/ToUint32 semantics — operands convert (NaN/±Infinity → 0,
|
|
2656
|
+
* truncate, wrap mod 2^32), the operation runs in 32-bit space (shift
|
|
2657
|
+
* counts mask to 5 bits), and the result returns to f64 (`>>>` as Uint32,
|
|
2658
|
+
* the rest as Int32) — backends emit the scr_bit_* runtime helpers. */
|
|
2659
|
+
export type IrNumBinOp = "+" | "-" | "*" | "/" | "%" | "**" | "&" | "|" | "^" | "<<" | ">>" | ">>>" | "<" | "<=" | ">" | ">=" | "===" | "!==";
|
|
2660
|
+
export type IrStrCmpOp = "<" | "<=" | ">" | ">=";
|
|
2661
|
+
export type IrExpr = {
|
|
2662
|
+
kind: "numLit";
|
|
2663
|
+
value: number;
|
|
2664
|
+
type: IrType;
|
|
2665
|
+
loc: SrcLoc;
|
|
2666
|
+
} | {
|
|
2667
|
+
kind: "strLit";
|
|
2668
|
+
value: string;
|
|
2669
|
+
type: IrType;
|
|
2670
|
+
loc: SrcLoc;
|
|
2671
|
+
} | {
|
|
2672
|
+
kind: "boolLit";
|
|
2673
|
+
value: boolean;
|
|
2674
|
+
type: IrType;
|
|
2675
|
+
loc: SrcLoc;
|
|
2676
|
+
}
|
|
2677
|
+
/** An `undefined` or `null` literal; `type` is the matching unit kind.
|
|
2678
|
+
* Valid ONLY as the immediate value of a `unionWrap` (the frontend's slot
|
|
2679
|
+
* coercion wraps it with the unit arm's tag) — unit types have no
|
|
2680
|
+
* standalone runtime value, so a bare unitLit anywhere else is a
|
|
2681
|
+
* validator error and an emitter bug. */
|
|
2682
|
+
| {
|
|
2683
|
+
kind: "unitLit";
|
|
2684
|
+
unit: "undefined" | "null";
|
|
2685
|
+
type: IrType;
|
|
2686
|
+
loc: SrcLoc;
|
|
2687
|
+
} | {
|
|
2688
|
+
kind: "varRef";
|
|
2689
|
+
localId: string;
|
|
2690
|
+
type: IrType;
|
|
2691
|
+
loc: SrcLoc;
|
|
2692
|
+
}
|
|
2693
|
+
/** Numeric operands; comparisons yield bool. `===`/`!==` additionally
|
|
2694
|
+
* accept two same-typed arrays: reference identity (pointer compare),
|
|
2695
|
+
* matching JS object equality — and two same-typed CLASS VALUES, where
|
|
2696
|
+
* the pointer compare IS class identity (one immortal object per
|
|
2697
|
+
* class). */
|
|
2698
|
+
| {
|
|
2699
|
+
kind: "bin";
|
|
2700
|
+
op: IrNumBinOp;
|
|
2701
|
+
left: IrExpr;
|
|
2702
|
+
right: IrExpr;
|
|
2703
|
+
type: IrType;
|
|
2704
|
+
loc: SrcLoc;
|
|
2705
|
+
}
|
|
2706
|
+
/** `~` is JS bitwise NOT: ToInt32 the operand, complement, back to f64. */
|
|
2707
|
+
| {
|
|
2708
|
+
kind: "unary";
|
|
2709
|
+
op: "-" | "!" | "~";
|
|
2710
|
+
operand: IrExpr;
|
|
2711
|
+
type: IrType;
|
|
2712
|
+
loc: SrcLoc;
|
|
2713
|
+
}
|
|
2714
|
+
/** `x++` / `x--` / `++x` / `--x` in EXPRESSION position over an f64 local
|
|
2715
|
+
* or module global: reads the binding, writes the binding ±1, and yields
|
|
2716
|
+
* the OLD value (postfix, prefix=false) or the NEW value (prefix=true) —
|
|
2717
|
+
* JS-exact for typed-number receivers (no ToNumber coercion can be
|
|
2718
|
+
* observed). Statement-position ++/-- keeps its historic `assign`
|
|
2719
|
+
* desugar; this node exists for value positions (`arr[i++]`, `{ index:
|
|
2720
|
+
* jobIndex++ }`). Type is always f64. */
|
|
2721
|
+
| {
|
|
2722
|
+
kind: "incDec";
|
|
2723
|
+
op: "+" | "-";
|
|
2724
|
+
prefix: boolean;
|
|
2725
|
+
localId: string;
|
|
2726
|
+
type: IrType;
|
|
2727
|
+
loc: SrcLoc;
|
|
2728
|
+
}
|
|
2729
|
+
/** `--obj.f` / `obj.f++` in EXPRESSION position over a CLASS field: one
|
|
2730
|
+
* receiver evaluation, read-modify-write of the field, yielding the OLD
|
|
2731
|
+
* (postfix) or NEW (prefix) value — countdown.js's `if (--this.limit ===
|
|
2732
|
+
* 0)`. f64 fields compute in place (JS-exact); fieldDyn marks a
|
|
2733
|
+
* CHECKED-DYNAMIC field (a JS implicit-any ctor assignment): the number
|
|
2734
|
+
* validates OUT of the box (dynCheck's catchable TypeError on
|
|
2735
|
+
* non-numbers — the documented dyn arithmetic stance, never a silent
|
|
2736
|
+
* ToNumber), computes, and boxes back into the slot (old box released
|
|
2737
|
+
* after the unlink, like fieldSet). Type is always f64. */
|
|
2738
|
+
| {
|
|
2739
|
+
kind: "fieldIncDec";
|
|
2740
|
+
op: "+" | "-";
|
|
2741
|
+
prefix: boolean;
|
|
2742
|
+
obj: IrExpr;
|
|
2743
|
+
className: string;
|
|
2744
|
+
field: string;
|
|
2745
|
+
fieldDyn: boolean;
|
|
2746
|
+
type: IrType;
|
|
2747
|
+
loc: SrcLoc;
|
|
2748
|
+
}
|
|
2749
|
+
/** `x = e` in EXPRESSION position over a local or module global: evaluates
|
|
2750
|
+
* `value` once, writes the binding, and yields the assigned value — JS
|
|
2751
|
+
* evaluation order (`while ((idx = s.indexOf("\n")) !== -1)`). The type is
|
|
2752
|
+
* the binding's type (the frontend coerces the RHS into it, exactly like
|
|
2753
|
+
* statement-position `assign`). Statement position keeps the `assign`
|
|
2754
|
+
* statement; this node exists for value positions. */
|
|
2755
|
+
| {
|
|
2756
|
+
kind: "assignExpr";
|
|
2757
|
+
localId: string;
|
|
2758
|
+
value: IrExpr;
|
|
2759
|
+
type: IrType;
|
|
2760
|
+
loc: SrcLoc;
|
|
2761
|
+
}
|
|
2762
|
+
/** JS ToBoolean: f64 is false iff 0, -0, or NaN; string is false iff empty.
|
|
2763
|
+
* Operand is f64|string (bool needs no conversion) or a UNION — the ARM
|
|
2764
|
+
* value's ToBoolean via a per-union interned helper (unit arms false;
|
|
2765
|
+
* f64/string/bool arms per-value; ref arms — arrays, records, objects,
|
|
2766
|
+
* functions, maps, sets, promises, ... — always true; jsval arms ask the
|
|
2767
|
+
* engine). Result is bool. */
|
|
2768
|
+
| {
|
|
2769
|
+
kind: "toBool";
|
|
2770
|
+
operand: IrExpr;
|
|
2771
|
+
type: IrType;
|
|
2772
|
+
loc: SrcLoc;
|
|
2773
|
+
}
|
|
2774
|
+
/** Distinct from `bin`: short-circuits, and has JS value semantics — the
|
|
2775
|
+
* result is the deciding operand itself (`a && b` ≡ `toBool(a) ? b : a`),
|
|
2776
|
+
* not a bool. Operands and result share one kind: f64, string, bool, or
|
|
2777
|
+
* one UNION type (the deciding test is the union's per-arm ToBoolean; the
|
|
2778
|
+
* frontend pre-coerces plain arm operands into the union, so both sides
|
|
2779
|
+
* arrive union-typed). */
|
|
2780
|
+
| {
|
|
2781
|
+
kind: "logical";
|
|
2782
|
+
op: "&&" | "||";
|
|
2783
|
+
left: IrExpr;
|
|
2784
|
+
right: IrExpr;
|
|
2785
|
+
type: IrType;
|
|
2786
|
+
loc: SrcLoc;
|
|
2787
|
+
} | {
|
|
2788
|
+
kind: "strConcat";
|
|
2789
|
+
left: IrExpr;
|
|
2790
|
+
right: IrExpr;
|
|
2791
|
+
type: IrType;
|
|
2792
|
+
loc: SrcLoc;
|
|
2793
|
+
} | {
|
|
2794
|
+
kind: "strEq";
|
|
2795
|
+
negated: boolean;
|
|
2796
|
+
left: IrExpr;
|
|
2797
|
+
right: IrExpr;
|
|
2798
|
+
type: IrType;
|
|
2799
|
+
loc: SrcLoc;
|
|
2800
|
+
} | {
|
|
2801
|
+
kind: "strCmp";
|
|
2802
|
+
op: IrStrCmpOp;
|
|
2803
|
+
left: IrExpr;
|
|
2804
|
+
right: IrExpr;
|
|
2805
|
+
type: IrType;
|
|
2806
|
+
loc: SrcLoc;
|
|
2807
|
+
}
|
|
2808
|
+
/** f64|bool → string, JS-exact (Number::toString / "true"/"false").
|
|
2809
|
+
* Union operands dispatch through the per-union ToString helper (arms
|
|
2810
|
+
* fenced to unit/string/f64/bool by the frontend); a CAUGHT operand is
|
|
2811
|
+
* `String(e)` over the exception snapshot (scr_caught_to_string). */
|
|
2812
|
+
| {
|
|
2813
|
+
kind: "toString";
|
|
2814
|
+
operand: IrExpr;
|
|
2815
|
+
type: IrType;
|
|
2816
|
+
loc: SrcLoc;
|
|
2817
|
+
}
|
|
2818
|
+
/** Lazily-branched conditional: exactly one arm evaluates. */
|
|
2819
|
+
| {
|
|
2820
|
+
kind: "ternary";
|
|
2821
|
+
cond: IrExpr;
|
|
2822
|
+
then: IrExpr;
|
|
2823
|
+
else_: IrExpr;
|
|
2824
|
+
type: IrType;
|
|
2825
|
+
loc: SrcLoc;
|
|
2826
|
+
}
|
|
2827
|
+
/** Nullish coalescing `a ?? b` — `logical`'s lazily-branched shape with
|
|
2828
|
+
* the left's runtime TAG against its unit arms as the test instead of
|
|
2829
|
+
* ToBoolean (JS-exact: ONLY null/undefined take the right side — 0, "",
|
|
2830
|
+
* and false do not). `left` is a unit-armed union; `right` evaluates
|
|
2831
|
+
* lazily, only when the tag IS a unit arm, and has the node's type.
|
|
2832
|
+
* Exactly two result shapes exist (frontend-enforced, validated):
|
|
2833
|
+
* pass-through — `type` equals `left.type` and the non-unit left value is
|
|
2834
|
+
* the result box itself — and narrowed — the union has ONE non-unit arm,
|
|
2835
|
+
* `type` equals it, and the payload is extracted unionNarrow-style (+1
|
|
2836
|
+
* for ref kinds) under the checker's proof that the tag matches. Unions
|
|
2837
|
+
* with several non-unit arms narrowing to a sub-union are fenced. */
|
|
2838
|
+
| {
|
|
2839
|
+
kind: "nullish";
|
|
2840
|
+
left: IrExpr;
|
|
2841
|
+
right: IrExpr;
|
|
2842
|
+
type: IrType;
|
|
2843
|
+
loc: SrcLoc;
|
|
2844
|
+
}
|
|
2845
|
+
/** `u || d` where u is a union and the checker types the RESULT as u's
|
|
2846
|
+
* single non-unit arm (`value || null`-style picks resolved to a plain
|
|
2847
|
+
* default: `marker() || "default"`): evaluate u exactly ONCE, ToBoolean
|
|
2848
|
+
* of the ARM value (the per-union truthy helper — unit arms falsy,
|
|
2849
|
+
* ""/0/NaN/false falsy, object arms truthy), extract the arm when
|
|
2850
|
+
* truthy (+1 for ref kinds — the only truthy values live in that arm),
|
|
2851
|
+
* evaluate d lazily otherwise. JS value semantics exactly; `nullish`'s
|
|
2852
|
+
* sibling with truthiness in place of the unit-tag test. */
|
|
2853
|
+
| {
|
|
2854
|
+
kind: "orDefault";
|
|
2855
|
+
left: IrExpr;
|
|
2856
|
+
right: IrExpr;
|
|
2857
|
+
type: IrType;
|
|
2858
|
+
loc: SrcLoc;
|
|
2859
|
+
}
|
|
2860
|
+
/** Optional chaining `a?.b` / `a?.m(...)` / `f?.()` / `a?.[i]` — the
|
|
2861
|
+
* `nullish` test inverted: `receiver` is a unit-armed union with exactly
|
|
2862
|
+
* ONE non-unit arm, evaluated exactly once; when its runtime tag is a
|
|
2863
|
+
* unit arm the result is the interned undefined arm of `type` (JS-exact:
|
|
2864
|
+
* a null receiver still yields undefined) and `body` never evaluates —
|
|
2865
|
+
* argument side effects included. Otherwise the narrowed receiver binds
|
|
2866
|
+
* to `id` (read via chainRecv inside `body`, +1 per read for ref kinds)
|
|
2867
|
+
* and `body` produces the result: `type` when non-void (an
|
|
2868
|
+
* undefined-armed union; the frontend pre-wraps the member value into
|
|
2869
|
+
* it), or nothing (`type` void — the `cb?.()` statement form, where the
|
|
2870
|
+
* checker's `void | undefined` maps to void). */
|
|
2871
|
+
| {
|
|
2872
|
+
kind: "optChain";
|
|
2873
|
+
id: string;
|
|
2874
|
+
receiver: IrExpr;
|
|
2875
|
+
body: IrExpr;
|
|
2876
|
+
type: IrType;
|
|
2877
|
+
loc: SrcLoc;
|
|
2878
|
+
}
|
|
2879
|
+
/** The narrowed receiver inside an enclosing optChain's `body`, by the
|
|
2880
|
+
* chain's `id` — typed as the union's single non-unit arm; each read is
|
|
2881
|
+
* +1 for ref kinds (a borrowed bind temp backs it). Valid nowhere else
|
|
2882
|
+
* (validated against the active-chain stack). */
|
|
2883
|
+
| {
|
|
2884
|
+
kind: "chainRecv";
|
|
2885
|
+
id: string;
|
|
2886
|
+
type: IrType;
|
|
2887
|
+
loc: SrcLoc;
|
|
2888
|
+
}
|
|
2889
|
+
/** String method/property with UTF-16 (JS-exact) index semantics. Optional
|
|
2890
|
+
* arguments are OMITTED from `args` (never encoded as non-finite literals —
|
|
2891
|
+
* the IR must stay JSON-safe); backends fill the defaults: indexOf position
|
|
2892
|
+
* 0, slice start 0, slice end +Infinity. */
|
|
2893
|
+
| {
|
|
2894
|
+
kind: "strIntrinsic";
|
|
2895
|
+
method: IrStrIntrinsicMethod;
|
|
2896
|
+
receiver: IrExpr;
|
|
2897
|
+
args: IrExpr[];
|
|
2898
|
+
type: IrType;
|
|
2899
|
+
loc: SrcLoc;
|
|
2900
|
+
}
|
|
2901
|
+
/** A regex literal `/ab+c/gi`. `pattern` is the text between the slashes
|
|
2902
|
+
* exactly as written (escapes UNprocessed — the regex engine parses them),
|
|
2903
|
+
* `flags` the trailing flags in source order (alphabet fenced to gimsuy by
|
|
2904
|
+
* the frontend). Backends intern ONE immortal static per (pattern, flags)
|
|
2905
|
+
* pair — like string literals, so repeated evaluation is free and
|
|
2906
|
+
* `re === re` would hold — and compile the pattern lazily at first use
|
|
2907
|
+
* (a pattern the engine rejects aborts with a clear message; Node throws
|
|
2908
|
+
* SyntaxError at parse time — documented divergence). Result is +1 (a
|
|
2909
|
+
* no-op retain on the immortal). */
|
|
2910
|
+
| {
|
|
2911
|
+
kind: "regexLit";
|
|
2912
|
+
pattern: string;
|
|
2913
|
+
flags: string;
|
|
2914
|
+
type: IrType;
|
|
2915
|
+
loc: SrcLoc;
|
|
2916
|
+
}
|
|
2917
|
+
/** The strings object of a tagged template `tag\`a${x}b\`` — the COOKED
|
|
2918
|
+
* span texts. `key` is a per-SITE identity (the spec canonicalizes the
|
|
2919
|
+
* template object per template-literal occurrence, so two sites with
|
|
2920
|
+
* identical text are DISTINCT objects while one site evaluated twice is
|
|
2921
|
+
* the SAME object — the memoizing-tag idiom): backends intern ONE
|
|
2922
|
+
* immortal static string array per key, like regex literals. `type` is
|
|
2923
|
+
* always string[]. Result is +1 (a no-op retain on the immortal).
|
|
2924
|
+
* Divergences live at the frontend: the array is not frozen (a tag
|
|
2925
|
+
* mutating its readonly parameter would diverge — tsc rejects the
|
|
2926
|
+
* spelling) and `.raw` does not exist on it (reads fence by name;
|
|
2927
|
+
* String.raw itself lowers separately, splicing raw text directly). */
|
|
2928
|
+
| {
|
|
2929
|
+
kind: "templateStrings";
|
|
2930
|
+
key: string;
|
|
2931
|
+
cooked: string[];
|
|
2932
|
+
type: IrType;
|
|
2933
|
+
loc: SrcLoc;
|
|
2934
|
+
}
|
|
2935
|
+
/** A regex operation (see IrRegexIntrinsicMethod for the surface and the
|
|
2936
|
+
* receiver/arg conventions). The receiver and args are BORROWED;
|
|
2937
|
+
* string/array results are owned (+1). `replaceAll` and `split` MAY THROW
|
|
2938
|
+
* catchable TypeErrors (backends seed their may-throw analyses on them);
|
|
2939
|
+
* `test` on a g/y-flagged regex aborts at runtime (the frontend rejects
|
|
2940
|
+
* the literal-receiver cases it can see at compile time). */
|
|
2941
|
+
| {
|
|
2942
|
+
kind: "regexIntrinsic";
|
|
2943
|
+
method: IrRegexIntrinsicMethod;
|
|
2944
|
+
receiver: IrExpr;
|
|
2945
|
+
args: IrExpr[];
|
|
2946
|
+
type: IrType;
|
|
2947
|
+
loc: SrcLoc;
|
|
2948
|
+
}
|
|
2949
|
+
/** Array literal `[a, b, c]`, spreads included (`[...xs, b]`). `type` is
|
|
2950
|
+
* the array type; every element's type is `type.elem` EXCEPT positions
|
|
2951
|
+
* listed in `spreads`, whose expressions are same-typed ARRAYS copied
|
|
2952
|
+
* element-by-element at construction (JS-exact: a fresh array, source
|
|
2953
|
+
* untouched). Allocates; the result is owned (+1); ownership of
|
|
2954
|
+
* refcounted plain elements MOVES into the array, spread sources are
|
|
2955
|
+
* BORROWED (their elements copy in retained). */
|
|
2956
|
+
| {
|
|
2957
|
+
kind: "arrayLit";
|
|
2958
|
+
elems: IrExpr[];
|
|
2959
|
+
spreads?: number[];
|
|
2960
|
+
type: IrType;
|
|
2961
|
+
loc: SrcLoc;
|
|
2962
|
+
}
|
|
2963
|
+
/** Mapper-less `Array.from({ length: n })` — a length-n array of ABSENT
|
|
2964
|
+
* slots: unions carrying an undefined arm hold the interned undefined
|
|
2965
|
+
* instance (reads are JS-exact), every other refcounted element kind
|
|
2966
|
+
* holds NULL — a slot that MUST be assigned before it is read (the
|
|
2967
|
+
* pMap/allSettled fill-by-index pattern; reads of unassigned slots trap
|
|
2968
|
+
* where Node yields undefined — SEMANTICS.md 46). Scalar elements have
|
|
2969
|
+
* no absent value and are fenced by the frontend. The bound is ToLength
|
|
2970
|
+
* via the `i <= n - 1` loop form (fractions truncate; negative/NaN give
|
|
2971
|
+
* an empty array). Allocates; the result is owned (+1). */
|
|
2972
|
+
| {
|
|
2973
|
+
kind: "arrayNewLen";
|
|
2974
|
+
length: IrExpr;
|
|
2975
|
+
type: IrType;
|
|
2976
|
+
loc: SrcLoc;
|
|
2977
|
+
}
|
|
2978
|
+
/** Element read `a[i]`. Index is f64; a non-integer or out-of-bounds index
|
|
2979
|
+
* traps at runtime (JS returns undefined — documented divergence). For
|
|
2980
|
+
* refcounted elements the result is a fresh owned (+1) reference. */
|
|
2981
|
+
| {
|
|
2982
|
+
kind: "arrayGet";
|
|
2983
|
+
arr: IrExpr;
|
|
2984
|
+
index: IrExpr;
|
|
2985
|
+
type: IrType;
|
|
2986
|
+
loc: SrcLoc;
|
|
2987
|
+
}
|
|
2988
|
+
/** Array method/property on an array receiver: `length` (f64), `push`
|
|
2989
|
+
* (VARIADIC like JS — zero or more elem-typed args; every argument
|
|
2990
|
+
* evaluates before any appends, then each appends in order; returns the
|
|
2991
|
+
* new length as f64, the unchanged length for the zero-argument call —
|
|
2992
|
+
* ownership of refcounted args MOVES into the array), `pushSpread` (`a.push(...src)`:
|
|
2993
|
+
* one arg of the RECEIVER's own array type, BORROWED — its elements
|
|
2994
|
+
* append in order, count snapshotted first so `a.push(...a)` duplicates
|
|
2995
|
+
* exactly like JS; returns the new length), `pop` (returns elem — traps on an
|
|
2996
|
+
* empty array; ownership moves OUT to the caller), `indexOf` (one
|
|
2997
|
+
* elem-typed arg, BORROWED; strict equality — NaN never matches; → f64),
|
|
2998
|
+
* `includes` (one elem-typed arg, borrowed; SameValueZero — NaN DOES
|
|
2999
|
+
* match; → bool), `join` (one string arg, borrowed; f64/bool/string
|
|
3000
|
+
* elements only — validated; → owned string), `shift` (zero args; JS
|
|
3001
|
+
* shift exactly — undefined on an empty array, else the first element
|
|
3002
|
+
* out with the tail sliding down; the result type is the interned
|
|
3003
|
+
* `elem | undefined` union — union ELEMENTS are frontend-fenced, so the
|
|
3004
|
+
* arms never collide; ref ownership moves out into the box), and
|
|
3005
|
+
* `splice` (the REMOVAL forms only — one or two f64 args, Node's
|
|
3006
|
+
* relative/clamped start and clamped count, an omitted count removes to
|
|
3007
|
+
* the end [backends fill +Infinity, the slice convention]; the result is
|
|
3008
|
+
* a fresh +1 array of the removed elements IN ORDER, their ownership
|
|
3009
|
+
* MOVED from the receiver; insertion forms are frontend-fenced). */
|
|
3010
|
+
| {
|
|
3011
|
+
kind: "arrIntrinsic";
|
|
3012
|
+
method: IrArrIntrinsicMethod;
|
|
3013
|
+
receiver: IrExpr;
|
|
3014
|
+
args: IrExpr[];
|
|
3015
|
+
type: IrType;
|
|
3016
|
+
loc: SrcLoc;
|
|
3017
|
+
}
|
|
3018
|
+
/** Typed-array / Buffer construction — `new Uint8Array(x)`,
|
|
3019
|
+
* `Buffer.from(u8 | number[])`, `Buffer.alloc(n)`. `type` is the bytes
|
|
3020
|
+
* type; the SOURCE's static type picks the form:
|
|
3021
|
+
* - null — `new Uint8Array()`: a fresh zero-length buffer. Never throws.
|
|
3022
|
+
* - f64 — a zero-filled buffer of that length (ToIndex: NaN → 0,
|
|
3023
|
+
* truncate; a negative/huge result THROWS Node's "Invalid typed array
|
|
3024
|
+
* length" RangeError catchably — backends' may-throw analyses seed on
|
|
3025
|
+
* bytesNew with a non-bytes, non-array source).
|
|
3026
|
+
* - bytes (same elem — frontend-fenced) — an independent COPY. Never
|
|
3027
|
+
* throws.
|
|
3028
|
+
* - array of f64 — a per-element-coerced copy (ToUint8/ToUint32/float).
|
|
3029
|
+
* Never throws.
|
|
3030
|
+
* The source is BORROWED; the result is owned (+1). */
|
|
3031
|
+
| {
|
|
3032
|
+
kind: "bytesNew";
|
|
3033
|
+
source: IrExpr | null;
|
|
3034
|
+
type: IrType;
|
|
3035
|
+
loc: SrcLoc;
|
|
3036
|
+
}
|
|
3037
|
+
/** Typed-array/Buffer method or property on a bytes receiver — see
|
|
3038
|
+
* IrBytesIntrinsicMethod for the surface and conventions. Methods in
|
|
3039
|
+
* MAY_THROW_BYTES_METHODS raise catchable RangeErrors (may-throw
|
|
3040
|
+
* seeds); `get` traps on invalid indices instead (the array runtime's
|
|
3041
|
+
* discipline — never catchable). */
|
|
3042
|
+
| {
|
|
3043
|
+
kind: "bytesIntrinsic";
|
|
3044
|
+
method: IrBytesIntrinsicMethod;
|
|
3045
|
+
receiver: IrExpr;
|
|
3046
|
+
args: IrExpr[];
|
|
3047
|
+
type: IrType;
|
|
3048
|
+
loc: SrcLoc;
|
|
3049
|
+
}
|
|
3050
|
+
/** `new Map<K, V>()` — allocate an empty map. `type` is the map type
|
|
3051
|
+
* (key/value fences already enforced by the frontend); the result is
|
|
3052
|
+
* owned (+1). `seed` carries the entries of the SUPPORTED seeded form —
|
|
3053
|
+
* `new Map([[k, v], ...])`, an array literal of pair literals at the
|
|
3054
|
+
* construction site — lowered pairwise (each key K-typed, each value
|
|
3055
|
+
* V-typed, source order; a repeated key overwrites like set()). The
|
|
3056
|
+
* entries array itself never exists at runtime: backends construct the
|
|
3057
|
+
* empty map and set() each pair. Tuple-array VALUE seeds desugar in the
|
|
3058
|
+
* frontend to a construct-and-set loop (lowerMapSeedArrayNew) and never
|
|
3059
|
+
* reach this node; other argument shapes (iterables, another Map) stay
|
|
3060
|
+
* frontend-fenced. */
|
|
3061
|
+
| {
|
|
3062
|
+
kind: "mapNew";
|
|
3063
|
+
seed?: {
|
|
3064
|
+
key: IrExpr;
|
|
3065
|
+
value: IrExpr;
|
|
3066
|
+
}[];
|
|
3067
|
+
type: IrType;
|
|
3068
|
+
loc: SrcLoc;
|
|
3069
|
+
}
|
|
3070
|
+
/** Map method/property on a map receiver (`type` of the receiver is the
|
|
3071
|
+
* map; K/V below are its key/value types): `get` (one K arg, borrowed →
|
|
3072
|
+
* the interned `V | undefined` union, owned +1 — the undefined arm is the
|
|
3073
|
+
* miss; because `undefined` sorts LAST in canonical arm order, a union V
|
|
3074
|
+
* keeps its tags and the stored box IS the result), `set` (K borrowed,
|
|
3075
|
+
* V moves in; replacing releases the old value; → void — the ambient
|
|
3076
|
+
* declares void, not the JS `this`, so chaining is a type error), `has`
|
|
3077
|
+
* (K borrowed → bool, SameValueZero), `delete` (K borrowed → bool;
|
|
3078
|
+
* releases the entry), `size` (→ f64 live count), `clear` (→ void), and
|
|
3079
|
+
* the desugar-internal iteration primitives: `iterCount` (→ f64, dense
|
|
3080
|
+
* entries INCLUDING tombstones — re-read each pass so callback appends
|
|
3081
|
+
* are visited), `iterLive` (f64 index → bool), `iterKey` (f64 index → K,
|
|
3082
|
+
* +1 for strings), `iterValue` (f64 index → V, +1 for ref kinds),
|
|
3083
|
+
* `iterEnter`/`iterExit` (→ void, bracket a forEach loop: no compaction
|
|
3084
|
+
* while the depth is nonzero). The receiver is borrowed. */
|
|
3085
|
+
| {
|
|
3086
|
+
kind: "mapIntrinsic";
|
|
3087
|
+
method: IrMapIntrinsicMethod;
|
|
3088
|
+
receiver: IrExpr;
|
|
3089
|
+
args: IrExpr[];
|
|
3090
|
+
type: IrType;
|
|
3091
|
+
loc: SrcLoc;
|
|
3092
|
+
}
|
|
3093
|
+
/** `new Set<T>()` — allocate an empty set. `type` is the set type (the
|
|
3094
|
+
* element fence already enforced by the frontend); the result is owned
|
|
3095
|
+
* (+1). `seed` carries the SUPPORTED seeded form — `new Set(values)`
|
|
3096
|
+
* where values is any T[]-typed expression (literal or variable; T
|
|
3097
|
+
* already a legal element type) — one borrowed array whose elements
|
|
3098
|
+
* add() in order (duplicates collapse, first insertion position wins,
|
|
3099
|
+
* SameValueZero — exactly JS). Non-array seeds (another Set, general
|
|
3100
|
+
* iterables) stay frontend-fenced. */
|
|
3101
|
+
| {
|
|
3102
|
+
kind: "setNew";
|
|
3103
|
+
seed?: IrExpr;
|
|
3104
|
+
type: IrType;
|
|
3105
|
+
loc: SrcLoc;
|
|
3106
|
+
}
|
|
3107
|
+
/** Set method/property on a set receiver (`type` of the receiver is the
|
|
3108
|
+
* set; T below is its element type): `add` (one T arg, borrowed — the
|
|
3109
|
+
* runtime retains stored strings; → void, the JS `this` result is
|
|
3110
|
+
* frontend-fenced like Map set's chaining), `has`/`delete` (T borrowed →
|
|
3111
|
+
* bool, SameValueZero), `size` (→ f64 live count), `clear` (→ void), and
|
|
3112
|
+
* the desugar-internal iteration primitives with mapIntrinsic's exact
|
|
3113
|
+
* contract — `iterKey` reads the ELEMENT (f64 index → T, +1 for
|
|
3114
|
+
* strings); there is no iterValue. The receiver is borrowed. */
|
|
3115
|
+
| {
|
|
3116
|
+
kind: "setIntrinsic";
|
|
3117
|
+
method: IrSetIntrinsicMethod;
|
|
3118
|
+
receiver: IrExpr;
|
|
3119
|
+
args: IrExpr[];
|
|
3120
|
+
type: IrType;
|
|
3121
|
+
loc: SrcLoc;
|
|
3122
|
+
}
|
|
3123
|
+
/** Call of a user function declared in this module, by name. */
|
|
3124
|
+
| {
|
|
3125
|
+
kind: "call";
|
|
3126
|
+
callee: string;
|
|
3127
|
+
args: IrExpr[];
|
|
3128
|
+
type: IrType;
|
|
3129
|
+
loc: SrcLoc;
|
|
3130
|
+
}
|
|
3131
|
+
/** Closure creation: a function value over `fnName` (a module function),
|
|
3132
|
+
* capturing the listed boxed locals of the CREATING function (localIds,
|
|
3133
|
+
* in the callee's captures[] order). The result is owned (+1); the closure
|
|
3134
|
+
* itself retains each captured box. A reference to a top-level declared
|
|
3135
|
+
* function lowers to a zero-capture closure — backends must intern that
|
|
3136
|
+
* case so `f === f` is true (JS function identity). */
|
|
3137
|
+
| {
|
|
3138
|
+
kind: "closure";
|
|
3139
|
+
fnName: string;
|
|
3140
|
+
captures: string[];
|
|
3141
|
+
type: IrType;
|
|
3142
|
+
loc: SrcLoc;
|
|
3143
|
+
}
|
|
3144
|
+
/** Indirect call of a func-typed value. Args follow `call`'s convention
|
|
3145
|
+
* (callee owns its params, callers pass +1). The callee expression is an
|
|
3146
|
+
* ordinary owned temp, released at statement end. */
|
|
3147
|
+
| {
|
|
3148
|
+
kind: "callValue";
|
|
3149
|
+
callee: IrExpr;
|
|
3150
|
+
args: IrExpr[];
|
|
3151
|
+
type: IrType;
|
|
3152
|
+
loc: SrcLoc;
|
|
3153
|
+
}
|
|
3154
|
+
/** The currently-executing closure, as a value (+1). Valid only inside a
|
|
3155
|
+
* lifted function. Exists so a named nested function can recurse on itself
|
|
3156
|
+
* WITHOUT capturing its own binding — a box holding its own closure would
|
|
3157
|
+
* be a reference cycle, which naive RC can never free. */
|
|
3158
|
+
| {
|
|
3159
|
+
kind: "selfRef";
|
|
3160
|
+
type: IrType;
|
|
3161
|
+
loc: SrcLoc;
|
|
3162
|
+
}
|
|
3163
|
+
/** `yield e` — only inside generator functions (validated). Stores the
|
|
3164
|
+
* operand in the generator's out-slot (moved in, typed `yieldT`; null =
|
|
3165
|
+
* `yield;`, the undefined arm — the frontend guarantees yieldT admits
|
|
3166
|
+
* it) and switches back to the resumer; the expression's value is the
|
|
3167
|
+
* NEXT `.next(v)` argument (typed `nextT`, +1 for refcounted kinds).
|
|
3168
|
+
* MAY-THROW SEED: a consumer `.throw(e)` surfaces here as the pending
|
|
3169
|
+
* exception (catchable by the body's own try/catch), and `.return(v)`
|
|
3170
|
+
* as the GENRET sentinel — pending like an exception, it unwinds
|
|
3171
|
+
* through finally blocks but must NOT be taken by catch handlers
|
|
3172
|
+
* (backends emit a sentinel re-unwind prologue at catch entry inside
|
|
3173
|
+
* generator bodies; scr_exc_genret_pending answers it). */
|
|
3174
|
+
| {
|
|
3175
|
+
kind: "yieldExpr";
|
|
3176
|
+
value: IrExpr | null;
|
|
3177
|
+
type: IrType;
|
|
3178
|
+
loc: SrcLoc;
|
|
3179
|
+
}
|
|
3180
|
+
/** One consumer resume of a generator: `g.next(arg)`, `g.return(arg)`,
|
|
3181
|
+
* `g.throw(arg)`, and the for-of/yield* desugars. `gen` is a borrowed
|
|
3182
|
+
* generator-typed temp. `arg` is the sent value (moves in): next's
|
|
3183
|
+
* TNext (null = valueless resume — only when nextT is the undefined
|
|
3184
|
+
* unit or dyn), return's TReturn (null = `.return()`, the undefined
|
|
3185
|
+
* done-value), throw's payload (any throwable type — the throw
|
|
3186
|
+
* statement's operand contract). Result is the interned IteratorResult
|
|
3187
|
+
* record `{ done: bool, value: V }` (+1) where V is the canonical union
|
|
3188
|
+
* of yieldT, retT (when it carries a value), and undefined — collapsed
|
|
3189
|
+
* when one member survives. Semantics per mode on an UNSTARTED /
|
|
3190
|
+
* SUSPENDED / DONE generator: next runs the body to its next
|
|
3191
|
+
* suspension or completion / return completes without running the body
|
|
3192
|
+
* unless suspended (then the GENRET unwind runs finallys; a finally
|
|
3193
|
+
* yield answers done:false and parks the return value) / throw on a
|
|
3194
|
+
* non-suspended generator marks it done and re-throws at the call site.
|
|
3195
|
+
* MAY-THROW SEED: a body exception (or the injected throw) propagates
|
|
3196
|
+
* into the caller synchronously. */
|
|
3197
|
+
| {
|
|
3198
|
+
kind: "genResume";
|
|
3199
|
+
mode: "next" | "return" | "throw";
|
|
3200
|
+
gen: IrExpr;
|
|
3201
|
+
arg: IrExpr | null;
|
|
3202
|
+
type: IrType;
|
|
3203
|
+
loc: SrcLoc;
|
|
3204
|
+
}
|
|
3205
|
+
/** Await a promise: parks the current fiber until it settles; a rejected
|
|
3206
|
+
* promise re-throws into the awaiter (may-throw seed). Result is the
|
|
3207
|
+
* promise's inner value (+1 for refcounted kinds). Only inside async fns. */
|
|
3208
|
+
| {
|
|
3209
|
+
kind: "awaitExpr";
|
|
3210
|
+
value: IrExpr;
|
|
3211
|
+
type: IrType;
|
|
3212
|
+
loc: SrcLoc;
|
|
3213
|
+
}
|
|
3214
|
+
/** Await of a promise-or-absent union (`Promise<T> | undefined`, the
|
|
3215
|
+
* mapped `Promise<T> | void`): `value` is a union whose arm `promiseTag`
|
|
3216
|
+
* is a promise and whose other arms are all units. The promise arm awaits
|
|
3217
|
+
* like awaitExpr (parks, re-throws rejections — may-throw seed); a unit
|
|
3218
|
+
* arm takes exactly ONE microtask hop (JS: await of a non-thenable) and
|
|
3219
|
+
* yields itself. `type` is void when the promise's inner is void and the
|
|
3220
|
+
* only unit arm is undefined; otherwise the interned union of the inner
|
|
3221
|
+
* type and the unit arms (+1). Only inside async fns. */
|
|
3222
|
+
| {
|
|
3223
|
+
kind: "awaitUnionExpr";
|
|
3224
|
+
value: IrExpr;
|
|
3225
|
+
promiseTag: number;
|
|
3226
|
+
type: IrType;
|
|
3227
|
+
loc: SrcLoc;
|
|
3228
|
+
}
|
|
3229
|
+
/** `new Promise<T>((resolve) => ...)`: creates a pending promise and runs
|
|
3230
|
+
* the executor synchronously with a resolve closure; an executor throw
|
|
3231
|
+
* rejects the promise (JS-exact). Result +1. */
|
|
3232
|
+
| {
|
|
3233
|
+
kind: "newPromise";
|
|
3234
|
+
executor: IrExpr;
|
|
3235
|
+
type: IrType;
|
|
3236
|
+
loc: SrcLoc;
|
|
3237
|
+
}
|
|
3238
|
+
/** `Promise.withResolvers<T>()`: a pending promise plus its runtime
|
|
3239
|
+
* resolve/reject closures (the newPromise pieces without an executor),
|
|
3240
|
+
* assembled into the record `{ promise, resolve, reject }` — `type` is
|
|
3241
|
+
* that record; the shape's promise field carries T, resolve is
|
|
3242
|
+
* (T) => void (() => void for void T), reject is (%Error) => void.
|
|
3243
|
+
* Result +1; never throws. */
|
|
3244
|
+
| {
|
|
3245
|
+
kind: "promiseWithResolvers";
|
|
3246
|
+
type: IrType;
|
|
3247
|
+
loc: SrcLoc;
|
|
3248
|
+
}
|
|
3249
|
+
/** `new C(args)`: allocate (fields zeroed), then call `%C.constructor`
|
|
3250
|
+
* with the new object as arg 0 (retained — the ctor owns and releases its
|
|
3251
|
+
* `this` param like any callee). Result is owned (+1). */
|
|
3252
|
+
| {
|
|
3253
|
+
kind: "new";
|
|
3254
|
+
className: string;
|
|
3255
|
+
args: IrExpr[];
|
|
3256
|
+
type: IrType;
|
|
3257
|
+
loc: SrcLoc;
|
|
3258
|
+
}
|
|
3259
|
+
/** The class itself as a value: a pointer to `className`'s immortal
|
|
3260
|
+
* class object (type `classval:className`, +1 — a no-op retain on the
|
|
3261
|
+
* immortal, kept for the uniform owned-temp discipline, the regexLit
|
|
3262
|
+
* pattern). The frontend notes an edge to `%className.constructor` at
|
|
3263
|
+
* every classRef, so a value's construct thunk always has a constructor
|
|
3264
|
+
* to call; backends emit class objects (and thunks) for exactly the
|
|
3265
|
+
* classes some classRef in the module names. */
|
|
3266
|
+
| {
|
|
3267
|
+
kind: "classRef";
|
|
3268
|
+
className: string;
|
|
3269
|
+
type: IrType;
|
|
3270
|
+
loc: SrcLoc;
|
|
3271
|
+
}
|
|
3272
|
+
/** `new X(args)` through a class VALUE: call the class object's
|
|
3273
|
+
* construct thunk. `callee` is classval-typed; args are completed
|
|
3274
|
+
* against `%<callee.className>.constructor`'s ABI — sound because every
|
|
3275
|
+
* legal classval flow preserves the constructor ABI (the upcast rule) —
|
|
3276
|
+
* and follow `call`'s ownership (callee owns, +1 in). `type` is
|
|
3277
|
+
* `object:<callee.className>` (a runtime descendant rides the ordinary
|
|
3278
|
+
* upcast story); result owned (+1). May throw whenever constructors may
|
|
3279
|
+
* (backends treat it like an indirect call). */
|
|
3280
|
+
| {
|
|
3281
|
+
kind: "newValue";
|
|
3282
|
+
callee: IrExpr;
|
|
3283
|
+
args: IrExpr[];
|
|
3284
|
+
type: IrType;
|
|
3285
|
+
loc: SrcLoc;
|
|
3286
|
+
}
|
|
3287
|
+
/** `x instanceof X` with a DYNAMIC right-hand side (a classval-typed
|
|
3288
|
+
* value): the preorder-interval check with the interval loaded from the
|
|
3289
|
+
* class object — `vt(x)->pre` within `[X->pre, X->post]`. The frontend
|
|
3290
|
+
* emits this only when the operand's static class and the target
|
|
3291
|
+
* classval's class are both hierarchy members (the operand carries a
|
|
3292
|
+
* vt; a standalone target has exactly one possible runtime value and
|
|
3293
|
+
* folds statically instead). Operands borrowed; result bool. */
|
|
3294
|
+
| {
|
|
3295
|
+
kind: "instanceOfValue";
|
|
3296
|
+
value: IrExpr;
|
|
3297
|
+
classValue: IrExpr;
|
|
3298
|
+
type: IrType;
|
|
3299
|
+
loc: SrcLoc;
|
|
3300
|
+
}
|
|
3301
|
+
/** Implicit widening of a derived-class value into a base-class slot
|
|
3302
|
+
* (`type` is the base; the operand's class is a strict descendant).
|
|
3303
|
+
* Prefix layout makes this a pointer reinterpret: SAME object, no RC
|
|
3304
|
+
* traffic — ownership of the operand transfers to the result. Also
|
|
3305
|
+
* widens CLASS VALUES (`classval:D` into `classval:C`): the identical
|
|
3306
|
+
* pointer, type-only — legal exactly when D strictly descends from C
|
|
3307
|
+
* AND the two constructors' completed ABIs are equal (param-wise
|
|
3308
|
+
* typeEquals; validator-enforced), the invariant `newValue` completion
|
|
3309
|
+
* rests on. */
|
|
3310
|
+
| {
|
|
3311
|
+
kind: "upcast";
|
|
3312
|
+
value: IrExpr;
|
|
3313
|
+
type: IrType;
|
|
3314
|
+
loc: SrcLoc;
|
|
3315
|
+
}
|
|
3316
|
+
/** Implicit widening of a promise value into a VOID-promise slot (an
|
|
3317
|
+
* inferred Promise<never>/Promise<void> return whose body built a
|
|
3318
|
+
* concrete-inner promise — `return Promise.reject(value)` typed
|
|
3319
|
+
* promise<dyn>). One C representation (ScrPromise*), so this is a
|
|
3320
|
+
* type-only reinterpret: awaiting through the slot ignores the
|
|
3321
|
+
* fulfillment payload (scr_await_void) and rejections flow untyped.
|
|
3322
|
+
* Ownership of the operand transfers to the result, like upcast. */
|
|
3323
|
+
| {
|
|
3324
|
+
kind: "promiseVoidWiden";
|
|
3325
|
+
value: IrExpr;
|
|
3326
|
+
type: IrType;
|
|
3327
|
+
loc: SrcLoc;
|
|
3328
|
+
}
|
|
3329
|
+
/** Checker-trusted narrowing of a base-class value to a subclass (`type`
|
|
3330
|
+
* is the subclass). The frontend emits this only where tsc's control-flow
|
|
3331
|
+
* narrowing has already proven the dynamic class (an `instanceof` guard)
|
|
3332
|
+
* — the same trust-the-checker contract as unionNarrow: no runtime check,
|
|
3333
|
+
* a pointer reinterpret with ownership transferring like upcast. */
|
|
3334
|
+
| {
|
|
3335
|
+
kind: "downcast";
|
|
3336
|
+
value: IrExpr;
|
|
3337
|
+
type: IrType;
|
|
3338
|
+
loc: SrcLoc;
|
|
3339
|
+
}
|
|
3340
|
+
/** `x instanceof C` where x's static class and C are both in extends-
|
|
3341
|
+
* hierarchies: an O(1) preorder-interval check against the vtable the
|
|
3342
|
+
* value carries (`C.pre <= vt(x)->pre <= C.post`). Statically-decided
|
|
3343
|
+
* cases (standalone classes, and always-true/unrelated combinations)
|
|
3344
|
+
* never reach the IR — the frontend folds them. The operand is borrowed;
|
|
3345
|
+
* the result is a plain bool. */
|
|
3346
|
+
| {
|
|
3347
|
+
kind: "instanceOf";
|
|
3348
|
+
value: IrExpr;
|
|
3349
|
+
className: string;
|
|
3350
|
+
type: IrType;
|
|
3351
|
+
loc: SrcLoc;
|
|
3352
|
+
}
|
|
3353
|
+
/** Method call that must dispatch on the receiver's DYNAMIC class:
|
|
3354
|
+
* `className` is the receiver's static class, `args[0]` the receiver
|
|
3355
|
+
* (typed exactly `object:className`), and some strict subclass overrides
|
|
3356
|
+
* `method` — the backend calls through the vtable slot of the method's
|
|
3357
|
+
* root-most declaring class. Monomorphic calls (no override reachable
|
|
3358
|
+
* from the static class) stay ordinary `call` nodes — whole-program
|
|
3359
|
+
* devirtualization is the frontend's job. Ownership follows `call`:
|
|
3360
|
+
* callees own their params, callers pass +1. */
|
|
3361
|
+
| {
|
|
3362
|
+
kind: "virtualCall";
|
|
3363
|
+
className: string;
|
|
3364
|
+
method: string;
|
|
3365
|
+
args: IrExpr[];
|
|
3366
|
+
type: IrType;
|
|
3367
|
+
loc: SrcLoc;
|
|
3368
|
+
}
|
|
3369
|
+
/** Field read `obj.f`. Refcounted fields come out retained (+1). */
|
|
3370
|
+
| {
|
|
3371
|
+
kind: "fieldGet";
|
|
3372
|
+
obj: IrExpr;
|
|
3373
|
+
className: string;
|
|
3374
|
+
field: string;
|
|
3375
|
+
type: IrType;
|
|
3376
|
+
loc: SrcLoc;
|
|
3377
|
+
}
|
|
3378
|
+
/** Record literal `{ a: 1, b: "x" }`. `type` is the record type; `fields`
|
|
3379
|
+
* are in SOURCE order (JS evaluates property values in source order) and
|
|
3380
|
+
* cover the shape's fields exactly once each (validated — a source literal
|
|
3381
|
+
* omitting OPTIONAL fields reaches the IR already completed: the frontend
|
|
3382
|
+
* appends the wrapped undefined arm for each omitted one). Allocates
|
|
3383
|
+
* (fields zeroed) and returns owned (+1); ownership of refcounted field
|
|
3384
|
+
* values MOVES into the record. */
|
|
3385
|
+
/** Entries flagged `overflow` are UNDECLARED keys of an index-signature
|
|
3386
|
+
* shape (their values have the shape's indexValue type — dyn included);
|
|
3387
|
+
* they insert into the overflow map in list order, interleaved with the
|
|
3388
|
+
* declared writes (one list keeps JS source-order evaluation). */
|
|
3389
|
+
/** Entries flagged `drop` are fields the shape MAPPING dropped (the
|
|
3390
|
+
* PromiseSettledResult honest subset — SEMANTICS.md 46): the value
|
|
3391
|
+
* expression still evaluates in its source-order slot (the awaited
|
|
3392
|
+
* mapper in `{ status: "fulfilled", value: await fn(...) }` must run and
|
|
3393
|
+
* may throw), but nothing is stored — the emitter releases the result
|
|
3394
|
+
* with the statement frame. Any value type is legal here, void included
|
|
3395
|
+
* (an awaited Promise<void>). */
|
|
3396
|
+
| {
|
|
3397
|
+
kind: "recordLit";
|
|
3398
|
+
fields: {
|
|
3399
|
+
name: string;
|
|
3400
|
+
value: IrExpr;
|
|
3401
|
+
overflow?: true;
|
|
3402
|
+
drop?: true;
|
|
3403
|
+
}[];
|
|
3404
|
+
type: IrType;
|
|
3405
|
+
loc: SrcLoc;
|
|
3406
|
+
}
|
|
3407
|
+
/** Record field read `r.f` — mirrors `fieldGet`: refcounted fields come
|
|
3408
|
+
* out retained (+1). */
|
|
3409
|
+
| {
|
|
3410
|
+
kind: "recordGet";
|
|
3411
|
+
obj: IrExpr;
|
|
3412
|
+
shapeId: string;
|
|
3413
|
+
field: string;
|
|
3414
|
+
type: IrType;
|
|
3415
|
+
loc: SrcLoc;
|
|
3416
|
+
}
|
|
3417
|
+
/** Dynamic-keyed record read `r[k]` (string key, evaluated at runtime).
|
|
3418
|
+
* Declared fields are tried FIRST (an emitted string-switch — field
|
|
3419
|
+
* access exactness is preserved: a declared name always answers from the
|
|
3420
|
+
* struct slot), then the overflow map on index-signature shapes. `type`
|
|
3421
|
+
* is the CHECKER's type for the access: the index signature's value type
|
|
3422
|
+
* (dyn for `unknown`; with noUncheckedIndexedAccess, its
|
|
3423
|
+
* `V | undefined` union). A MISSING key produces: the undefined DOM
|
|
3424
|
+
* singleton when `type` is dyn; the undefined arm when `type` is an
|
|
3425
|
+
* undefined-armed union; otherwise a TRAP — the checker claimed V and no
|
|
3426
|
+
* undefined is representable (the array OOB policy; on declared-only
|
|
3427
|
+
* shapes tsc's keyof check makes the trap unreachable without an `as`
|
|
3428
|
+
* smuggle). Declared-field values surface as `type`: V-typed fields read
|
|
3429
|
+
* directly, dyn results build a DOM COPY of the field value (the dynFrom
|
|
3430
|
+
* conversion — deep for composites, documented), union results wrap.
|
|
3431
|
+
* The key and object are borrowed; refcounted results are owned (+1).
|
|
3432
|
+
* `overflowOnly` (set when the key is a LITERAL that names no declared
|
|
3433
|
+
* field): the read touches only the overflow map — declared fields need
|
|
3434
|
+
* not surface as `type`, and the emitted helper skips the string-switch. */
|
|
3435
|
+
| {
|
|
3436
|
+
kind: "recordKeyGet";
|
|
3437
|
+
obj: IrExpr;
|
|
3438
|
+
shapeId: string;
|
|
3439
|
+
key: IrExpr;
|
|
3440
|
+
overflowOnly?: true;
|
|
3441
|
+
type: IrType;
|
|
3442
|
+
loc: SrcLoc;
|
|
3443
|
+
}
|
|
3444
|
+
/** Static value → dyn DOM conversion (`type` is always dyn): the operand
|
|
3445
|
+
* (a JSON-safe type — f64/string/bool/record/array/union, validated)
|
|
3446
|
+
* converts to a fresh DOM tree, DEEP-COPYING composites (the jsMarshal
|
|
3447
|
+
* aliasing stance; a dyn value can never alias static storage). An
|
|
3448
|
+
* undefined-armed union's undefined arm becomes the undefined DOM
|
|
3449
|
+
* singleton. A FUNCTION operand (canBoxFuncIntoDyn — the mustCall shape:
|
|
3450
|
+
* a typed closure flowing into an untyped JS helper's implicit-any
|
|
3451
|
+
* param) BOXES instead of copying: the DOM's function kind carries the
|
|
3452
|
+
* retained closure, a compiled per-signature call thunk (per-argument
|
|
3453
|
+
* dynCheck into the declared param types, result dynFrom'd back — JS
|
|
3454
|
+
* arity: extras ignored, missing args are the undefined DOM value and
|
|
3455
|
+
* must satisfy the param's type or the thunk throws the catchable
|
|
3456
|
+
* TypeError), the interned signature key (dynCheck's exact-unwrap fast
|
|
3457
|
+
* path), and `fnName` — the best-effort static spelling for inspect
|
|
3458
|
+
* ([Function: name]) and Node-shaped call errors. The operand is
|
|
3459
|
+
* borrowed; the result is owned (+1). Never throws. */
|
|
3460
|
+
| {
|
|
3461
|
+
kind: "dynFrom";
|
|
3462
|
+
value: IrExpr;
|
|
3463
|
+
fnName?: string;
|
|
3464
|
+
type: IrType;
|
|
3465
|
+
loc: SrcLoc;
|
|
3466
|
+
}
|
|
3467
|
+
/** CALLING a dyn DOM value — `fn(a, b)` where fn is checked-dynamic (an
|
|
3468
|
+
* implicit-any JS binding, a dyn record member, a dynKeyGet result).
|
|
3469
|
+
* Arguments are ALREADY dyn-typed (typed values box through dynFrom at
|
|
3470
|
+
* the call's coercion — function args included); `type` is always dyn.
|
|
3471
|
+
* A non-function callee kind throws the catchable Node-shaped TypeError
|
|
3472
|
+
* "`calleeName` is not a function" BEFORE evaluating no arguments —
|
|
3473
|
+
* actually args evaluate first, source order, then the callee kind is
|
|
3474
|
+
* tested (JS evaluates callee before args, but the callee EXPRESSION
|
|
3475
|
+
* already evaluated; only the callability test is deferred — Node's
|
|
3476
|
+
* message exactly). A function callee calls through the boxed thunk:
|
|
3477
|
+
* per-arg validation against the boxed signature (mismatches throw the
|
|
3478
|
+
* path-annotated TypeError), result converted back to dyn. Callee and
|
|
3479
|
+
* args are borrowed; the result is owned (+1). MAY THROW. */
|
|
3480
|
+
| {
|
|
3481
|
+
kind: "dynCall";
|
|
3482
|
+
callee: IrExpr;
|
|
3483
|
+
calleeName: string;
|
|
3484
|
+
args: IrExpr[];
|
|
3485
|
+
type: IrType;
|
|
3486
|
+
loc: SrcLoc;
|
|
3487
|
+
}
|
|
3488
|
+
/** Prototype-method DISPATCH on a dyn receiver — `recv.m(...)` where `m`
|
|
3489
|
+
* is a name a DOM-representable prototype declares (Array/String/
|
|
3490
|
+
* Function shared names: push, slice, join, forEach, map, apply, ...),
|
|
3491
|
+
* so a stored-member read would silently mis-answer real methods. The
|
|
3492
|
+
* runtime (scr_dyn_invoke) dispatches on the receiver's KIND:
|
|
3493
|
+
* implemented (kind, name) pairs run JS-exact semantics; a real-but-
|
|
3494
|
+
* unimplemented method throws a LOUD "not supported yet" Error; a name
|
|
3495
|
+
* the kind's prototype lacks throws Node's catchable "<calleeName> is
|
|
3496
|
+
* not a function"; OBJ receivers call the own member (own properties
|
|
3497
|
+
* shadow prototypes in JS too); undefined/null receivers throw Node's
|
|
3498
|
+
* "Cannot read properties of ...". Arguments are already dyn.
|
|
3499
|
+
* `calleeName` is the source spelling for the error texts. Receiver and
|
|
3500
|
+
* args are borrowed; the result is owned (+1). MAY THROW. */
|
|
3501
|
+
| {
|
|
3502
|
+
kind: "dynInvoke";
|
|
3503
|
+
recv: IrExpr;
|
|
3504
|
+
method: string;
|
|
3505
|
+
calleeName: string;
|
|
3506
|
+
args: IrExpr[];
|
|
3507
|
+
type: IrType;
|
|
3508
|
+
loc: SrcLoc;
|
|
3509
|
+
}
|
|
3510
|
+
/** A DOM ARRAY built element-by-element (JS mixed-element literals —
|
|
3511
|
+
* `['pwd', []]` — and evolving `[]` declarations): each element is
|
|
3512
|
+
* already a dyn value; the result owns them. Never throws. */
|
|
3513
|
+
| {
|
|
3514
|
+
kind: "dynArrLit";
|
|
3515
|
+
elems: IrExpr[];
|
|
3516
|
+
type: IrType;
|
|
3517
|
+
loc: SrcLoc;
|
|
3518
|
+
}
|
|
3519
|
+
/** A DOM OBJECT built member-by-member. With no `fields` it is the empty
|
|
3520
|
+
* object (the JS stand-in for opaque container values — `new WeakMap()`
|
|
3521
|
+
* in harness code: the value exists for identity; every reached METHOD
|
|
3522
|
+
* use meets its own fence). With `fields` it is a JS object literal whose
|
|
3523
|
+
* keys are RUNTIME values (the computed-key idiom `{ [field]: criteria,
|
|
3524
|
+
* actual: 0 }` in test/common's _mustCallInner): each entry's key is a
|
|
3525
|
+
* string-typed expression (identifier/string keys lower to strLits;
|
|
3526
|
+
* computed keys evaluate their expression and pass through ToString —
|
|
3527
|
+
* JS's ToPropertyKey on the string side), each value is already dyn, and
|
|
3528
|
+
* entries evaluate key-then-value in SOURCE order (JS's object-literal
|
|
3529
|
+
* evaluation order; later duplicate keys win, insertion order preserved —
|
|
3530
|
+
* the DOM's own set semantics). Keys and values are borrowed (the member
|
|
3531
|
+
* retains the value in). Never throws itself. */
|
|
3532
|
+
| {
|
|
3533
|
+
kind: "dynObjLit";
|
|
3534
|
+
fields?: {
|
|
3535
|
+
key: IrExpr;
|
|
3536
|
+
value: IrExpr;
|
|
3537
|
+
}[];
|
|
3538
|
+
type: IrType;
|
|
3539
|
+
loc: SrcLoc;
|
|
3540
|
+
}
|
|
3541
|
+
/** Runtime kind test on a dyn DOM value — the narrowing tests tsc's
|
|
3542
|
+
* control flow understands on `unknown`: `typeof v === "string" |
|
|
3543
|
+
* "number" | "boolean" | "undefined"` and the unit comparisons `v ===
|
|
3544
|
+
* undefined` / `v === null` (`"nullish"` is the LOOSE `v == null` pair —
|
|
3545
|
+
* undefined or null in one test), and `v instanceof Uint8Array`
|
|
3546
|
+
* (`"bytes"` — the DOM's bytes kind; Node's Buffer IS a Uint8Array
|
|
3547
|
+
* subclass and both worlds answer true for it, SEMANTICS.md 45), plus
|
|
3548
|
+
* the two object-family tests: `"object"` is `typeof v === "object"`
|
|
3549
|
+
* exactly (true for the DOM's object, array, bytes, AND null kinds —
|
|
3550
|
+
* JS's oldest wart preserved), `"array"` is `Array.isArray(v)` (the
|
|
3551
|
+
* array kind alone), and `"truthy"` is ToBoolean over the whole DOM
|
|
3552
|
+
* (`if (v)` on unknown): undefined/null false, bool by value, number
|
|
3553
|
+
* falsy exactly for 0, -0, and NaN, string falsy exactly when empty,
|
|
3554
|
+
* object/array/bytes always true — JS-exact for every kind. A pure
|
|
3555
|
+
* kind-tag compare against the DOM node's kind (truthy also reads the
|
|
3556
|
+
* scalar payload); the operand is
|
|
3557
|
+
* borrowed, nothing allocates, never throws. Result is bool. Narrowed
|
|
3558
|
+
* READS afterwards bridge through `dynCheck` extraction
|
|
3559
|
+
* (trust-but-VERIFY: unlike unionNarrow, a read reached with a lying
|
|
3560
|
+
* kind throws instead of misreading the payload). `"error"` is
|
|
3561
|
+
* `v instanceof Error` on an unknown value: true exactly for the DOM's
|
|
3562
|
+
* error encoding — an object carrying the reserved "%error" key, the
|
|
3563
|
+
* shape caughtToDyn builds for Error payloads (SEMANTICS.md 67) — so a
|
|
3564
|
+
* caught Error passed through an unknown slot answers true like Node;
|
|
3565
|
+
* dynCheck against %Error extracts it. `"function"` is `typeof v ===
|
|
3566
|
+
* "function"` — true exactly for the DOM's function kind (boxed
|
|
3567
|
+
* closures); function values are truthy and answer FALSE to the
|
|
3568
|
+
* `"object"` test, JS-exact. */
|
|
3569
|
+
| {
|
|
3570
|
+
kind: "dynTest";
|
|
3571
|
+
test: "string" | "number" | "boolean" | "undefined" | "null" | "nullish" | "bytes" | "object" | "array" | "truthy" | "error" | "function";
|
|
3572
|
+
negated?: true;
|
|
3573
|
+
value: IrExpr;
|
|
3574
|
+
type: IrType;
|
|
3575
|
+
loc: SrcLoc;
|
|
3576
|
+
}
|
|
3577
|
+
/** Keyed read on a dyn DOM value — `pkg.name` / `pkg["k"]` / the
|
|
3578
|
+
* `pkg?.scripts` chain step on a JSON.parse result. `key` is
|
|
3579
|
+
* string-typed (a strLit for the dot form); `type` is always dyn. An
|
|
3580
|
+
* OBJ receiver answers the member (+1) or the undefined singleton (the
|
|
3581
|
+
* own-property answer — prototype members like `toString` answer
|
|
3582
|
+
* undefined, SEMANTICS.md); ARR answers `length` and canonical
|
|
3583
|
+
* in-range indices, STR answers `length` (UTF-16-exact), both
|
|
3584
|
+
* undefined otherwise; NUM/BOOL/BYTES answer undefined. An
|
|
3585
|
+
* undefined/null receiver THROWS the catchable Node-shaped TypeError
|
|
3586
|
+
* ("Cannot read properties of undefined (reading 'k')") — unless
|
|
3587
|
+
* `optional` is set (a `?.` step, or a later step of a chain whose
|
|
3588
|
+
* earlier `?.` guards it): then it answers the undefined singleton,
|
|
3589
|
+
* JS's short-circuit. Receiver and key are borrowed; the result is
|
|
3590
|
+
* owned (+1). */
|
|
3591
|
+
| {
|
|
3592
|
+
kind: "dynKeyGet";
|
|
3593
|
+
key: IrExpr;
|
|
3594
|
+
optional?: true;
|
|
3595
|
+
value: IrExpr;
|
|
3596
|
+
type: IrType;
|
|
3597
|
+
loc: SrcLoc;
|
|
3598
|
+
}
|
|
3599
|
+
/** `"k" in pkg` on a dyn DOM receiver (literal keys only): OBJ answers
|
|
3600
|
+
* own-member presence (a member holding the undefined value still
|
|
3601
|
+
* answers true — the DOM stores presence, unlike the record form's
|
|
3602
|
+
* SEMANTICS.md 55 stance), ARR answers true for "length" and canonical
|
|
3603
|
+
* in-range indices, everything else answers false (tsc admits `in`
|
|
3604
|
+
* only on object-typed operands, so unit receivers — where JS throws —
|
|
3605
|
+
* are checker-unreachable and answer false). Borrowed operand, no
|
|
3606
|
+
* allocation, never throws. Result is bool. */
|
|
3607
|
+
| {
|
|
3608
|
+
kind: "dynHasKey";
|
|
3609
|
+
key: string;
|
|
3610
|
+
negated?: true;
|
|
3611
|
+
value: IrExpr;
|
|
3612
|
+
type: IrType;
|
|
3613
|
+
loc: SrcLoc;
|
|
3614
|
+
}
|
|
3615
|
+
/** Strict equality between a dyn DOM value and a SCALAR-typed value
|
|
3616
|
+
* (`v !== ""`, `v === 5` — one side `unknown`, the other f64/string/
|
|
3617
|
+
* bool): a guarded kind test plus payload compare — true exactly when
|
|
3618
|
+
* the DOM holds that scalar kind AND the payloads are strictly equal
|
|
3619
|
+
* (C == for numbers: NaN false, ±0 equal — JS-exact; bytewise for
|
|
3620
|
+
* strings). `left`/`right` keep SOURCE order (evaluation order is
|
|
3621
|
+
* JS's); at least one side is dyn-typed — BOTH-dyn compares run the
|
|
3622
|
+
* runtime's whole-DOM strict equality (scr_dyn_strict_eq: scalars by
|
|
3623
|
+
* value, units by kind, reference kinds by node identity — JS-exact
|
|
3624
|
+
* within the DOM's aliasing story). Both operands are borrowed,
|
|
3625
|
+
* nothing allocates, never throws. Result is bool. */
|
|
3626
|
+
| {
|
|
3627
|
+
kind: "dynScalarEq";
|
|
3628
|
+
left: IrExpr;
|
|
3629
|
+
right: IrExpr;
|
|
3630
|
+
negated?: true;
|
|
3631
|
+
type: IrType;
|
|
3632
|
+
loc: SrcLoc;
|
|
3633
|
+
}
|
|
3634
|
+
/** Statements inside an expression: `stmts` run in order, then `result`
|
|
3635
|
+
* is the expression's value — the lift behind assignment-as-expression
|
|
3636
|
+
* forms whose statement lowering needs temps and writes (destructuring
|
|
3637
|
+
* assignments in value position, keyed dyn writes yielding the RHS).
|
|
3638
|
+
* `type` IS result's type. Restricted on purpose: stmts must be
|
|
3639
|
+
* straight-line (varDecl/assign/exprStmt/field-and-record writes — no
|
|
3640
|
+
* control flow, no jumps; the validator enforces the subset), and any
|
|
3641
|
+
* varDecl-introduced local is a function local like every hidden temp. */
|
|
3642
|
+
| {
|
|
3643
|
+
kind: "seqExpr";
|
|
3644
|
+
stmts: IrStmt[];
|
|
3645
|
+
result: IrExpr;
|
|
3646
|
+
type: IrType;
|
|
3647
|
+
loc: SrcLoc;
|
|
3648
|
+
}
|
|
3649
|
+
/** RequireObjectCoercible with V8's destructuring TypeError: throws
|
|
3650
|
+
* "Cannot destructure 'SPELLING' as it is undefined." (or "…null.") on
|
|
3651
|
+
* a nullish value — the property form "Cannot destructure property
|
|
3652
|
+
* 'FIRSTPROP' of 'SPELLING' …" when `firstProp` is set (V8 names the
|
|
3653
|
+
* pattern's first property) — and yields the value unchanged otherwise.
|
|
3654
|
+
* `spelling` is the RHS's compile-time source spelling. Value and type
|
|
3655
|
+
* are dyn (the DOM helper) or jsval (the island's prelude guard —
|
|
3656
|
+
* engine-thrown, catchable like every boundary throw). */
|
|
3657
|
+
| {
|
|
3658
|
+
kind: "dynDestrCheck";
|
|
3659
|
+
value: IrExpr;
|
|
3660
|
+
spelling: string;
|
|
3661
|
+
firstProp?: string;
|
|
3662
|
+
type: IrType;
|
|
3663
|
+
loc: SrcLoc;
|
|
3664
|
+
}
|
|
3665
|
+
/** GetIterator + the first `count` steps, as array destructuring sees
|
|
3666
|
+
* it. Over a DOM value: arrays step by index, strings by code point,
|
|
3667
|
+
* Buffers by byte; everything else throws V8's exact "<desc> is not
|
|
3668
|
+
* iterable (cannot read property Symbol(Symbol.iterator))" TypeError.
|
|
3669
|
+
* Over an island (jsval) value the engine runs the REAL iterator
|
|
3670
|
+
* protocol (user iterables included, IteratorClose per spec) behind the
|
|
3671
|
+
* same V8 message for non-iterables. The result is a FRESH array (DOM
|
|
3672
|
+
* or engine, matching the operand) of exactly `count` elements
|
|
3673
|
+
* (undefined-padded past the end) — the empty pattern passes count 0
|
|
3674
|
+
* and uses only the validation. Value is borrowed; the result is owned
|
|
3675
|
+
* (+1). */
|
|
3676
|
+
| {
|
|
3677
|
+
kind: "dynIterN";
|
|
3678
|
+
value: IrExpr;
|
|
3679
|
+
count: number;
|
|
3680
|
+
type: IrType;
|
|
3681
|
+
loc: SrcLoc;
|
|
3682
|
+
}
|
|
3683
|
+
/** The OVERFLOW key list of an index-signature record, in JS OWN-KEY
|
|
3684
|
+
* order (canonical array indices ascending first, then insertion order —
|
|
3685
|
+
* the runtime's scr_map_keys_js_order): a fresh string[] snapshot, the
|
|
3686
|
+
* iteration surface behind Object.keys/values/entries over hybrid
|
|
3687
|
+
* shapes. `obj` must be a record whose shape carries an indexValue; the
|
|
3688
|
+
* receiver is borrowed, the array is owned (+1). Declared fields are NOT
|
|
3689
|
+
* listed (they never live in the overflow map — the lowering prepends
|
|
3690
|
+
* them from the shape). Never throws. */
|
|
3691
|
+
| {
|
|
3692
|
+
kind: "recordOvfKeys";
|
|
3693
|
+
obj: IrExpr;
|
|
3694
|
+
shapeId: string;
|
|
3695
|
+
type: IrType;
|
|
3696
|
+
loc: SrcLoc;
|
|
3697
|
+
}
|
|
3698
|
+
/** Union construction: wrap an arm value into a fresh tagged box (the
|
|
3699
|
+
* frontend inserts these wherever a `B` flows into an `A | B` slot).
|
|
3700
|
+
* `tag` is the arm's index in the union's canonical arm list; `value` has
|
|
3701
|
+
* exactly that arm's type; `type` is the union. Allocates, returns owned
|
|
3702
|
+
* (+1); ownership of a refcounted payload MOVES into the union. Unions are
|
|
3703
|
+
* immutable once constructed. */
|
|
3704
|
+
| {
|
|
3705
|
+
kind: "unionWrap";
|
|
3706
|
+
unionId: string;
|
|
3707
|
+
tag: number;
|
|
3708
|
+
value: IrExpr;
|
|
3709
|
+
type: IrType;
|
|
3710
|
+
loc: SrcLoc;
|
|
3711
|
+
}
|
|
3712
|
+
/** Runtime test on a catch binding (`value` is a caught-typed varRef,
|
|
3713
|
+
* borrowed). The primitive tests ("string"/"number"/"boolean") compare
|
|
3714
|
+
* the snapshot's kind tag — exactly what `typeof e === "..."` observes;
|
|
3715
|
+
* "instanceof" requires `className` (a hierarchy class) and tests an OBJ
|
|
3716
|
+
* payload's vtable preorder against its interval (false for every other
|
|
3717
|
+
* payload kind). `negated` flips the result (the `!==` spelling). */
|
|
3718
|
+
| {
|
|
3719
|
+
kind: "caughtTest";
|
|
3720
|
+
value: IrExpr;
|
|
3721
|
+
test: "string" | "number" | "boolean" | "instanceof";
|
|
3722
|
+
className?: string;
|
|
3723
|
+
negated?: boolean;
|
|
3724
|
+
type: IrType;
|
|
3725
|
+
loc: SrcLoc;
|
|
3726
|
+
}
|
|
3727
|
+
/** Checker-trusted extraction of a catch binding's payload as `type` —
|
|
3728
|
+
* the caught analog of unionNarrow: the frontend emits this only where
|
|
3729
|
+
* tsc's control-flow narrowing has already proven the matching test
|
|
3730
|
+
* (`e instanceof C` / `typeof e === "string"`), so the read is
|
|
3731
|
+
* kind-UNCHECKED at runtime. `type` is f64, bool, string, or a
|
|
3732
|
+
* hierarchy-class object; refcounted results come out retained (+1). */
|
|
3733
|
+
| {
|
|
3734
|
+
kind: "caughtNarrow";
|
|
3735
|
+
value: IrExpr;
|
|
3736
|
+
type: IrType;
|
|
3737
|
+
loc: SrcLoc;
|
|
3738
|
+
}
|
|
3739
|
+
/** CHECKED extraction of a catch binding's payload as a hierarchy-class
|
|
3740
|
+
* instance — the caught analog of dynCheck, emitted for `e as C` casts
|
|
3741
|
+
* on catch bindings (the `(err as Error).message` idiom): an OBJ payload
|
|
3742
|
+
* inside C's preorder interval extracts (+1); every other payload THROWS
|
|
3743
|
+
* a catchable TypeError naming the class. Node's `as` is erasure — the
|
|
3744
|
+
* checked cast is the documented trust-but-verify stance for dynamic
|
|
3745
|
+
* values, extended to exception payloads. `type` is C's object type;
|
|
3746
|
+
* may-throw seeds like dynCheck. */
|
|
3747
|
+
| {
|
|
3748
|
+
kind: "caughtCheck";
|
|
3749
|
+
value: IrExpr;
|
|
3750
|
+
className: string;
|
|
3751
|
+
type: IrType;
|
|
3752
|
+
loc: SrcLoc;
|
|
3753
|
+
}
|
|
3754
|
+
/** A catch binding flowing into an `unknown` slot (`options.onError?.(e)`
|
|
3755
|
+
* — the caught snapshot converting to a dyn DOM value, the typed→unknown
|
|
3756
|
+
* deep-copy stance extended to exception payloads, SEMANTICS.md 67).
|
|
3757
|
+
* Runtime dispatch on the snapshot's kind: string/number/boolean payloads
|
|
3758
|
+
* become the exact DOM scalars; an Error-family OBJ payload becomes the
|
|
3759
|
+
* DOM's error encoding — an object with the reserved "%error" marker key
|
|
3760
|
+
* plus "name"/"message" (and "code" when stamped), so `instanceof Error`
|
|
3761
|
+
* (dynTest "error"), the %Error dynCheck extraction, and String() answer
|
|
3762
|
+
* like Node; every other payload (records, arrays, closures, unions,
|
|
3763
|
+
* non-Error hierarchy objects — type-erased at runtime) becomes an EMPTY
|
|
3764
|
+
* DOM object: truthy, typeof "object", fields unreadable — the
|
|
3765
|
+
* "[object Object]" approximation, documented. `value` is a caught-typed
|
|
3766
|
+
* varRef (borrowed); `type` is dyn; the result is a fresh tree (+1),
|
|
3767
|
+
* never aliasing the payload. Never throws. */
|
|
3768
|
+
| {
|
|
3769
|
+
kind: "caughtToDyn";
|
|
3770
|
+
value: IrExpr;
|
|
3771
|
+
type: IrType;
|
|
3772
|
+
loc: SrcLoc;
|
|
3773
|
+
}
|
|
3774
|
+
/** Union payload extraction, tag-UNCHECKED: `value` is union-typed,
|
|
3775
|
+
* `type` is arms[tag], and the backend reads the payload assuming the tag
|
|
3776
|
+
* — SOUNDNESS RESTS ON tsc's control-flow narrowing (the frontend emits
|
|
3777
|
+
* this only where the checker has already narrowed the expression to that
|
|
3778
|
+
* arm; see docs/ir.md). Refcounted payloads come out retained (+1). */
|
|
3779
|
+
| {
|
|
3780
|
+
kind: "unionNarrow";
|
|
3781
|
+
unionId: string;
|
|
3782
|
+
tag: number;
|
|
3783
|
+
value: IrExpr;
|
|
3784
|
+
type: IrType;
|
|
3785
|
+
loc: SrcLoc;
|
|
3786
|
+
}
|
|
3787
|
+
/** Discriminant read `r.kind` on a union receiver: every arm is a
|
|
3788
|
+
* record/class possessing field `field` with the SAME primitive IR type
|
|
3789
|
+
* (f64|string|bool — `type`). Backends switch on the runtime tag and read
|
|
3790
|
+
* the field from the concretely-typed payload; string results come out
|
|
3791
|
+
* retained (+1). Composes with existing `strEq`/`bin`/`switch` nodes for
|
|
3792
|
+
* the narrowing tests themselves. */
|
|
3793
|
+
| {
|
|
3794
|
+
kind: "unionDisc";
|
|
3795
|
+
unionId: string;
|
|
3796
|
+
field: string;
|
|
3797
|
+
value: IrExpr;
|
|
3798
|
+
type: IrType;
|
|
3799
|
+
loc: SrcLoc;
|
|
3800
|
+
}
|
|
3801
|
+
/** Keyed read `r.f` / `r[k]` on a union receiver whose arms answer
|
|
3802
|
+
* DIFFERENT (but joinable) types — the unionDisc generalization for
|
|
3803
|
+
* index-signature and optional-chain shapes (`env.PORTLESS_PORT` on
|
|
3804
|
+
* `ProcessEnv | Record<string, string>`, the tail read of
|
|
3805
|
+
* `loaded?.config.script`). `key` is a string-typed expression (a strLit
|
|
3806
|
+
* for dot access), evaluated ONCE before the tag switch. `type` is the
|
|
3807
|
+
* JOIN of the per-arm answers (each arm's declared answer is `type`
|
|
3808
|
+
* itself or one of its arms). Per arm, the backend answers: a record arm
|
|
3809
|
+
* with the key as a DECLARED field (literal keys only) reads the slot
|
|
3810
|
+
* and wraps into `type` when needed; a record arm with an index
|
|
3811
|
+
* signature goes through the per-(shape, type) keyed-read helper (the
|
|
3812
|
+
* recordKeyGet machinery — missing keys yield the undefined arm of
|
|
3813
|
+
* `type`, or trap when `type` has none, the same policy as the
|
|
3814
|
+
* single-record read); a UNIT arm (undefined/null — reachable only
|
|
3815
|
+
* through optional-chain tails, where JS answers undefined) yields the
|
|
3816
|
+
* interned undefined arm of `type`. The receiver and key are borrowed;
|
|
3817
|
+
* refcounted results are owned (+1). Never throws (a smuggled miss
|
|
3818
|
+
* traps in the helper). */
|
|
3819
|
+
| {
|
|
3820
|
+
kind: "unionKeyGet";
|
|
3821
|
+
unionId: string;
|
|
3822
|
+
key: IrExpr;
|
|
3823
|
+
value: IrExpr;
|
|
3824
|
+
type: IrType;
|
|
3825
|
+
loc: SrcLoc;
|
|
3826
|
+
}
|
|
3827
|
+
/** Union tag test: true iff `value`'s runtime tag equals `tag` (negated:
|
|
3828
|
+
* differs). The narrowing test for UNIT arms — the frontend lowers
|
|
3829
|
+
* `v === undefined` / `v !== null` on a union-typed v here (tsc's
|
|
3830
|
+
* control-flow narrowing then types the branches, and reads inside them
|
|
3831
|
+
* bridge via unionNarrow as usual). Composes like unionDisc: the result
|
|
3832
|
+
* is a plain bool for if/while/ternary/! to consume. The union operand is
|
|
3833
|
+
* an ordinary borrowed temp; no ownership changes. */
|
|
3834
|
+
| {
|
|
3835
|
+
kind: "unionIsTag";
|
|
3836
|
+
unionId: string;
|
|
3837
|
+
tag: number;
|
|
3838
|
+
negated: boolean;
|
|
3839
|
+
value: IrExpr;
|
|
3840
|
+
type: IrType;
|
|
3841
|
+
loc: SrcLoc;
|
|
3842
|
+
}
|
|
3843
|
+
/** `===`/`!==` between two values of the SAME union: JS-exact strict
|
|
3844
|
+
* equality of the ARM values via a per-union interned helper — different
|
|
3845
|
+
* tags are never equal (distinct types, and null !== undefined), unit
|
|
3846
|
+
* arms of equal tag are equal, f64 arms compare with C `==` (NaN !== NaN,
|
|
3847
|
+
* +0 === -0), string arms compare bytes, bool arms compare values, and
|
|
3848
|
+
* ref arms (arrays, records, objects, functions, maps, sets, ...) compare
|
|
3849
|
+
* POINTER IDENTITY — exactly JS object equality. A union-vs-plain-arm
|
|
3850
|
+
* comparison (`u === "text"`) arrives here after the frontend wraps the
|
|
3851
|
+
* plain side (payload identity is preserved by the wrap, so ref-arm
|
|
3852
|
+
* semantics stay JS-exact). Operands are borrowed; result is a plain
|
|
3853
|
+
* bool. `negated` is the `!==` spelling. */
|
|
3854
|
+
| {
|
|
3855
|
+
kind: "unionEq";
|
|
3856
|
+
unionId: string;
|
|
3857
|
+
negated: boolean;
|
|
3858
|
+
left: IrExpr;
|
|
3859
|
+
right: IrExpr;
|
|
3860
|
+
type: IrType;
|
|
3861
|
+
loc: SrcLoc;
|
|
3862
|
+
}
|
|
3863
|
+
/** Backend-special-cased operations. console.log: f64/string/bool args,
|
|
3864
|
+
* void. console.error (console.warn lowers here too — Node's warn IS
|
|
3865
|
+
* error): the same args and formatting, written to STDERR; stdout
|
|
3866
|
+
* flushes first so merged (2>&1) output keeps source order.
|
|
3867
|
+
* promise.race: every arg is a PROMISE (the array literal's
|
|
3868
|
+
* entries, lowered individually — the array never materializes), the
|
|
3869
|
+
* type is the checker's combined result promise; the backend emits a
|
|
3870
|
+
* fresh promise plus one scr_promise_race_add per entry with an
|
|
3871
|
+
* interned per-(entry-inner → result-inner) adapter (raceAdapterFor) —
|
|
3872
|
+
* same-type entries share the runtime's copy adapter, arm entries wrap
|
|
3873
|
+
* into the result union, sub-union entries re-tag arm-wise. First
|
|
3874
|
+
* settle wins; rejections copy raw and count handled on the entry.
|
|
3875
|
+
* promise.reject: one %Error-rooted arg (the reason — rejection
|
|
3876
|
+
* payloads share the thrown-Error representation), type is the
|
|
3877
|
+
* context-named result promise; the backend mints a fresh promise and
|
|
3878
|
+
* rejects it through the exception cell (scr_throw_obj +
|
|
3879
|
+
* scr_promise_reject_pending), so the result enters the unhandled
|
|
3880
|
+
* ledger until observed, exactly like a reject() call.
|
|
3881
|
+
* promise.resolve: zero args (Promise<void>) or one PLAIN value of the
|
|
3882
|
+
* result's inner type (promise arguments never reach here — the
|
|
3883
|
+
* frontend returns them as-is, the spec's native-promise identity;
|
|
3884
|
+
* thenables and promise-armed unions fence); the backend mints a fresh
|
|
3885
|
+
* promise and fulfills it immediately per the inner kind. */
|
|
3886
|
+
| {
|
|
3887
|
+
kind: "intrinsic";
|
|
3888
|
+
name: "console.log" | "console.error" | "promise.race" | "promise.all" | "promise.reject" | "promise.resolve";
|
|
3889
|
+
args: IrExpr[];
|
|
3890
|
+
type: IrType;
|
|
3891
|
+
loc: SrcLoc;
|
|
3892
|
+
}
|
|
3893
|
+
/** Standard-library call (`process` members, node:fs functions). `fn` is a
|
|
3894
|
+
* closed union; arg/result types are fixed per member (validated against
|
|
3895
|
+
* LIB_FN_SIGS). Property READS (`process.argv`, `process.platform`) are
|
|
3896
|
+
* zero-arg libCalls. Args are BORROWED by the operation (frame temps
|
|
3897
|
+
* release at statement end); refcounted results come back owned (+1) —
|
|
3898
|
+
* `process.argv` returns +1 on ONE interned array (JS identity:
|
|
3899
|
+
* `process.argv === process.argv` is true; mutations persist across
|
|
3900
|
+
* reads), everything else is fresh. fs.* members can throw (catchable
|
|
3901
|
+
* string payloads formatted like Node's messages) — backends must consult
|
|
3902
|
+
* the may-throw seed set (MAY_THROW_LIB_FNS) in their analysis and emit
|
|
3903
|
+
* pending checks; process.* members never throw. `process.exit` flushes
|
|
3904
|
+
* stdout and terminates the process without running exit handlers. */
|
|
3905
|
+
| {
|
|
3906
|
+
kind: "libCall";
|
|
3907
|
+
fn: IrLibFn;
|
|
3908
|
+
args: IrExpr[];
|
|
3909
|
+
type: IrType;
|
|
3910
|
+
loc: SrcLoc;
|
|
3911
|
+
}
|
|
3912
|
+
/** `JSON.stringify(v)` — type-DIRECTED serialization: `value`'s static IR
|
|
3913
|
+
* type must be JSON-safe (f64/string/bool/record/array/union of those,
|
|
3914
|
+
* recursively — validated), and backends emit one serializer per type used
|
|
3915
|
+
* in stringify position (interned, like the array-HOF desugars) instead of
|
|
3916
|
+
* walking any runtime tag. Output is Node-compatible byte-for-byte with
|
|
3917
|
+
* ONE documented divergence: record fields serialize in canonical (sorted)
|
|
3918
|
+
* order, not insertion order (SEMANTICS.md). NaN/±Infinity stringify as
|
|
3919
|
+
* `null` and -0 as `0`, exactly like JS; a record field holding the
|
|
3920
|
+
* undefined arm of its union (an optional field) is DROPPED from the
|
|
3921
|
+
* output — Node's rule for undefined-valued properties. The value is
|
|
3922
|
+
* BORROWED; the result string is owned (+1). Never throws. */
|
|
3923
|
+
| {
|
|
3924
|
+
kind: "jsonStringify";
|
|
3925
|
+
value: IrExpr;
|
|
3926
|
+
type: IrType;
|
|
3927
|
+
loc: SrcLoc;
|
|
3928
|
+
}
|
|
3929
|
+
/** The dynamic-boundary check — a CHECKED cast `dynValue as T`: validate
|
|
3930
|
+
* the dyn value's JSON DOM against `type` (a non-dyn, JSON-representable
|
|
3931
|
+
* IR type) and BUILD the typed value (+1), or THROW a catchable
|
|
3932
|
+
* TypeError-flavored, path-annotated string ("TypeError: expected number
|
|
3933
|
+
* at $.items[2].price, got string") through the exception cell. Semantics:
|
|
3934
|
+
* numbers/strings/bools match strictly (no coercions); records are
|
|
3935
|
+
* WIDTH-TOLERANT (extra JSON keys are ignored — this is check-and-extract,
|
|
3936
|
+
* not shape equality; missing or wrong-typed fields throw, EXCEPT that a
|
|
3937
|
+
* missing key for an undefined-armed union field — an optional field —
|
|
3938
|
+
* builds the interned undefined arm instead); arrays check every element;
|
|
3939
|
+
* unions try arms in canonical order and the first FULL match wins (no
|
|
3940
|
+
* match → throw; an undefined arm matches no DOM value); JSON null matches
|
|
3941
|
+
* exactly the nullT arm of a union target (bare null targets cannot
|
|
3942
|
+
* exist). MAY THROW:
|
|
3943
|
+
* backends' may-throw analyses must treat it like a `throw` statement.
|
|
3944
|
+
* The dyn operand is borrowed; the result is owned (+1). This is
|
|
3945
|
+
* scriptc-specific behavior — JS `as` never checks (SEMANTICS.md
|
|
3946
|
+
* documents it as the headline divergence: a lying cast throws instead of
|
|
3947
|
+
* corrupting memory). */
|
|
3948
|
+
| {
|
|
3949
|
+
kind: "dynCheck";
|
|
3950
|
+
value: IrExpr;
|
|
3951
|
+
type: IrType;
|
|
3952
|
+
loc: SrcLoc;
|
|
3953
|
+
}
|
|
3954
|
+
/** Static → island marshal (--dynamic builds only). `value`'s type is
|
|
3955
|
+
* f64/string/bool (marshaled by value) or a JSON-safe composite
|
|
3956
|
+
* (record/array/union — marshaled as a DEEP COPY through the emitted
|
|
3957
|
+
* type-directed JSON serializer and the engine's JSON parser; the
|
|
3958
|
+
* aliasing divergence is documented in SEMANTICS.md). Result is an
|
|
3959
|
+
* owned (+1) jsval; the operand is borrowed. Never throws. */
|
|
3960
|
+
| {
|
|
3961
|
+
kind: "jsMarshal";
|
|
3962
|
+
value: IrExpr;
|
|
3963
|
+
type: IrType;
|
|
3964
|
+
loc: SrcLoc;
|
|
3965
|
+
}
|
|
3966
|
+
/** An operation on island values (--dynamic builds only), executed by
|
|
3967
|
+
* the embedded engine with JS-exact semantics (coercions come from
|
|
3968
|
+
* pinned prelude closures, not C reimplementations). `args` are
|
|
3969
|
+
* jsval-typed and borrowed. Result `type` per op: arithmetic
|
|
3970
|
+
* (add/sub/mul/div/mod/pow), unary neg/plus, getProp/getIdx,
|
|
3971
|
+
* callMethod/callFn/globalGet → jsval (+1); comparisons
|
|
3972
|
+
* (lt/le/gt/ge/eq/neq), truthy, not → bool; typeof, toStr → string (+1);
|
|
3973
|
+
* setProp/setIdx → void. `name` carries the property/method identifier
|
|
3974
|
+
* for getProp/setProp/callMethod/globalGet, absent otherwise. MAY THROW
|
|
3975
|
+
* (engine
|
|
3976
|
+
* exceptions bridge into the exception cell, catchably) — backends'
|
|
3977
|
+
* may-throw analyses must seed on every jsOp like a `throw`. */
|
|
3978
|
+
| {
|
|
3979
|
+
kind: "jsOp";
|
|
3980
|
+
op: IrJsOp;
|
|
3981
|
+
name?: string;
|
|
3982
|
+
args: IrExpr[];
|
|
3983
|
+
type: IrType;
|
|
3984
|
+
loc: SrcLoc;
|
|
3985
|
+
}
|
|
3986
|
+
/** Island → static validated exit (--dynamic builds only): `value` is
|
|
3987
|
+
* jsval-typed, `type` is the static target. STRICT for primitives (a
|
|
3988
|
+
* non-number refuses to exit as number — no coercion); composite
|
|
3989
|
+
* targets round-trip through the engine's JSON.stringify and the
|
|
3990
|
+
* existing dynCheck walker for the target (width-tolerant records,
|
|
3991
|
+
* path-annotated failures — identical semantics to `dyn as T`). MAY
|
|
3992
|
+
* THROW a catchable TypeError-shaped string. The operand is borrowed;
|
|
3993
|
+
* the result is owned (+1) for refcounted targets. */
|
|
3994
|
+
| {
|
|
3995
|
+
kind: "jsExit";
|
|
3996
|
+
value: IrExpr;
|
|
3997
|
+
type: IrType;
|
|
3998
|
+
loc: SrcLoc;
|
|
3999
|
+
}
|
|
4000
|
+
/** Island → static PROMISE bridge (--dynamic builds only): `value` is a
|
|
4001
|
+
* jsval whose declared type is Promise<T> (a package call's promise —
|
|
4002
|
+
* it lives in the engine); the result is a fresh pending static promise
|
|
4003
|
+
* the engine promise settles. `type` is promise-of-jsval (the settled
|
|
4004
|
+
* engine value crosses as a retained handle; typed uses exit like any
|
|
4005
|
+
* jsval) or promise-of-void (T mapped to void — nothing to carry).
|
|
4006
|
+
* Fulfillment wakes parked awaiters through the ready queue; rejection
|
|
4007
|
+
* crosses like a bridged exception (engine Errors become real static
|
|
4008
|
+
* Errors) and re-throws at the await or enters the unhandled ledger.
|
|
4009
|
+
* Bridging one engine promise twice makes two independent static
|
|
4010
|
+
* observers of the same settlement — semantically equivalent, slightly
|
|
4011
|
+
* redundant (SEMANTICS.md). Operand borrowed; result +1. MAY THROW
|
|
4012
|
+
* only on an engine-level surprise minting the subscription — backends
|
|
4013
|
+
* seed may-throw and emit the pending check like other island ops. */
|
|
4014
|
+
| {
|
|
4015
|
+
kind: "jsBridgePromise";
|
|
4016
|
+
value: IrExpr;
|
|
4017
|
+
type: IrType;
|
|
4018
|
+
loc: SrcLoc;
|
|
4019
|
+
};
|
|
4020
|
+
/** The island operation set. Grouped by result type — see the jsOp node
|
|
4021
|
+
* doc. A closed union: every member has a lowering rule in the frontend,
|
|
4022
|
+
* a validation rule, and a scr_jsval_* implementation in scr_island.c. */
|
|
4023
|
+
export type IrJsOp = "add" | "sub" | "mul" | "div" | "mod" | "pow" | "neg" | "plus" | "lt" | "le" | "gt" | "ge" | "eq" | "neq"
|
|
4024
|
+
/** `v instanceof C` where BOTH sides are island values (a package-
|
|
4025
|
+
* exported class as the RHS): the spec's InstanceofOperator in the
|
|
4026
|
+
* engine, Symbol.hasInstance included; a non-object RHS throws the
|
|
4027
|
+
* engine's own TypeError, bridged catchably. */
|
|
4028
|
+
| "instanceOf" | "truthy" | "not" | "typeof" | "toStr" | "getProp" | "setProp" | "getIdx" | "setIdx" | "callMethod" | "callFn"
|
|
4029
|
+
/** `new X(...)` where X is jsval-typed (package-declared classes):
|
|
4030
|
+
* JS_CallConstructor — args are the callee then the constructor
|
|
4031
|
+
* arguments, mirroring callFn. */
|
|
4032
|
+
| "construct"
|
|
4033
|
+
/** A member of the engine's global object by name (Math, parseFloat, ...)
|
|
4034
|
+
* — the receiver/callee for the island-backed ambient surface. Zero args;
|
|
4035
|
+
* `name` carries the global's identifier. May-throw for uniformity with
|
|
4036
|
+
* the other engine entries (the emitter's pending check runs after it). */
|
|
4037
|
+
| "globalGet"
|
|
4038
|
+
/** Island-native literals: an object literal / array literal whose
|
|
4039
|
+
* contextual type is `any` builds directly in the engine — objLit args
|
|
4040
|
+
* are alternating key/value jsvals (keys are marshaled strings), arrLit
|
|
4041
|
+
* args are the elements. Never throw. */
|
|
4042
|
+
| "objLit" | "arrLit"
|
|
4043
|
+
/** The engine's own undefined / null as island values (zero args, never
|
|
4044
|
+
* throw): the unit arms of a union marshaling IN (`string | undefined`
|
|
4045
|
+
* into an 'any' slot — the undefined arm IS the engine undefined), and
|
|
4046
|
+
* conceptually the unit path of `x?.y` on 'any' (the emitter inlines
|
|
4047
|
+
* that one). */
|
|
4048
|
+
| "undefLit" | "nullLit"
|
|
4049
|
+
/** GetIterator over an island value — the for-of head over 'any' (the
|
|
4050
|
+
* engine's own protocol lookup; V8's not-iterable TypeError on refusal).
|
|
4051
|
+
* The loop drives next() through callMethod and reads value/done with
|
|
4052
|
+
* getProp/truthy. */
|
|
4053
|
+
| "iterNew"
|
|
4054
|
+
/** `o.name?.(...)` — the optional METHOD call on an island receiver: a
|
|
4055
|
+
* nullish member answers the engine's undefined, anything else calls
|
|
4056
|
+
* with `this = o` (JS-exact; non-callables throw in the engine). */
|
|
4057
|
+
| "optCallMethod";
|
|
4058
|
+
/** Result-type rule for each island op (the validator enforces it; the
|
|
4059
|
+
* frontend constructs nodes with exactly these). */
|
|
4060
|
+
export declare function jsOpResultKind(op: IrJsOp): "jsval" | "bool" | "string" | "void";
|
|
4061
|
+
/** True when a type is a union with an undefined arm — the optional-flavored
|
|
4062
|
+
* slot marker shared by the frontend (record literals may omit such fields)
|
|
4063
|
+
* and backends (JSON serializers DROP such fields when they hold undefined,
|
|
4064
|
+
* dynCheck builders produce the undefined arm for a MISSING key). Note the
|
|
4065
|
+
* question is about the TYPE, not a declaration's `?:` token: without
|
|
4066
|
+
* exactOptionalPropertyTypes, `{a?: string}` and `{a: string | undefined}`
|
|
4067
|
+
* are the same shape and behave identically — which is exactly Node's rule
|
|
4068
|
+
* (JSON.stringify drops ANY undefined-valued field, declared optional or
|
|
4069
|
+
* not). */
|
|
4070
|
+
export declare function isUndefinedArmedUnion(t: IrType, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4071
|
+
/** True when a type is JSON-representable — the shared fence for
|
|
4072
|
+
* `jsonStringify` (what can be serialized) and `dynCheck` (what a dyn value
|
|
4073
|
+
* can be validated against): f64, string, bool, records, arrays, and unions
|
|
4074
|
+
* of those, recursively. Closures, class instances, dyn itself, and void are
|
|
4075
|
+
* not JSON. Registry lookups are parameters because the frontend holds
|
|
4076
|
+
* registries and the validator/backend hold maps; recursive shapes/unions
|
|
4077
|
+
* cannot exist (the frontend rejects them), so the recursion terminates. */
|
|
4078
|
+
export declare function isJsonSafeType(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4079
|
+
/** THE island boundary predicate: true when a static type can cross into
|
|
4080
|
+
* the island (jsMarshal — primitives by value, composites as deep JSON
|
|
4081
|
+
* copies) and back out (jsExit — strict primitive extraction, composites
|
|
4082
|
+
* through the dynCheck walker). Primitives are JSON-safe, so the rule
|
|
4083
|
+
* coincides with isJsonSafeType; it has its own name because the boundary
|
|
4084
|
+
* is its own concept — the frontend's implicit coercions, the explicit-cast
|
|
4085
|
+
* lowering, and the validator's jsMarshal/jsExit rules all ask this ONE
|
|
4086
|
+
* question, and the boundary rejection messages describe exactly this set. */
|
|
4087
|
+
export declare function canCrossIslandBoundary(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4088
|
+
/** True for a closure type that can cross INTO the island as a host
|
|
4089
|
+
* function: every parameter jsval (the engine's arguments pass through as
|
|
4090
|
+
* handles — no per-type extraction exists inside a host call) and the
|
|
4091
|
+
* result jsval, void, or a primitive (which marshals back by value —
|
|
4092
|
+
* `(x) => x * 2` on an 'any' x infers a number return). Contextual typing
|
|
4093
|
+
* produces exactly this shape for callbacks passed to package APIs
|
|
4094
|
+
* (`.action((a, b) => ...)` against `(...args: any[]) => void`). Arity is
|
|
4095
|
+
* capped by the runtime's host-call argument buffer (scr_island.c). */
|
|
4096
|
+
export declare const MAX_ISLAND_CALLBACK_ARITY = 16;
|
|
4097
|
+
export declare function canMarshalFuncIntoIsland(t: IrType): boolean;
|
|
4098
|
+
/** Parameter types a TYPED closure may declare when it crosses INTO the
|
|
4099
|
+
* island as a host function: jsval params take the engine argument as a
|
|
4100
|
+
* handle (the all-'any' shape above); every other admitted type converts
|
|
4101
|
+
* AT CALL TIME through the validated-exit machinery — strict primitives,
|
|
4102
|
+
* JSON round-trip composites (the dynCheck walker: width-tolerant records,
|
|
4103
|
+
* path-annotated failures). On top of the jsExit set, a bare `T | undefined`
|
|
4104
|
+
* union is admitted here — an absent or undefined engine argument takes the
|
|
4105
|
+
* undefined arm, exactly the missing-optional-field rule (and exactly the
|
|
4106
|
+
* commander case: `.action((text: string | undefined, opts) => ...)` sees
|
|
4107
|
+
* undefined when the command argument is omitted). */
|
|
4108
|
+
export declare function isIslandCallbackParamType(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4109
|
+
/** Classify a typed island callback's RETURN for adapter synthesis: sync
|
|
4110
|
+
* kinds marshal back by value ('void'|'jsval'|'f64'|'bool'|'string' — the
|
|
4111
|
+
* canMarshalFuncIntoIsland set), 'json' marshals a JSON-safe composite
|
|
4112
|
+
* through the type-directed serializer + engine parse (the jsMarshal
|
|
4113
|
+
* composite path — commander's option-argument collectors return arrays
|
|
4114
|
+
* this way), and a Promise of the by-value kinds wraps as an engine
|
|
4115
|
+
* promise settled when the scriptc promise settles (async callbacks —
|
|
4116
|
+
* the `.action(async ...)` case). Null for anything else (Promise of
|
|
4117
|
+
* composites: still fenced). */
|
|
4118
|
+
export declare function islandCallbackRet(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): {
|
|
4119
|
+
async: boolean;
|
|
4120
|
+
tag: "void" | "jsval" | "f64" | "bool" | "string" | "json";
|
|
4121
|
+
} | null;
|
|
4122
|
+
/** The TYPED extension of canMarshalFuncIntoIsland (a strict superset):
|
|
4123
|
+
* closures whose params are per-argument-convertible at call time
|
|
4124
|
+
* (isIslandCallbackParamType) and whose return classifies
|
|
4125
|
+
* (islandCallbackRet). Same arity cap — the runtime's host-call argument
|
|
4126
|
+
* buffer. Closures taking closures and 'unknown'-typed params stay fenced
|
|
4127
|
+
* (no per-type extraction exists for them inside a host call). */
|
|
4128
|
+
export declare function canMarshalTypedFuncIntoIsland(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4129
|
+
/** The runtime HANDLE kinds that cross the checked-dynamic boundary as
|
|
4130
|
+
* the DOM's HANDLE kind (SCR_DYN_HANDLE): boxed by REFERENCE (identity —
|
|
4131
|
+
* stateful I/O objects never copy), unboxed by tag check, members
|
|
4132
|
+
* dispatched at runtime onto the same entry points the static lowerings
|
|
4133
|
+
* use. The set is deliberately the handles whose member surfaces have
|
|
4134
|
+
* complete static lowerings (the http/net receiver surface —
|
|
4135
|
+
* `server.on('request', mustCall((req, res) => ...))` is the canonical
|
|
4136
|
+
* crossing); other handle kinds keep the honest cannot-box fence. Each
|
|
4137
|
+
* entry carries the runtime tag spelling and the class display name
|
|
4138
|
+
* (dynCheck's "expected IncomingMessage ..." texts). */
|
|
4139
|
+
export declare const DYN_HANDLE_KINDS: ReadonlyMap<string, {
|
|
4140
|
+
tag: string;
|
|
4141
|
+
cls: string;
|
|
4142
|
+
}>;
|
|
4143
|
+
/** A static type that CONVERTS into a dyn DOM value — the dynFrom domain:
|
|
4144
|
+
* JSON-safe data, bytes<u8> (payload copied), undefined-armed unions of
|
|
4145
|
+
* JSON-safe arms, boxable function types, and the runtime HANDLE kinds
|
|
4146
|
+
* (boxed by reference — DYN_HANDLE_KINDS). */
|
|
4147
|
+
export declare function canConvertToDyn(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4148
|
+
/** A type a dyn value can be VALIDATED into — the dynCheck domain:
|
|
4149
|
+
* JSON-safe data, bytes<u8> (a fresh copy out), the %Error extraction,
|
|
4150
|
+
* undefined-armed unions of JSON-safe arms, adaptable function types,
|
|
4151
|
+
* and the runtime HANDLE kinds (a tag-checked reference unwrap —
|
|
4152
|
+
* DYN_HANDLE_KINDS). */
|
|
4153
|
+
export declare function canDynCheckTo(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4154
|
+
/** A closure type that can BOX into the DOM's function kind (dynFrom):
|
|
4155
|
+
* every param dyn or dynCheckable (the thunk validates dyn arguments into
|
|
4156
|
+
* them), return void, dyn, or dyn-convertible (the thunk converts it
|
|
4157
|
+
* back). */
|
|
4158
|
+
export declare function canBoxFuncIntoDyn(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4159
|
+
/** A closure type a dyn function value can ADAPT to (dynCheck): every
|
|
4160
|
+
* param dyn or dyn-convertible (the adapter converts typed arguments into
|
|
4161
|
+
* dyn), return void, dyn, or dynCheckable (the adapter validates the dyn
|
|
4162
|
+
* result). */
|
|
4163
|
+
export declare function canAdaptDynFuncTo(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4164
|
+
/** The MARSHAL-direction boundary (jsMarshal): everything that can cross
|
|
4165
|
+
* out and back (canCrossIslandBoundary) plus qualifying closures — those
|
|
4166
|
+
* enter as host functions but never EXIT (jsExit keeps the narrower
|
|
4167
|
+
* predicate). */
|
|
4168
|
+
export declare function canMarshalIntoIsland(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4169
|
+
/** The EXIT-direction boundary (jsExit): everything round-trippable
|
|
4170
|
+
* (canCrossIslandBoundary) plus BARE undefined/null-armed unions whose
|
|
4171
|
+
* data arms are all JSON-safe — the engine's undefined takes the
|
|
4172
|
+
* undefined arm before the JSON detour (JSON cannot spell undefined, and
|
|
4173
|
+
* bare undefined-armed unions are JSON-unsafe for exactly that reason),
|
|
4174
|
+
* null and data ride the round trip into the union's dynCheck. The
|
|
4175
|
+
* package-API shape `result.headers` : `Record<string, string> |
|
|
4176
|
+
* undefined` is the motivating case. */
|
|
4177
|
+
export declare function canExitIslandToType(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): boolean;
|
|
4178
|
+
/** True when the module contains any regex construct — a regexLit /
|
|
4179
|
+
* regexIntrinsic node or a regex-typed slot anywhere. This is the link
|
|
4180
|
+
* switch that pulls scr_regex.c + the vendored libregexp into the binary
|
|
4181
|
+
* (cc.ts); regex-free programs keep the historical command line. A generic
|
|
4182
|
+
* JSON walk: `kind` discriminants live only on IR objects, so user string
|
|
4183
|
+
* VALUES can never false-positive. */
|
|
4184
|
+
export declare function moduleUsesRegex(mod: IrModule): boolean;
|
|
4185
|
+
/** True when the embedded npm graph references fetch — the link switch
|
|
4186
|
+
* that pulls scr_fetch.c + its socket/tls/zlib dependencies into the binary (cc.ts) and
|
|
4187
|
+
* has the emitted main call scr_fetch_install. A word-boundary scan over
|
|
4188
|
+
* the embedded SOURCES, erring toward linking: a false positive costs one
|
|
4189
|
+
* dylib reference; a false negative would leave embedded code without the
|
|
4190
|
+
* global at runtime. Static builds and fetch-free graphs keep their exact
|
|
4191
|
+
* historical link lines. */
|
|
4192
|
+
export declare function moduleUsesFetch(mod: IrModule): boolean;
|
|
4193
|
+
/** True when the module uses the process-events surface — the link switch
|
|
4194
|
+
* that pulls scr_events.c into the binary and has the emitted main call
|
|
4195
|
+
* scr_events_install (cc.ts + emitter; the scr_regex/scr_fetch/scr_zlib
|
|
4196
|
+
* gating precedent). Event-free programs pay zero bytes and keep their
|
|
4197
|
+
* exact link line. Same generic-walk shape as moduleUsesRegex. */
|
|
4198
|
+
export declare function moduleUsesProcessEvents(mod: IrModule): boolean;
|
|
4199
|
+
/** True when the module uses the node:events EventEmitter surface — the
|
|
4200
|
+
* link switch that pulls scr_events_emitter.c into the binary (cc.ts; the
|
|
4201
|
+
* scr_events.c gating precedent, but pure data structure: no install, no
|
|
4202
|
+
* loop hooks). Two signals: the `%EventEmitter` class def rides the
|
|
4203
|
+
* module (any emitter-typed value or `extends EventEmitter` subclass
|
|
4204
|
+
* references it, and the emitted RC/trace helpers call scr_emitter_*),
|
|
4205
|
+
* or an emitter.* libCall survived (the defaultMaxListeners statics carry
|
|
4206
|
+
* no emitter-typed value). Emitter-free programs pay zero bytes and keep
|
|
4207
|
+
* their exact link line. */
|
|
4208
|
+
export declare function moduleUsesEmitter(mod: IrModule): boolean;
|
|
4209
|
+
/** True when the program touches the node:stream surface (scr_stream.c —
|
|
4210
|
+
* the moduleUsesEmitter story: the class defs ride the module whenever a
|
|
4211
|
+
* stream-typed value exists, and every stream libCall names its unit).
|
|
4212
|
+
* Stream programs always use the emitter unit too — the stream class
|
|
4213
|
+
* defs pull `%EventEmitter` through their base chain, so
|
|
4214
|
+
* moduleUsesEmitter answers true whenever this does. Stream-free
|
|
4215
|
+
* programs pay zero bytes and keep their exact link line. */
|
|
4216
|
+
export declare function moduleUsesStream(mod: IrModule): boolean;
|
|
4217
|
+
/** True when the embedded npm graph has an edge into `builtin` — the
|
|
4218
|
+
* island shim needs the corresponding native bridge linked (zlib's is
|
|
4219
|
+
* the first; the emitted main installs it before any island entry). */
|
|
4220
|
+
export declare function moduleEmbedsBuiltin(mod: IrModule, builtin: string): boolean;
|
|
4221
|
+
/** Embedded module texts at least this long are DEFLATE-compressed into
|
|
4222
|
+
* the emitted C (emit-island.ts; each stays plain when deflate does not
|
|
4223
|
+
* shrink it) and inflated lazily by the island's module loader at first
|
|
4224
|
+
* load. Below it the zlib round trip cannot pay for itself. */
|
|
4225
|
+
export declare const NPM_COMPRESS_MIN = 1024;
|
|
4226
|
+
/** True when the emitted npm tables will carry compressed module text —
|
|
4227
|
+
* the SAME candidate test emit-island.ts compresses by, so index.ts's
|
|
4228
|
+
* zlib link switch and emitter.ts's inflater installation stay in
|
|
4229
|
+
* lockstep with the emission (a candidate whose deflate happens not to
|
|
4230
|
+
* shrink stays plain; the installed inflater is then just unused). */
|
|
4231
|
+
export declare function moduleEmbedsCompressedNpm(mod: IrModule): boolean;
|
|
4232
|
+
/** True when the module contains any zlib libCall (the static lowering)
|
|
4233
|
+
* OR the embedded npm graph imports node:zlib (the island shim) — the
|
|
4234
|
+
* link switch that pulls scr_zlib.c + the system libz into the binary
|
|
4235
|
+
* (cc.ts); zlib-free programs keep their exact link line. Same
|
|
4236
|
+
* generic-walk shape as moduleUsesRegex: `kind`/`fn` discriminants live
|
|
4237
|
+
* only on IR objects. */
|
|
4238
|
+
export declare function moduleUsesZlib(mod: IrModule): boolean;
|
|
4239
|
+
/** True when the module contains any dc.* libCall — the link switch that
|
|
4240
|
+
* pulls scr_dc.c (the diagnostics_channel registry and pub/sub) into the
|
|
4241
|
+
* binary (cc.ts). Channel-free binaries keep their exact size class.
|
|
4242
|
+
* Same walk shape as moduleUsesZlib. */
|
|
4243
|
+
export declare function moduleUsesDc(mod: IrModule): boolean;
|
|
4244
|
+
/** True when the module contains any assert libCall — the link switch
|
|
4245
|
+
* that pulls scr_assert.c into the binary (cc.ts). scr_regex.c calls the
|
|
4246
|
+
* assert throw/inspect helpers (assert.match lives there), so the regex
|
|
4247
|
+
* switch also pulls scr_assert.c; assert-free, regex-free binaries keep
|
|
4248
|
+
* the historical command line and size. Same walk shape as
|
|
4249
|
+
* moduleUsesZlib. */
|
|
4250
|
+
export declare function moduleUsesAssert(mod: IrModule): boolean;
|
|
4251
|
+
/** True when the module contains any dynInvoke node or dyn.defineProps
|
|
4252
|
+
* libCall — the link switch that pulls scr_dyn_invoke.c (the prototype-
|
|
4253
|
+
* method dispatch on dyn receivers, plus scr_dyn_display and
|
|
4254
|
+
* scr_dyn_define_props) into the binary (cc.ts; the assert gating
|
|
4255
|
+
* precedent — dispatch-free binaries keep their exact size class). Same
|
|
4256
|
+
* walk shape as moduleUsesZlib. */
|
|
4257
|
+
export declare function moduleUsesDynInvoke(mod: IrModule): boolean;
|
|
4258
|
+
/** True when the module contains any insp libCall — the link switch that
|
|
4259
|
+
* pulls scr_inspect.c into the binary (cc.ts; the assert gating
|
|
4260
|
+
* precedent — inspect-free binaries keep the historical command line and
|
|
4261
|
+
* size class). Same walk shape as moduleUsesZlib. */
|
|
4262
|
+
/** True when the module needs scr_async_dyn.c — the checked-dynamic
|
|
4263
|
+
* async surfaces (DOM-promise then/catch/finally reactions, await of a
|
|
4264
|
+
* dyn value, `new Promise(setImmediate)`, AsyncLocalStorage, the
|
|
4265
|
+
* unhandledRejection/warning process events). Also pulled by the
|
|
4266
|
+
* dynInvoke and dc gates (their TUs call into this one) — cc.ts. Same
|
|
4267
|
+
* walk shape as moduleUsesZlib. */
|
|
4268
|
+
export declare function moduleUsesDynAsync(mod: IrModule): boolean;
|
|
4269
|
+
export declare function moduleUsesInspect(mod: IrModule): boolean;
|
|
4270
|
+
/** True when the module contains any net libCall — the link switch that
|
|
4271
|
+
* pulls scr_net.c into the binary and has the emitted main call
|
|
4272
|
+
* scr_net_install (cc.ts + emitter; the scr_events gating precedent).
|
|
4273
|
+
* Net-free programs pay zero bytes and keep their exact link line. Same
|
|
4274
|
+
* generic-walk shape as moduleUsesZlib. */
|
|
4275
|
+
export declare function moduleUsesNet(mod: IrModule): boolean;
|
|
4276
|
+
/** True when the module contains any sym.* libCall or a symbol-kind type
|
|
4277
|
+
* anywhere in the IR — the link switch that pulls scr_symbol.c into the
|
|
4278
|
+
* binary (cc.ts; the scr_net gating precedent — no install call, the
|
|
4279
|
+
* Symbol.for registry initializes lazily). The TYPE check matters like
|
|
4280
|
+
* net's: a symbol-typed local whose initializer compiled to a runtime
|
|
4281
|
+
* fence still emits release calls that need the unit linked. Symbol-free
|
|
4282
|
+
* programs pay zero bytes and keep their exact link line. */
|
|
4283
|
+
export declare function moduleUsesSymbol(mod: IrModule): boolean;
|
|
4284
|
+
/** True when the module uses the URLSearchParams surface — sp.* libCalls,
|
|
4285
|
+
* the url.searchParams getter, or a searchParams-kind type anywhere on
|
|
4286
|
+
* the IR (a fenced statement can leave a typed local whose release call
|
|
4287
|
+
* still needs the unit linked) — the link switch that pulls
|
|
4288
|
+
* scr_url_params.c into the binary (the moduleUsesSymbol precedent: pure
|
|
4289
|
+
* data structure, no loop hooks, cross-compiles everywhere). sp-free
|
|
4290
|
+
* programs keep their exact link line; scr_url.c itself stays
|
|
4291
|
+
* always-linked and never references the unit. */
|
|
4292
|
+
export declare function moduleUsesSearchParams(mod: IrModule): boolean;
|
|
4293
|
+
/** True when the module contains any fs.watch/watcher.* libCall — the
|
|
4294
|
+
* link switch that pulls scr_watch.c into the binary and has the emitted
|
|
4295
|
+
* main call scr_watch_install (cc.ts + emitter; the scr_net gating
|
|
4296
|
+
* precedent). Watch-free programs pay zero bytes and keep their exact
|
|
4297
|
+
* link line. Same generic-walk shape as moduleUsesZlib. */
|
|
4298
|
+
export declare function moduleUsesFsWatch(mod: IrModule): boolean;
|
|
4299
|
+
/** True when the module contains any test.* libCall or a testCtx handle
|
|
4300
|
+
* type — the link switch that pulls scr_test.c into the binary and has
|
|
4301
|
+
* the emitted main return scr_test_exit_code() after the loop drains
|
|
4302
|
+
* (cc.ts + emitter; the moduleUsesDgram shape). Test-free programs pay
|
|
4303
|
+
* zero bytes and keep their exact link line. */
|
|
4304
|
+
export declare function moduleUsesNodeTest(mod: IrModule): boolean;
|
|
4305
|
+
/** True when the module contains any dgram.* or dns.* libCall — the
|
|
4306
|
+
* link switch that pulls scr_dgram.c into the binary and has the emitted
|
|
4307
|
+
* main call scr_dgram_install (cc.ts + emitter; the scr_net gating
|
|
4308
|
+
* precedent — dns.lookup lives in the same unit, so either prefix
|
|
4309
|
+
* answers). Dgram-free programs pay zero bytes and keep their exact link
|
|
4310
|
+
* line. Same generic-walk shape as moduleUsesZlib. */
|
|
4311
|
+
export declare function moduleUsesDgram(mod: IrModule): boolean;
|
|
4312
|
+
/** True when the module contains any http.* libCall — the link switch
|
|
4313
|
+
* that pulls scr_http.c into the binary (cc.ts; moduleUsesNet already
|
|
4314
|
+
* answers true for these, so scr_net.c comes along). */
|
|
4315
|
+
export declare function moduleUsesHttpServer(mod: IrModule): boolean;
|
|
4316
|
+
/** True when the module uses the REAL h2 surface (scr_http2.c): any core
|
|
4317
|
+
* http2.* libCall, or an h2 handle type left behind by a fenced statement
|
|
4318
|
+
* (its emitted release call needs the unit — the moduleUsesNet story). */
|
|
4319
|
+
export declare function moduleUsesHttp2(mod: IrModule): boolean;
|
|
4320
|
+
/** True when the module contains any tls.* or https.* libCall — the link
|
|
4321
|
+
* switch that pulls scr_tls.c and the vendored mbedTLS archive into the
|
|
4322
|
+
* binary (cc.ts; moduleUsesNet and moduleUsesHttpServer already answer
|
|
4323
|
+
* true for these, so scr_net.c and scr_http.c come along). TLS-free
|
|
4324
|
+
* programs keep their exact link line and never build mbedTLS. */
|
|
4325
|
+
export declare function moduleUsesTls(mod: IrModule): boolean;
|
|
4326
|
+
/** The may-throw seed: libCall members that can raise. Every fs.* member
|
|
4327
|
+
* EXCEPT existsSync (which, like Node's, swallows errors and returns false)
|
|
4328
|
+
* throws a catchable error on failure; json.parse throws a catchable
|
|
4329
|
+
* SyntaxError-shaped string on malformed input; process.* members never
|
|
4330
|
+
* throw. Backends' may-throw analyses must treat a function containing one
|
|
4331
|
+
* of these as throwing, exactly like a `throw` statement (and must ALSO
|
|
4332
|
+
* seed on `dynCheck` and `awaitExpr` nodes, which throw on validation
|
|
4333
|
+
* failure / promise rejection). */
|
|
4334
|
+
export declare const MAY_THROW_LIB_FNS: ReadonlySet<IrLibFn>;
|