@scriptc/compiler 0.1.1 → 0.1.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.
Files changed (209) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +45 -17
  2. package/ambient/scriptc.d.ts +2 -1
  3. package/dist/backend/build-cache.js.map +1 -1
  4. package/dist/backend/c/async.js +24 -2
  5. package/dist/backend/c/async.js.map +1 -1
  6. package/dist/backend/c/c-emitter.d.ts +22 -10
  7. package/dist/backend/c/c-emitter.js +60 -15
  8. package/dist/backend/c/c-emitter.js.map +1 -1
  9. package/dist/backend/c/exprs.js +220 -10
  10. package/dist/backend/c/exprs.js.map +1 -1
  11. package/dist/backend/c/island.js.map +1 -1
  12. package/dist/backend/c/may-throw.js.map +1 -1
  13. package/dist/backend/c/stmts.d.ts +3 -5
  14. package/dist/backend/c/stmts.js +58 -17
  15. package/dist/backend/c/stmts.js.map +1 -1
  16. package/dist/backend/c/types.js.map +1 -1
  17. package/dist/backend/c/walkers.js +31 -5
  18. package/dist/backend/c/walkers.js.map +1 -1
  19. package/dist/backend/external-c.js.map +1 -1
  20. package/dist/backend/linker.js.map +1 -1
  21. package/dist/backend/llvm/blocks.js.map +1 -1
  22. package/dist/backend/llvm/dyn.js +56 -3
  23. package/dist/backend/llvm/dyn.js.map +1 -1
  24. package/dist/backend/llvm/emitter.js +98 -19
  25. package/dist/backend/llvm/emitter.js.map +1 -1
  26. package/dist/backend/llvm/expr-async.js +85 -3
  27. package/dist/backend/llvm/expr-async.js.map +1 -1
  28. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  29. package/dist/backend/llvm/expr-calls.js.map +1 -1
  30. package/dist/backend/llvm/expr-containers.js.map +1 -1
  31. package/dist/backend/llvm/expr-context.d.ts +1 -0
  32. package/dist/backend/llvm/expr-control.js.map +1 -1
  33. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  34. package/dist/backend/llvm/expr-dynamic.js +6 -3
  35. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  36. package/dist/backend/llvm/expr-island.js.map +1 -1
  37. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  38. package/dist/backend/llvm/expr-records.js.map +1 -1
  39. package/dist/backend/llvm/expr-stream-bridges.js +220 -9
  40. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  41. package/dist/backend/llvm/lib-dispatch.js +2 -0
  42. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  43. package/dist/backend/llvm/lib-shared.js +18 -0
  44. package/dist/backend/llvm/lib-shared.js.map +1 -1
  45. package/dist/backend/llvm/lib-stream.js +6 -3
  46. package/dist/backend/llvm/lib-stream.js.map +1 -1
  47. package/dist/backend/llvm/split.js.map +1 -1
  48. package/dist/backend/llvm/unsupported.js.map +1 -1
  49. package/dist/backend/llvm/walkers.js.map +1 -1
  50. package/dist/backend/native-codegen.js.map +1 -1
  51. package/dist/backend/native-codegen.test.js +2 -0
  52. package/dist/backend/native-codegen.test.js.map +1 -1
  53. package/dist/backend/native-toolchain.js.map +1 -1
  54. package/dist/backend/native-toolchain.test.js.map +1 -1
  55. package/dist/backend/runtime-pack.js.map +1 -1
  56. package/dist/backend/targets.js.map +1 -1
  57. package/dist/backend/vendor-archives.js.map +1 -1
  58. package/dist/compat/fetch-profile.js +4 -2
  59. package/dist/compat/fetch-profile.js.map +1 -1
  60. package/dist/coverage/report.js.map +1 -1
  61. package/dist/coverage/surface-manifest.js +12 -0
  62. package/dist/coverage/surface-manifest.js.map +1 -1
  63. package/dist/diagnostics/diagnostic.d.ts +6 -5
  64. package/dist/diagnostics/diagnostic.js +7 -6
  65. package/dist/diagnostics/diagnostic.js.map +1 -1
  66. package/dist/diagnostics/render.js.map +1 -1
  67. package/dist/ffi/ffi-manifest.js.map +1 -1
  68. package/dist/frontend/cjs-lexer.js.map +1 -1
  69. package/dist/frontend/dts-paths.js.map +1 -1
  70. package/dist/frontend/input-tracker.d.ts +10 -0
  71. package/dist/frontend/input-tracker.js +26 -3
  72. package/dist/frontend/input-tracker.js.map +1 -1
  73. package/dist/frontend/input-tracker.test.js +8 -1
  74. package/dist/frontend/input-tracker.test.js.map +1 -1
  75. package/dist/frontend/lib-contract.js.map +1 -1
  76. package/dist/frontend/lowering/array-values.d.ts +4 -0
  77. package/dist/frontend/lowering/array-values.js +18 -2
  78. package/dist/frontend/lowering/array-values.js.map +1 -1
  79. package/dist/frontend/lowering/callback-arg.js.map +1 -1
  80. package/dist/frontend/lowering/containers/bytes.d.ts +35 -0
  81. package/dist/frontend/lowering/containers/bytes.js +1021 -0
  82. package/dist/frontend/lowering/containers/bytes.js.map +1 -0
  83. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +17 -0
  84. package/dist/frontend/lowering/containers/string-and-regexp.js +345 -0
  85. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -0
  86. package/dist/frontend/lowering/expressions/evaluation-safety.d.ts +13 -0
  87. package/dist/frontend/lowering/expressions/evaluation-safety.js +76 -0
  88. package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -0
  89. package/dist/frontend/lowering/expressions/object-literals.d.ts +44 -0
  90. package/dist/frontend/lowering/expressions/object-literals.js +1815 -0
  91. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -0
  92. package/dist/frontend/lowering/expressions/optional-chains.d.ts +31 -0
  93. package/dist/frontend/lowering/expressions/optional-chains.js +382 -0
  94. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -0
  95. package/dist/frontend/lowering/expressions/try-lower-expression.d.ts +7 -0
  96. package/dist/frontend/lowering/expressions/try-lower-expression.js +26 -0
  97. package/dist/frontend/lowering/expressions/try-lower-expression.js.map +1 -0
  98. package/dist/frontend/lowering/lib-boundary.js +7 -2
  99. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  100. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  101. package/dist/frontend/lowering/lower-async-iteration.d.ts +7 -0
  102. package/dist/frontend/lowering/lower-async-iteration.js +657 -0
  103. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -0
  104. package/dist/frontend/lowering/lower-builtins.d.ts +18 -0
  105. package/dist/frontend/lowering/lower-builtins.js +219 -48
  106. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  107. package/dist/frontend/lowering/lower-calls.d.ts +13 -4
  108. package/dist/frontend/lowering/lower-calls.js +407 -64
  109. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  110. package/dist/frontend/lowering/lower-classes.d.ts +7 -13
  111. package/dist/frontend/lowering/lower-classes.js +128 -35
  112. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  113. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  114. package/dist/frontend/lowering/lower-containers.d.ts +1 -47
  115. package/dist/frontend/lowering/lower-containers.js +135 -1467
  116. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  117. package/dist/frontend/lowering/lower-event-emitter.js +51 -5
  118. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  119. package/dist/frontend/lowering/lower-exprs.d.ts +0 -78
  120. package/dist/frontend/lowering/lower-exprs.js +402 -2351
  121. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  122. package/dist/frontend/lowering/lower-generators.d.ts +18 -3
  123. package/dist/frontend/lowering/lower-generators.js +145 -9
  124. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  125. package/dist/frontend/lowering/lower-inspect.js +3 -3
  126. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  127. package/dist/frontend/lowering/lower-island.d.ts +6 -0
  128. package/dist/frontend/lowering/lower-island.js +37 -5
  129. package/dist/frontend/lowering/lower-island.js.map +1 -1
  130. package/dist/frontend/lowering/lower-modules.js +52 -15
  131. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  132. package/dist/frontend/lowering/lower-node-module.d.ts +18 -0
  133. package/dist/frontend/lowering/lower-node-module.js +302 -0
  134. package/dist/frontend/lowering/lower-node-module.js.map +1 -0
  135. package/dist/frontend/lowering/lower-server.js +1 -1
  136. package/dist/frontend/lowering/lower-server.js.map +1 -1
  137. package/dist/frontend/lowering/lower-stmts.d.ts +5 -24
  138. package/dist/frontend/lowering/lower-stmts.js +519 -253
  139. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  140. package/dist/frontend/lowering/lower-stream.js +4 -4
  141. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  142. package/dist/frontend/lowering/lowerer.d.ts +37 -34
  143. package/dist/frontend/lowering/lowerer.js +143 -57
  144. package/dist/frontend/lowering/lowerer.js.map +1 -1
  145. package/dist/frontend/lowering/optional-arguments.d.ts +9 -0
  146. package/dist/frontend/lowering/optional-arguments.js +57 -0
  147. package/dist/frontend/lowering/optional-arguments.js.map +1 -0
  148. package/dist/frontend/npm-static-declarations.d.ts +35 -0
  149. package/dist/frontend/npm-static-declarations.js +506 -0
  150. package/dist/frontend/npm-static-declarations.js.map +1 -0
  151. package/dist/frontend/npm-static-declarations.test.d.ts +1 -0
  152. package/dist/frontend/npm-static-declarations.test.js +122 -0
  153. package/dist/frontend/npm-static-declarations.test.js.map +1 -0
  154. package/dist/frontend/npm-static.d.ts +2 -0
  155. package/dist/frontend/npm-static.js +26 -10
  156. package/dist/frontend/npm-static.js.map +1 -1
  157. package/dist/frontend/npm.d.ts +60 -0
  158. package/dist/frontend/npm.js +38 -4
  159. package/dist/frontend/npm.js.map +1 -1
  160. package/dist/frontend/npm.test.d.ts +1 -0
  161. package/dist/frontend/npm.test.js +50 -0
  162. package/dist/frontend/npm.test.js.map +1 -0
  163. package/dist/frontend/program.d.ts +3 -2
  164. package/dist/frontend/program.js +495 -68
  165. package/dist/frontend/program.js.map +1 -1
  166. package/dist/frontend/resolve.d.ts +10 -2
  167. package/dist/frontend/resolve.js +90 -14
  168. package/dist/frontend/resolve.js.map +1 -1
  169. package/dist/frontend/resolve.test.js +4 -1
  170. package/dist/frontend/resolve.test.js.map +1 -1
  171. package/dist/frontend/runtime-resolve.d.ts +22 -0
  172. package/dist/frontend/runtime-resolve.js +101 -0
  173. package/dist/frontend/runtime-resolve.js.map +1 -0
  174. package/dist/frontend/runtime-resolve.test.d.ts +1 -0
  175. package/dist/frontend/runtime-resolve.test.js +18 -0
  176. package/dist/frontend/runtime-resolve.test.js.map +1 -0
  177. package/dist/frontend/ts7/adapter.js +12 -13
  178. package/dist/frontend/ts7/adapter.js.map +1 -1
  179. package/dist/frontend/ts7/ast.js.map +1 -1
  180. package/dist/frontend/ts7/census-check.js +3 -3
  181. package/dist/frontend/ts7/census-check.js.map +1 -1
  182. package/dist/frontend/ts7/checker.d.ts +3 -0
  183. package/dist/frontend/ts7/checker.js +12 -3
  184. package/dist/frontend/ts7/checker.js.map +1 -1
  185. package/dist/frontend/ts7/enums.js.map +1 -1
  186. package/dist/frontend/ts7/program-adapter.js +42 -3
  187. package/dist/frontend/ts7/program-adapter.js.map +1 -1
  188. package/dist/frontend/type-mapper.js +120 -7
  189. package/dist/frontend/type-mapper.js.map +1 -1
  190. package/dist/index.js +5 -5
  191. package/dist/index.js.map +1 -1
  192. package/dist/ir/analysis.js.map +1 -1
  193. package/dist/ir/ir.d.ts +60 -30
  194. package/dist/ir/ir.js +57 -6
  195. package/dist/ir/ir.js.map +1 -1
  196. package/dist/ir/validate.js +44 -59
  197. package/dist/ir/validate.js.map +1 -1
  198. package/dist/library/cache-primitives.js.map +1 -1
  199. package/dist/library/cache-reset.test.js.map +1 -1
  200. package/dist/library/compiler-self-identity.js.map +1 -1
  201. package/dist/library/int-infer.js.map +1 -1
  202. package/dist/library/int-infer.test.js.map +1 -1
  203. package/dist/library/library-profile.js.map +1 -1
  204. package/dist/library/sidecar-validate.js.map +1 -1
  205. package/dist/library/sidecar.js.map +1 -1
  206. package/dist/startup-cache.js.map +1 -1
  207. package/dist/wasi-paths.js.map +1 -1
  208. package/package.json +18 -18
  209. package/surface-manifest.json +60 -4
@@ -0,0 +1,1021 @@
1
+ import * as ts from "../../ts7/adapter.js";
2
+ import { BOOL, BYTES_U8, DYN, F64, STRING, UNDEFINED_T, VOID, arrayOf, bytesOf, typeEquals } from "../../../ir/ir.js";
3
+ import { locOf } from "../../program.js";
4
+ import { dynUndefinedExpr, own } from "../lowerer.js";
5
+ import { buildBytesSortFn } from "../lower-array-sort.js";
6
+ import { isSafeToDiscard } from "../expressions/evaluation-safety.js";
7
+ import { lowerDynObjectLiteral } from "../expressions/object-literals.js";
8
+ import { defaultAfterUndefined, lowerOptionalArgument, lowerStaticallyUndefinedArgument } from "../optional-arguments.js";
9
+ /** Uint8Array.prototype.toSorted. The receiver/comparator expressions are
10
+ * evaluated before entering the helper; the helper snapshots with
11
+ * TypedArray.prototype.slice before its first comparison, then performs
12
+ * the same stable merge walk as Array.toSorted. Uint8Array's default
13
+ * comparator is numeric ascending, so its comparator-less form needs no
14
+ * string-conversion machinery. */
15
+ function lowerBytesToSortedCall(lowerer, call, access, bytesT) {
16
+ const loc = locOf(call);
17
+ if (call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement)) {
18
+ lowerer.noLowering(`.toSorted with ${call.arguments.length} arguments on Uint8Array`, call);
19
+ }
20
+ const receiver = lowerer.lowerExpr(access.expression);
21
+ const undefinedArg = call.arguments[0]
22
+ ? lowerStaticallyUndefinedArgument(lowerer, call.arguments[0])
23
+ : null;
24
+ if (call.arguments.length === 0 || undefinedArg) {
25
+ const key = "bytes.toSorted:u8:default";
26
+ let helper = lowerer.arrHofHelpers.get(key);
27
+ if (!helper) {
28
+ helper = `%bytes.toSorted.${lowerer.arrHofHelpers.size}`;
29
+ lowerer.arrHofHelpers.set(key, helper);
30
+ lowerer.liftedFns.push(buildBytesSortFn(helper, 0, false, loc));
31
+ }
32
+ if (!undefinedArg || isSafeToDiscard(undefinedArg)) {
33
+ return { kind: "call", callee: helper, args: [receiver], type: bytesT, loc };
34
+ }
35
+ // The default helper takes no comparator argument. Snapshot the
36
+ // receiver into a hidden local so the discarded undefined argument
37
+ // still evaluates after the receiver and before the helper call.
38
+ const saved = lowerer.declareHiddenLocal("%bytesSortRecv", bytesT);
39
+ const savedRef = {
40
+ kind: "varRef",
41
+ localId: saved.id,
42
+ type: bytesT,
43
+ loc,
44
+ };
45
+ return {
46
+ kind: "seqExpr",
47
+ stmts: [
48
+ { kind: "varDecl", localId: saved.id, init: receiver, loc },
49
+ { kind: "exprStmt", expr: undefinedArg, loc: undefinedArg.loc },
50
+ ],
51
+ result: {
52
+ kind: "call",
53
+ callee: helper,
54
+ args: [savedRef],
55
+ type: bytesT,
56
+ loc,
57
+ },
58
+ type: bytesT,
59
+ loc,
60
+ };
61
+ }
62
+ const argNode = call.arguments[0];
63
+ const fnArg = lowerer.lowerExpr(argNode);
64
+ if (fnArg.type.kind !== "func" ||
65
+ fnArg.type.params.length > 2 ||
66
+ !fnArg.type.params.every((p) => p.kind === "f64") ||
67
+ fnArg.type.ret.kind !== "f64") {
68
+ lowerer.badType(argNode, lowerer.typeOf(argNode));
69
+ }
70
+ const arity = fnArg.type.params.length;
71
+ const key = `bytes.toSorted:u8:${arity}`;
72
+ let helper = lowerer.arrHofHelpers.get(key);
73
+ if (!helper) {
74
+ helper = `%bytes.toSorted.${lowerer.arrHofHelpers.size}`;
75
+ lowerer.arrHofHelpers.set(key, helper);
76
+ lowerer.liftedFns.push(buildBytesSortFn(helper, arity, true, loc));
77
+ }
78
+ return {
79
+ kind: "call",
80
+ callee: helper,
81
+ args: [receiver, fnArg],
82
+ type: bytesT,
83
+ loc,
84
+ };
85
+ }
86
+ /* ── typed arrays / Buffer ─────────────────────────────────────────────── */
87
+ /** The typed-array constructors with a runtime representation, by lib
88
+ * interface name. The other TypedArray flavors (Int8Array, Float64Array,
89
+ * DataView, ...) fall through to the generic stdlib-constructor fence. */
90
+ const BYTES_CTORS = {
91
+ Uint8Array: "u8",
92
+ Uint32Array: "u32",
93
+ Int32Array: "i32",
94
+ Float32Array: "f32",
95
+ };
96
+ /** `new Uint8Array(...)` / `new Uint32Array(...)` / `new Float32Array(...)`
97
+ * (stdlib provenance — a user's own class with the name resolves through
98
+ * classBySymbol). Lowered argument shapes: none (empty), a length
99
+ * (zero-filled; ToIndex at runtime — invalid lengths throw Node's
100
+ * RangeError), a same-kind typed array or Buffer (an independent COPY —
101
+ * the readFile chain's `new Uint8Array(await readFile(p))`), a number[]
102
+ * literal (element-coerced; its contextual type is the lib's
103
+ * ArrayLike/Iterable union, which cannot map — the Set-seed pattern), or
104
+ * a number[]-typed value. ArrayBuffer/view forms are fenced: scriptc
105
+ * typed arrays own their storage. Null when this isn't a stdlib
106
+ * typed-array construction. */
107
+ export function lowerBytesNew(lowerer, expr, symbol) {
108
+ if (symbol && symbol.name === "DataView" && lowerer.isStdlibSymbol(symbol)) {
109
+ return lowerDataViewNew(lowerer, expr);
110
+ }
111
+ const elem = symbol ? own(BYTES_CTORS, symbol.name) : undefined;
112
+ if (!elem || !symbol || !lowerer.isStdlibSymbol(symbol))
113
+ return null;
114
+ const name = symbol.name;
115
+ const type = bytesOf(elem);
116
+ const loc = locOf(expr);
117
+ const args = expr.arguments ?? [];
118
+ if (args.length === 0)
119
+ return { kind: "bytesNew", source: null, type, loc };
120
+ if (args.length === 1 && !ts.isSpreadElement(args[0])) {
121
+ const argNode = args[0];
122
+ if (ts.isArrayLiteralExpression(argNode) && !argNode.elements.some(ts.isSpreadElement)) {
123
+ const elems = argNode.elements.map((el) => lowerer.lowerExprExpecting(el, F64));
124
+ const seed = { kind: "arrayLit", elems, type: arrayOf(F64), loc };
125
+ return { kind: "bytesNew", source: seed, type, loc };
126
+ }
127
+ // The SYNTACTIC `new T(new ArrayBuffer(n))` and `new T(new
128
+ // SharedArrayBuffer(n))` forms — fresh-buffer construction (the
129
+ // shared spelling is the Atomics.wait sleep idiom's). The buffer
130
+ // never exists as a value: n must be a byte-length LITERAL divisible
131
+ // by the element size (tsc would admit any number; a bad one is
132
+ // Node's RangeError — rejected at compile time instead of
133
+ // half-lowering), and the whole expression is a zero-filled typed
134
+ // array of n/elemSize elements. Erasing the buffer is exact: nothing
135
+ // else can ever reference it, so neither sharing (scriptc has no
136
+ // threads) nor aliasing is observable — SEMANTICS.md documents the
137
+ // stance. The RESIZABLE form (a maxByteLength options bag) fences by
138
+ // name: resize needs the buffer to exist as a value, and none does.
139
+ if (ts.isNewExpression(argNode) &&
140
+ ts.isIdentifier(argNode.expression) &&
141
+ (argNode.expression.text === "ArrayBuffer" ||
142
+ argNode.expression.text === "SharedArrayBuffer") &&
143
+ lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(argNode.expression) ?? undefined)) {
144
+ const bufCtor = argNode.expression.text;
145
+ if ((argNode.arguments?.length ?? 0) > 1) {
146
+ lowerer.noLowering(`new ${name} over a resizable ${bufCtor}`, argNode, "a maxByteLength options bag makes the buffer resizable, and resizing needs the buffer " +
147
+ "to exist as a runtime value — no free-standing ArrayBuffer value exists (the buffer here " +
148
+ "erases into the view): drop the options bag");
149
+ }
150
+ const elemSize = elem === "u8" ? 1 : 4;
151
+ const lenArg = argNode.arguments?.length === 1 ? argNode.arguments[0] : undefined;
152
+ const lenT = lenArg ? lowerer.typeOf(lenArg) : null;
153
+ const byteLen = lenT?.isNumberLiteralType() ? lenT.value : null;
154
+ if (byteLen === null || byteLen % elemSize !== 0 || byteLen < 0) {
155
+ lowerer.noLowering(`new ${name} over this ${bufCtor}`, argNode, `the byte length must be a number literal divisible by ${elemSize} — new ${name}(new ${bufCtor}(${elemSize}))`);
156
+ }
157
+ const count = { kind: "numLit", value: byteLen / elemSize, type: F64, loc };
158
+ return { kind: "bytesNew", source: count, type, loc };
159
+ }
160
+ const src = lowerer.lowerExpr(argNode);
161
+ if (src.type.kind === "union" && lowerer.armTag(src.type.unionId, UNDEFINED_T) >= 0) {
162
+ const present = lowerer.stripUndefinedArm(src.type);
163
+ if (present.kind === "array" && present.elem.kind === "f64") {
164
+ const undefTag = lowerer.armTag(src.type.unionId, UNDEFINED_T);
165
+ const presentTag = lowerer.armTag(src.type.unionId, present);
166
+ if (undefTag >= 0 && presentTag >= 0) {
167
+ const empty = { kind: "arrayLit", elems: [], type: present, loc };
168
+ const source = {
169
+ kind: "ternary",
170
+ cond: { kind: "unionIsTag", unionId: src.type.unionId, tag: undefTag, negated: false, value: src, type: BOOL, loc },
171
+ then: empty,
172
+ else_: { kind: "unionNarrow", unionId: src.type.unionId, tag: presentTag, value: src, type: present, loc },
173
+ type: present,
174
+ loc,
175
+ };
176
+ return { kind: "bytesNew", source, type, loc };
177
+ }
178
+ }
179
+ }
180
+ if (src.type.kind === "f64" ||
181
+ typeEquals(src.type, type) ||
182
+ (src.type.kind === "array" && src.type.elem.kind === "f64")) {
183
+ return { kind: "bytesNew", source: src, type, loc };
184
+ }
185
+ if (src.type.kind === "bytes") {
186
+ lowerer.noLowering(`new ${name} over a '${lowerer.fmt(src.type)}'`, argNode, "cross-kind typed-array conversion has no lowering — copy element by element");
187
+ }
188
+ lowerer.noLowering(`new ${name} over '${lowerer.fmt(src.type)}' values`, argNode, `supported: new ${name}(), (length), (typedArray) — always a copy — or (number[]); ` +
189
+ "ArrayBuffers and views do not exist here (narrow unions first)");
190
+ }
191
+ lowerer.noLowering(`new ${name} with ${args.length} arguments`, expr, `supported: new ${name}(), (length), (typedArray), or (number[])`);
192
+ }
193
+ /** `new DataView(x.buffer, byteOffset?, byteLength?)` (stdlib provenance).
194
+ * The first argument must be the SYNTACTIC `.buffer` of a typed-array/
195
+ * Buffer value — `x.buffer` names x's own storage (scriptc typed arrays
196
+ * always own it whole, byteOffset 0), so the view construction takes x
197
+ * itself as the receiver and no ArrayBuffer value ever exists.
198
+ * byteOffset/byteLength are optional f64s (omitted args OMITTED, like
199
+ * slice); bad indices THROW Node's RangeErrors catchably. The result is
200
+ * a true borrowed view: reads and writes through it alias x. */
201
+ function lowerDataViewNew(lowerer, expr) {
202
+ const loc = locOf(expr);
203
+ const args = expr.arguments ?? [];
204
+ const bufNode = args[0];
205
+ if (!bufNode || args.length > 3 || args.some(ts.isSpreadElement)) {
206
+ lowerer.noLowering(`new DataView with ${args.length} arguments`, expr, "supported: new DataView(x.buffer), (x.buffer, byteOffset), or (x.buffer, byteOffset, byteLength)");
207
+ }
208
+ // The FRESH-BUFFER form: `new DataView(new ArrayBuffer(n), ...)` — the
209
+ // buffer erases into the view (nothing else can ever reference it, so
210
+ // the aliasing a shared buffer would exhibit is unobservable): the
211
+ // view's storage is a fresh zero-filled n-byte allocation. n must be a
212
+ // non-negative integer LITERAL (tsc admits any number; a fractional
213
+ // one is ToIndex truncation nothing here implements). byteOffset and
214
+ // byteLength keep their runtime Node-RangeError story. The RESIZABLE
215
+ // form (a maxByteLength options bag) fences by name.
216
+ if (ts.isNewExpression(bufNode) &&
217
+ ts.isIdentifier(bufNode.expression) &&
218
+ bufNode.expression.text === "ArrayBuffer" &&
219
+ lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(bufNode.expression) ?? undefined)) {
220
+ if ((bufNode.arguments?.length ?? 0) > 1) {
221
+ lowerer.noLowering("new DataView over a resizable ArrayBuffer", bufNode, "a maxByteLength options bag makes the buffer resizable, and resizing needs the buffer " +
222
+ "to exist as a runtime value — no free-standing ArrayBuffer value exists (the buffer here " +
223
+ "erases into the view): drop the options bag");
224
+ }
225
+ const lenArg = bufNode.arguments?.length === 1 ? bufNode.arguments[0] : undefined;
226
+ const lenT = lenArg ? lowerer.typeOf(lenArg) : null;
227
+ const byteLen = lenT?.isNumberLiteralType() ? lenT.value : null;
228
+ if (byteLen === null || !Number.isInteger(byteLen) || byteLen < 0) {
229
+ lowerer.noLowering("new DataView over this ArrayBuffer", bufNode, "the byte length must be a non-negative integer literal — new DataView(new ArrayBuffer(8))");
230
+ }
231
+ const count = { kind: "numLit", value: byteLen, type: F64, loc };
232
+ const receiver = { kind: "bytesNew", source: count, type: BYTES_U8, loc };
233
+ const idxArgs = args.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
234
+ return { kind: "bytesIntrinsic", method: "dataViewNew", receiver, args: idxArgs, type: BYTES_U8, loc };
235
+ }
236
+ const hint = "views compile over a typed array's own storage — new DataView(x.buffer, byteOffset?, byteLength?) " +
237
+ "where x is a Uint8Array/Uint32Array/Float32Array/Buffer value — or a fresh buffer erased into " +
238
+ "the view: new DataView(new ArrayBuffer(n), ...); free-standing ArrayBuffers have no representation";
239
+ if (!ts.isPropertyAccessExpression(bufNode) || bufNode.name.text !== "buffer" || bufNode.questionDotToken) {
240
+ lowerer.noLowering("new DataView over this buffer expression", bufNode, hint);
241
+ }
242
+ const srcIr = lowerer.mapTypeOf(lowerer.typeOf(bufNode.expression));
243
+ if (srcIr?.kind !== "bytes" || !lowerer.isStdlibMember(bufNode)) {
244
+ lowerer.noLowering(`new DataView over '.buffer' of a '${lowerer.checker.typeToString(lowerer.typeOf(bufNode.expression))}'`, bufNode, hint);
245
+ }
246
+ const receiver = lowerer.lowerExpr(bufNode.expression);
247
+ const idxArgs = args.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
248
+ return { kind: "bytesIntrinsic", method: "dataViewNew", receiver, args: idxArgs, type: BYTES_U8, loc };
249
+ }
250
+ /** Method calls on typed-array/Buffer receivers: slice and subarray (BOTH
251
+ * copy — subarray's sharing is the documented divergence), set(src,
252
+ * offset?), and the u8-only Buffer surface: toString(enc?) plus the
253
+ * whole numeric read/write family (fixed widths BE/LE and the
254
+ * variable-width read/writeUIntLE quartet — BUF_NUM_METHODS). Everything
255
+ * else the lib declares (fill, indexOf, reverse, ...) falls through to
256
+ * the SC2020 member fence. Null when this isn't a bytes method call. */
257
+ export function lowerBytesMethodCall(lowerer, call, access) {
258
+ if (lowerer.chainBlocked(access, call))
259
+ return null;
260
+ const name = access.name.text;
261
+ const receiverIr = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
262
+ if (receiverIr?.kind !== "bytes")
263
+ return null;
264
+ if (!lowerer.isStdlibMember(access))
265
+ return null;
266
+ const loc = locOf(call);
267
+ const nArgs = call.arguments.length;
268
+ if (receiverIr.elem === "u8" && name === "toSorted") {
269
+ return lowerBytesToSortedCall(lowerer, call, access, receiverIr);
270
+ }
271
+ if (receiverIr.elem === "u8" && name === "toReversed") {
272
+ if (nArgs !== 0) {
273
+ lowerer.noLowering(`.toReversed with ${nArgs} arguments on Uint8Array`, call);
274
+ }
275
+ return {
276
+ kind: "bytesIntrinsic",
277
+ method: "toReversed",
278
+ receiver: lowerer.lowerExpr(access.expression),
279
+ args: [],
280
+ type: receiverIr,
281
+ loc,
282
+ };
283
+ }
284
+ if (receiverIr.elem === "u8" && name === "with") {
285
+ if (nArgs !== 2 || call.arguments.some(ts.isSpreadElement)) {
286
+ lowerer.noLowering(`.with with ${nArgs} arguments on Uint8Array`, call);
287
+ }
288
+ return {
289
+ kind: "bytesIntrinsic",
290
+ method: "with",
291
+ receiver: lowerer.lowerExpr(access.expression),
292
+ args: [
293
+ lowerer.lowerExprExpecting(call.arguments[0], F64),
294
+ lowerer.lowerExprExpecting(call.arguments[1], F64),
295
+ ],
296
+ type: receiverIr,
297
+ loc,
298
+ };
299
+ }
300
+ if (receiverIr.elem === "u8" && name === "join") {
301
+ if (nArgs > 1 || call.arguments.some(ts.isSpreadElement)) {
302
+ lowerer.noLowering(`.join with ${nArgs} arguments on Uint8Array`, call);
303
+ }
304
+ const separatorDefault = {
305
+ kind: "strLit",
306
+ value: ",",
307
+ type: STRING,
308
+ loc,
309
+ };
310
+ const separator = call.arguments[0]
311
+ ? lowerOptionalArgument(lowerer, call.arguments[0], STRING, separatorDefault)
312
+ : separatorDefault;
313
+ return {
314
+ kind: "bytesIntrinsic",
315
+ method: "join",
316
+ receiver: lowerer.lowerExpr(access.expression),
317
+ args: [separator],
318
+ type: STRING,
319
+ loc,
320
+ };
321
+ }
322
+ if (name === "slice" || name === "subarray") {
323
+ if (nArgs > 2) {
324
+ lowerer.noLowering(`.${name} with ${nArgs} arguments on typed arrays`, call);
325
+ }
326
+ const receiver = lowerer.lowerExpr(access.expression);
327
+ const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, F64));
328
+ // subarray is a VIEW (TypedArray.prototype.subarray aliases), and
329
+ // Buffer's slice() is subarray's deprecated Node alias — resolved by
330
+ // where the member is declared, the toString discipline below. Only
331
+ // the plain typed arrays' slice() copies (JS-exact).
332
+ const declaredOnBuffer = name === "slice" &&
333
+ (() => {
334
+ const nameSym = lowerer.checker.getSymbolAtLocation(access.name);
335
+ return nameSym !== undefined && lowerer.checker.declarationsOf(nameSym).some((d) => ts.isInterfaceDeclaration(d.parent) && d.parent.name.text === "Buffer");
336
+ })();
337
+ const method = name === "subarray" || declaredOnBuffer ? "subarray" : "slice";
338
+ return { kind: "bytesIntrinsic", method, receiver, args, type: receiverIr, loc };
339
+ }
340
+ if (name === "fill" && receiverIr.elem !== "u8") {
341
+ // TypedArray.prototype.fill on the non-u8 kinds: per-element value
342
+ // coercion, slice-clamped relative indices, never throws. u8
343
+ // receivers keep the Buffer fill family (string patterns, throwing
344
+ // offset validation) — lowerBufferInstanceMethod's surface.
345
+ if (nArgs < 1 || nArgs > 3) {
346
+ lowerer.noLowering(`.fill with ${nArgs} arguments on typed arrays`, call);
347
+ }
348
+ const receiver = lowerer.lowerExpr(access.expression);
349
+ const v = lowerer.lowerExprExpecting(call.arguments[0], F64);
350
+ const idx = call.arguments.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
351
+ return { kind: "bytesIntrinsic", method: "fillElem", receiver, args: [v, ...idx], type: receiverIr, loc };
352
+ }
353
+ if (name === "set") {
354
+ if (nArgs < 1 || nArgs > 2) {
355
+ lowerer.noLowering(`.set with ${nArgs} arguments on typed arrays`, call);
356
+ }
357
+ const receiver = lowerer.lowerExpr(access.expression);
358
+ const src = lowerer.lowerExpr(call.arguments[0]);
359
+ if (!typeEquals(src.type, receiverIr)) {
360
+ lowerer.noLowering(`.set from '${lowerer.fmt(src.type)}' values`, call.arguments[0], "only a same-kind typed array copies in (number[] sources have no lowering — narrow unions first)");
361
+ }
362
+ const args = [src];
363
+ if (nArgs === 2)
364
+ args.push(lowerer.lowerExprExpecting(call.arguments[1], F64));
365
+ return { kind: "bytesIntrinsic", method: "setFrom", receiver, args, type: VOID, loc };
366
+ }
367
+ if (name === "toString") {
368
+ // Buffer's toString(encoding?) — utf8 by default. A 0-arg toString
369
+ // resolved against the plain Uint8Array interface is JS's
370
+ // Array-toString (comma join), a different operation: fenced.
371
+ const declaredOnBuffer = (() => {
372
+ const nameSym = lowerer.checker.getSymbolAtLocation(access.name);
373
+ return nameSym !== undefined && lowerer.checker.declarationsOf(nameSym).some((d) => ts.isInterfaceDeclaration(d.parent) && d.parent.name.text === "Buffer");
374
+ })();
375
+ if (receiverIr.elem !== "u8" || !declaredOnBuffer) {
376
+ lowerer.noLowering("typed-array toString", call, 'Buffer.from(x).toString("utf8" | "hex" | "base64") is the lowered string conversion');
377
+ }
378
+ if (nArgs > 3)
379
+ lowerer.noLowering(`.toString with ${nArgs} arguments on Buffers`, call);
380
+ const receiver = lowerer.lowerExpr(access.expression);
381
+ const encNode = call.arguments[0];
382
+ let method = "toString";
383
+ let enc = { kind: "strLit", value: "utf8", type: STRING, loc };
384
+ if (encNode) {
385
+ const encType = lowerer.typeOf(encNode);
386
+ const encName = encType.isStringLiteralType()
387
+ ? knownBufEncoding(encType.value)
388
+ : undefined;
389
+ if (encName !== undefined) {
390
+ // Keep literals on the canonical, non-throwing fast path.
391
+ enc = { kind: "strLit", value: encName, type: STRING, loc };
392
+ }
393
+ else {
394
+ const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, encNode);
395
+ if (undefinedArg) {
396
+ // An explicit undefined is the omitted-encoding default. Keep
397
+ // the canonical, non-throwing path while preserving effects
398
+ // from equivalent spellings such as `void sideEffect()`.
399
+ enc = defaultAfterUndefined(undefinedArg, enc);
400
+ }
401
+ else {
402
+ // A BufferEncoding-typed variable selects its decoder at
403
+ // runtime. Optional variables default their undefined arm to
404
+ // utf8; the checked intrinsic canonicalizes every present
405
+ // alias/case and raises Node's ERR_UNKNOWN_ENCODING when a cast
406
+ // lets a bad value through.
407
+ enc = lowerOptionalArgument(lowerer, encNode, STRING, enc);
408
+ method = "toStringVar";
409
+ }
410
+ }
411
+ }
412
+ // The range form toString(enc, start[, end]) decodes the clamped
413
+ // [start, end) byte window (Node's slice-then-decode). An omitted
414
+ // end stays omitted (2 intrinsic args) — the emitter supplies the
415
+ // receiver's length, because EXPLICIT negative ends clamp to empty
416
+ // in Node and no in-band sentinel can represent "omitted" safely.
417
+ if (nArgs > 1) {
418
+ const start = lowerer.lowerExprExpecting(call.arguments[1], F64);
419
+ if (nArgs === 3) {
420
+ const end = lowerer.lowerExprExpecting(call.arguments[2], F64);
421
+ return { kind: "bytesIntrinsic", method, receiver, args: [enc, start, end], type: STRING, loc };
422
+ }
423
+ return { kind: "bytesIntrinsic", method, receiver, args: [enc, start], type: STRING, loc };
424
+ }
425
+ return { kind: "bytesIntrinsic", method, receiver, args: [enc], type: STRING, loc };
426
+ }
427
+ // The Buffer-declared comparison/search/mutation surface. All of
428
+ // these resolve against the Buffer interface (the checker keeps most
429
+ // off plain typed arrays; where the lib DOES declare a same-named
430
+ // TypedArray member — indexOf, includes, fill — the semantics differ,
431
+ // so only Buffer-declared resolutions lower and u8 receivers gate the
432
+ // rest).
433
+ const declOnBuffer = (() => {
434
+ const nameSym = lowerer.checker.getSymbolAtLocation(access.name);
435
+ return nameSym !== undefined && lowerer.checker.declarationsOf(nameSym).some((d) => ts.isInterfaceDeclaration(d.parent) && d.parent.name.text === "Buffer");
436
+ })();
437
+ if (declOnBuffer && receiverIr.elem === "u8") {
438
+ const bufMethod = lowerBufferInstanceMethod(lowerer, call, access, name, loc);
439
+ if (bufMethod)
440
+ return bufMethod;
441
+ }
442
+ // The Buffer numeric read/write families — every fixed-width kind in
443
+ // both endiannesses ("Uint" and "UInt" alike: Node aliases both), plus
444
+ // the variable-width read/writeUIntLE quartet. The kind token rides as
445
+ // a strLit args[0]; omitted offsets complete to Node's default 0.
446
+ const numKind = own(BUF_NUM_METHODS, name);
447
+ if (numKind !== undefined) {
448
+ if (receiverIr.elem !== "u8") {
449
+ lowerer.noLowering(`.${name} on a '${lowerer.fmt(receiverIr)}'`, call, "the numeric families read/write Buffer bytes");
450
+ }
451
+ const write = name.startsWith("write");
452
+ const required = write ? 1 : 0; // value; offset defaults to 0
453
+ if (nArgs < required || nArgs > required + 1) {
454
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
455
+ }
456
+ const receiver = lowerer.lowerExpr(access.expression);
457
+ const kind = { kind: "strLit", value: numKind, type: STRING, loc };
458
+ const args = [kind, ...call.arguments.map((a) => lowerer.lowerExprExpecting(a, F64))];
459
+ if (nArgs === required) {
460
+ args.push({ kind: "numLit", value: 0, type: F64, loc }); // Node's offset default
461
+ }
462
+ return { kind: "bytesIntrinsic", method: write ? "writeNum" : "readNum", receiver, args, type: F64, loc };
463
+ }
464
+ const varKind = own(BUF_NUM_VAR_METHODS, name);
465
+ if (varKind !== undefined) {
466
+ if (receiverIr.elem !== "u8") {
467
+ lowerer.noLowering(`.${name} on a '${lowerer.fmt(receiverIr)}'`, call, "the numeric families read/write Buffer bytes");
468
+ }
469
+ const write = name.startsWith("write");
470
+ const required = write ? 3 : 2; // Node declares offset AND byteLength required
471
+ if (nArgs !== required) {
472
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
473
+ }
474
+ const receiver = lowerer.lowerExpr(access.expression);
475
+ const kind = { kind: "strLit", value: varKind, type: STRING, loc };
476
+ const args = [kind, ...call.arguments.map((a) => lowerer.lowerExprExpecting(a, F64))];
477
+ return { kind: "bytesIntrinsic", method: write ? "writeNumVar" : "readNumVar", receiver, args, type: F64, loc };
478
+ }
479
+ // DataView getters (DataView maps to bytes<u8>, so the receiver kind
480
+ // and stdlib provenance land here; the checker keeps these names off
481
+ // typed arrays and Buffers). The multi-byte kinds take the optional
482
+ // littleEndian bool (omitted = big-endian, the JS default). All THROW
483
+ // Node's RangeError on a bad offset (may-throw seeds).
484
+ const dvGetter = own(DV_GETTERS, name);
485
+ if (dvGetter !== undefined && receiverIr.elem === "u8") {
486
+ if (dvGetter.method === "dvGetBigUint64Number" || dvGetter.method === "dvGetBigInt64Number") {
487
+ // bigint values have no representation — only the COMPOSED
488
+ // `Number(view.getBigUint64/getBigInt64(...))` compiles (the
489
+ // randomBytesToString pattern): the 8-byte integer converts to
490
+ // double exactly as Number(bigint) would, and the bigint never
491
+ // exists as a value (the f64-typed intrinsic result IS what the
492
+ // identity Number(f64) lowering hands back).
493
+ const p = call.parent;
494
+ const composed = ts.isCallExpression(p) &&
495
+ p.arguments.length === 1 &&
496
+ p.arguments[0] === call &&
497
+ ts.isIdentifier(p.expression) &&
498
+ p.expression.text === "Number" &&
499
+ lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(p.expression) ?? undefined);
500
+ if (!composed) {
501
+ lowerer.noLowering(`.${name} outside Number(...)`, call, `bigint values have no representation — Number(view.${name}(offset, littleEndian?)) is the lowered form`);
502
+ }
503
+ }
504
+ const maxArgs = dvGetter.le ? 2 : 1;
505
+ if (nArgs < 1 || nArgs > maxArgs) {
506
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
507
+ }
508
+ const receiver = lowerer.lowerExpr(access.expression);
509
+ const args = [lowerer.lowerExprExpecting(call.arguments[0], F64)];
510
+ if (nArgs === 2)
511
+ args.push(lowerer.lowerExprExpecting(call.arguments[1], BOOL));
512
+ return { kind: "bytesIntrinsic", method: dvGetter.method, receiver, args, type: F64, loc };
513
+ }
514
+ // DataView setters — the getters' mirror: (byteOffset, value) plus the
515
+ // optional littleEndian bool on the multi-byte kinds. Void results;
516
+ // the same constant Node RangeError on a bad offset (may-throw seeds).
517
+ // setBigUint64/setBigInt64 never lower (bigint ARGUMENTS have no
518
+ // representation and no composed form exists) — they keep the member
519
+ // fence, as does setFloat16.
520
+ const dvSetter = own(DV_SETTERS, name);
521
+ if (dvSetter !== undefined && receiverIr.elem === "u8") {
522
+ const maxArgs = dvSetter.le ? 3 : 2;
523
+ if (nArgs < 2 || nArgs > maxArgs) {
524
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
525
+ }
526
+ const receiver = lowerer.lowerExpr(access.expression);
527
+ const args = [
528
+ lowerer.lowerExprExpecting(call.arguments[0], F64),
529
+ lowerer.lowerExprExpecting(call.arguments[1], F64),
530
+ ];
531
+ if (nArgs === 3)
532
+ args.push(lowerer.lowerExprExpecting(call.arguments[2], BOOL));
533
+ return { kind: "bytesIntrinsic", method: dvSetter.method, receiver, args, type: VOID, loc };
534
+ }
535
+ return null;
536
+ }
537
+ /** Node's Buffer encoding names → the runtime's canonical spelling (every
538
+ * alias folds at compile time; the runtime sees only canonical names).
539
+ * Shared by toString, Buffer.from, and Buffer.byteLength. */
540
+ const BUF_ENCODINGS = {
541
+ utf8: "utf8",
542
+ "utf-8": "utf8",
543
+ hex: "hex",
544
+ base64: "base64",
545
+ base64url: "base64url",
546
+ latin1: "latin1",
547
+ binary: "latin1",
548
+ ascii: "ascii",
549
+ utf16le: "utf16le",
550
+ "utf-16le": "utf16le",
551
+ ucs2: "utf16le",
552
+ "ucs-2": "utf16le",
553
+ };
554
+ /** A literal encoding's canonical name, or undefined for a spelling Node
555
+ * does not know — the ladder callers (stream options) turn unknown
556
+ * literals into Node's runtime ERR_UNKNOWN_ENCODING throw. */
557
+ export function knownBufEncoding(name) {
558
+ return own(BUF_ENCODINGS, name);
559
+ }
560
+ /** The literal encoding argument of a Buffer surface, normalized — or a
561
+ * fence when it isn't a literal alias Node knows. */
562
+ export function bufEncoding(lowerer, what, encNode) {
563
+ const t = lowerer.typeOf(encNode);
564
+ const v = t.isStringLiteralType() ? own(BUF_ENCODINGS, t.value) : undefined;
565
+ if (v === undefined) {
566
+ lowerer.noLowering(`${what} with this encoding`, encNode, 'a literal "utf8", "hex", "base64", "base64url", "latin1", "binary", "ascii", "utf16le", or "ucs2" spelling is the lowered encoding surface');
567
+ }
568
+ return v;
569
+ }
570
+ /** The fixed-width Buffer numeric methods by source name → the readNum/
571
+ * writeNum kind token. Node declares BOTH capitalizations ("UInt" is the
572
+ * original, "Uint" the aliased spelling) — the tables carry both. */
573
+ const BUF_NUM_METHODS = (() => {
574
+ const out = {};
575
+ for (const rw of ["read", "write"]) {
576
+ for (const u of ["UInt", "Uint"]) {
577
+ out[`${rw}${u}8`] = "u8";
578
+ out[`${rw}${u}16BE`] = "u16be";
579
+ out[`${rw}${u}16LE`] = "u16le";
580
+ out[`${rw}${u}32BE`] = "u32be";
581
+ out[`${rw}${u}32LE`] = "u32le";
582
+ }
583
+ out[`${rw}Int8`] = "i8";
584
+ out[`${rw}Int16BE`] = "i16be";
585
+ out[`${rw}Int16LE`] = "i16le";
586
+ out[`${rw}Int32BE`] = "i32be";
587
+ out[`${rw}Int32LE`] = "i32le";
588
+ out[`${rw}FloatBE`] = "f32be";
589
+ out[`${rw}FloatLE`] = "f32le";
590
+ out[`${rw}DoubleBE`] = "f64be";
591
+ out[`${rw}DoubleLE`] = "f64le";
592
+ }
593
+ return out;
594
+ })();
595
+ /** The variable-width quartet (offset + byteLength) → sign/endian token. */
596
+ const BUF_NUM_VAR_METHODS = {
597
+ readUIntBE: "ube",
598
+ readUintBE: "ube",
599
+ readUIntLE: "ule",
600
+ readUintLE: "ule",
601
+ readIntBE: "ibe",
602
+ readIntLE: "ile",
603
+ writeUIntBE: "ube",
604
+ writeUintBE: "ube",
605
+ writeUIntLE: "ule",
606
+ writeUintLE: "ule",
607
+ writeIntBE: "ibe",
608
+ writeIntLE: "ile",
609
+ };
610
+ /** The Buffer-declared comparison/search/mutation methods on a u8
611
+ * receiver: equals, compare, indexOf/lastIndexOf/includes (number,
612
+ * string-with-encoding, and Buffer needles), fill, copy, swap16/32/64,
613
+ * and write. Null when `name` isn't one of them (the numeric families
614
+ * and the generic bytes surface try next). Encodings must be literals
615
+ * (bufEncoding's fence); a trailing string-typed argument is the
616
+ * encoding, exactly Node's overloads. */
617
+ function lowerBufferInstanceMethod(lowerer, call, access, name, loc) {
618
+ const args = call.arguments;
619
+ const nArgs = args.length;
620
+ if (args.some(ts.isSpreadElement))
621
+ return null;
622
+ const isStringArg = (i) => lowerer.mapTypeOf(lowerer.typeOf(args[i]))?.kind === "string";
623
+ const u8Arg = (i) => {
624
+ const v = lowerer.lowerExpr(args[i]);
625
+ if (!(v.type.kind === "bytes" && v.type.elem === "u8")) {
626
+ lowerer.noLowering(`.${name} of '${lowerer.fmt(v.type)}' values`, args[i], "a Buffer/Uint8Array argument is the lowered shape (narrow unions first)");
627
+ }
628
+ return v;
629
+ };
630
+ // The checked-dynamic crossing for a compare/equals argument slot: dyn
631
+ // passes through, convertible statics (the invalid-input probes'
632
+ // literals) wrap in dynFrom, `undefined` literals ride the same wrap.
633
+ // Fences (never returns) when the value cannot cross — an island jsval.
634
+ const chkArg = (i) => {
635
+ // Object literals take the dyn literal path directly (method members
636
+ // box as dyn functions — the typed record fence never applies).
637
+ if (ts.isObjectLiteralExpression(args[i])) {
638
+ return lowerDynObjectLiteral(lowerer, args[i]);
639
+ }
640
+ const v = lowerer.lowerExpr(args[i]);
641
+ if (v.type.kind === "dyn")
642
+ return v;
643
+ if (v.kind === "unitLit" || lowerer.dynConvertible(v.type)) {
644
+ return { kind: "dynFrom", value: v, type: DYN, loc: v.loc };
645
+ }
646
+ lowerer.noLowering(`.${name} of '${lowerer.fmt(v.type)}' values`, args[i], "a Buffer/Uint8Array argument is the lowered shape (narrow unions first)");
647
+ };
648
+ const argIrKind = (i) => lowerer.mapTypeOf(lowerer.typeOf(args[i]));
649
+ if (name === "equals") {
650
+ if (nArgs !== 1)
651
+ lowerer.noLowering(`.equals with ${nArgs} arguments`, call);
652
+ if (argIrKind(0)?.kind === "bytes") {
653
+ const other = u8Arg(0);
654
+ const receiver = lowerer.lowerExpr(access.expression);
655
+ return { kind: "bytesIntrinsic", method: "equals", receiver, args: [other], type: BOOL, loc };
656
+ }
657
+ // Not statically bytes (the invalid-input probes, untyped JS
658
+ // helpers): Node's "otherBuffer" argument ladder runs at runtime.
659
+ const receiver = lowerer.lowerExpr(access.expression);
660
+ return { kind: "libCall", fn: "bytes.equalsChk", args: [receiver, chkArg(0)], type: BOOL, loc };
661
+ }
662
+ if (name === "compare") {
663
+ if (nArgs > 5)
664
+ lowerer.noLowering(`.compare with ${nArgs} arguments`, call);
665
+ const fast = nArgs >= 1 &&
666
+ argIrKind(0)?.kind === "bytes" &&
667
+ call.arguments.slice(1).every((a) => lowerer.mapTypeOf(lowerer.typeOf(a))?.kind === "f64");
668
+ if (fast) {
669
+ const target = u8Arg(0);
670
+ const idx = call.arguments.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
671
+ const receiver = lowerer.lowerExpr(access.expression);
672
+ return { kind: "bytesIntrinsic", method: "compareBuf", receiver, args: [target, ...idx], type: F64, loc };
673
+ }
674
+ // An absent/ill-typed target or offset (`a.compare()`, string
675
+ // offsets, explicit undefined): Node's target/targetStart/targetEnd/
676
+ // sourceStart/sourceEnd ladder runs at runtime; absent slots pass
677
+ // the undefined dyn (Node defaults apply there).
678
+ const receiver = lowerer.lowerExpr(access.expression);
679
+ const slots = [];
680
+ for (let i = 0; i < 5; i++)
681
+ slots.push(i < nArgs ? chkArg(i) : dynUndefinedExpr(loc));
682
+ return { kind: "libCall", fn: "bytes.compareChk", args: [receiver, ...slots], type: F64, loc };
683
+ }
684
+ if (name === "indexOf" || name === "lastIndexOf" || name === "includes") {
685
+ if (nArgs < 1 || nArgs > 3)
686
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
687
+ // The overloads: (v), (v, byteOffset), (v, encoding), (v, byteOffset,
688
+ // encoding) — a trailing string-typed arg is the encoding.
689
+ let encName = "utf8";
690
+ let offNode;
691
+ if (nArgs === 3) {
692
+ offNode = args[1];
693
+ encName = bufEncoding(lowerer, `.${name}`, args[2]);
694
+ }
695
+ else if (nArgs === 2) {
696
+ if (isStringArg(1))
697
+ encName = bufEncoding(lowerer, `.${name}`, args[1]);
698
+ else
699
+ offNode = args[1];
700
+ }
701
+ const resultT = name === "includes" ? BOOL : F64;
702
+ const vT = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
703
+ const receiver = lowerer.lowerExpr(access.expression);
704
+ if (vT?.kind === "f64") {
705
+ // A number needle wraps & 0xFF at runtime (Buffer semantics; the
706
+ // encoding is irrelevant, like Node).
707
+ const v = lowerer.lowerExprExpecting(args[0], F64);
708
+ const numArgs = [v, ...(offNode ? [lowerer.lowerExprExpecting(offNode, F64)] : [])];
709
+ const method = name === "indexOf" ? "indexOfNum" : name === "lastIndexOf" ? "lastIndexOfNum" : "includesNum";
710
+ return { kind: "bytesIntrinsic", method, receiver, args: numArgs, type: resultT, loc };
711
+ }
712
+ let needle;
713
+ let align = 1;
714
+ if (vT?.kind === "string") {
715
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
716
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
717
+ needle = { kind: "libCall", fn: "buffer.fromStr", args: [s, enc], type: BYTES_U8, loc };
718
+ if (encName === "utf16le")
719
+ align = 2;
720
+ }
721
+ else if (vT?.kind === "bytes" && vT.elem === "u8") {
722
+ needle = lowerer.lowerExpr(args[0]);
723
+ }
724
+ else {
725
+ lowerer.noLowering(`.${name} of '${lowerer.checker.typeToString(lowerer.typeOf(args[0]))}' values`, args[0], "string, number, and Buffer/Uint8Array needles search (narrow unions first)");
726
+ }
727
+ const alignLit = { kind: "numLit", value: align, type: F64, loc };
728
+ const searchArgs = [needle, alignLit, ...(offNode ? [lowerer.lowerExprExpecting(offNode, F64)] : [])];
729
+ return { kind: "bytesIntrinsic", method: name, receiver, args: searchArgs, type: resultT, loc };
730
+ }
731
+ if (name === "fill") {
732
+ if (nArgs < 1 || nArgs > 4)
733
+ lowerer.noLowering(`.fill with ${nArgs} arguments`, call);
734
+ // A trailing string-typed arg past the value is the encoding.
735
+ let encNode;
736
+ let idxNodes = call.arguments.slice(1);
737
+ if (idxNodes.length > 0 && isStringArg(nArgs - 1)) {
738
+ encNode = idxNodes[idxNodes.length - 1];
739
+ idxNodes = idxNodes.slice(0, -1);
740
+ }
741
+ if (idxNodes.length > 2)
742
+ lowerer.noLowering(`.fill with ${nArgs} arguments`, call);
743
+ const idx = idxNodes.map((a) => lowerer.lowerExprExpecting(a, F64));
744
+ const receiverT = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
745
+ if (receiverT?.kind !== "bytes")
746
+ lowerer.badType(access.expression, lowerer.typeOf(access.expression));
747
+ const vT = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
748
+ const receiver = lowerer.lowerExpr(access.expression);
749
+ if (vT?.kind === "string") {
750
+ const encName = encNode ? bufEncoding(lowerer, ".fill", encNode) : "utf8";
751
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
752
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
753
+ return { kind: "bytesIntrinsic", method: "fillStr", receiver, args: [s, enc, ...idx], type: BYTES_U8, loc };
754
+ }
755
+ if (encNode)
756
+ lowerer.noLowering(".fill with an encoding on a non-string value", encNode);
757
+ if (vT?.kind === "f64") {
758
+ const v = lowerer.lowerExprExpecting(args[0], F64);
759
+ return { kind: "bytesIntrinsic", method: "fillNum", receiver, args: [v, ...idx], type: BYTES_U8, loc };
760
+ }
761
+ const pattern = u8Arg(0);
762
+ return { kind: "bytesIntrinsic", method: "fill", receiver, args: [pattern, ...idx], type: BYTES_U8, loc };
763
+ }
764
+ if (name === "copy") {
765
+ if (nArgs < 1 || nArgs > 4)
766
+ lowerer.noLowering(`.copy with ${nArgs} arguments`, call);
767
+ const target = u8Arg(0);
768
+ const idx = call.arguments.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
769
+ const receiver = lowerer.lowerExpr(access.expression);
770
+ return { kind: "bytesIntrinsic", method: "copy", receiver, args: [target, ...idx], type: F64, loc };
771
+ }
772
+ if (name === "swap16" || name === "swap32" || name === "swap64") {
773
+ if (nArgs !== 0)
774
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
775
+ const receiver = lowerer.lowerExpr(access.expression);
776
+ return { kind: "bytesIntrinsic", method: name, receiver, args: [], type: BYTES_U8, loc };
777
+ }
778
+ if (name === "write") {
779
+ if (nArgs < 1 || nArgs > 4)
780
+ lowerer.noLowering(`.write with ${nArgs} arguments`, call);
781
+ // (str), (str, enc), (str, offset), (str, offset, enc),
782
+ // (str, offset, length), (str, offset, length, enc).
783
+ let encNode;
784
+ let idxNodes = call.arguments.slice(1);
785
+ if (idxNodes.length > 0 && isStringArg(nArgs - 1)) {
786
+ encNode = idxNodes[idxNodes.length - 1];
787
+ idxNodes = idxNodes.slice(0, -1);
788
+ }
789
+ if (idxNodes.length > 2)
790
+ lowerer.noLowering(`.write with ${nArgs} arguments`, call);
791
+ const encName = encNode ? bufEncoding(lowerer, "Buffer.write", encNode) : "utf8";
792
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
793
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
794
+ const offset = idxNodes[0]
795
+ ? lowerer.lowerExprExpecting(idxNodes[0], F64)
796
+ : { kind: "numLit", value: 0, type: F64, loc };
797
+ const writeArgs = [s, enc, offset, ...(idxNodes[1] ? [lowerer.lowerExprExpecting(idxNodes[1], F64)] : [])];
798
+ const receiver = lowerer.lowerExpr(access.expression);
799
+ return { kind: "bytesIntrinsic", method: "writeStr", receiver, args: writeArgs, type: F64, loc };
800
+ }
801
+ return null;
802
+ }
803
+ /** The DataView getter surface by source name. `le` marks the multi-byte
804
+ * kinds whose lib signature declares the optional littleEndian parameter
805
+ * (the 8-bit getters take none). The Big pair only compiles composed
806
+ * inside Number(...) — see the use site. */
807
+ const DV_GETTERS = {
808
+ getUint8: { method: "dvGetUint8", le: false },
809
+ getInt8: { method: "dvGetInt8", le: false },
810
+ getUint16: { method: "dvGetUint16", le: true },
811
+ getInt16: { method: "dvGetInt16", le: true },
812
+ getUint32: { method: "dvGetUint32", le: true },
813
+ getInt32: { method: "dvGetInt32", le: true },
814
+ getFloat32: { method: "dvGetFloat32", le: true },
815
+ getFloat64: { method: "dvGetFloat64", le: true },
816
+ getBigUint64: { method: "dvGetBigUint64Number", le: true },
817
+ getBigInt64: { method: "dvGetBigInt64Number", le: true },
818
+ };
819
+ const DV_SETTERS = {
820
+ setUint8: { method: "dvSetUint8", le: false },
821
+ setInt8: { method: "dvSetInt8", le: false },
822
+ setUint16: { method: "dvSetUint16", le: true },
823
+ setInt16: { method: "dvSetInt16", le: true },
824
+ setUint32: { method: "dvSetUint32", le: true },
825
+ setInt32: { method: "dvSetInt32", le: true },
826
+ setFloat32: { method: "dvSetFloat32", le: true },
827
+ setFloat64: { method: "dvSetFloat64", le: true },
828
+ };
829
+ /** The Buffer statics — `Buffer.from(...)`, `Buffer.alloc(n)`,
830
+ * `Buffer.concat(list)`, `Buffer.isBuffer(x)` — on THE stdlib Buffer
831
+ * global (name + provenance; fallback and @types/node alike). Null when
832
+ * the callee isn't a Buffer-static access. */
833
+ export function lowerBufferStaticCall(lowerer, call, access) {
834
+ if (call.questionDotToken || access.questionDotToken)
835
+ return null;
836
+ if (!lowerer.isStdlibGlobal(access.expression, "Buffer"))
837
+ return null;
838
+ const member = access.name.text;
839
+ const loc = locOf(call);
840
+ const args = call.arguments;
841
+ if (member === "from") {
842
+ // Buffer.from(x.buffer[, byteOffset[, length]]): a u8 VIEW sharing
843
+ // x's storage (Node shares the ArrayBuffer; length is in BYTES).
844
+ // The first argument must be the SYNTACTIC `.buffer` of a typed
845
+ // array — the DataView peel — and the construction rides the same
846
+ // dataViewNew intrinsic (offset/length validation throws Node's
847
+ // DataView-shaped RangeErrors; valid indices behave exactly).
848
+ if (args.length >= 1 && args.length <= 3 && !args.some(ts.isSpreadElement) &&
849
+ ts.isPropertyAccessExpression(args[0]) && args[0].name.text === "buffer") {
850
+ const srcNode = args[0].expression;
851
+ const srcIr = lowerer.mapTypeOf(lowerer.typeOf(srcNode));
852
+ if (srcIr?.kind === "bytes") {
853
+ const receiver = lowerer.lowerExpr(srcNode);
854
+ const idxArgs = args.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
855
+ return { kind: "bytesIntrinsic", method: "dataViewNew", receiver, args: idxArgs, type: BYTES_U8, loc };
856
+ }
857
+ }
858
+ if (args.length >= 1 && args.length <= 2 && !ts.isSpreadElement(args[0])) {
859
+ const argNode = args[0];
860
+ if (ts.isArrayLiteralExpression(argNode) && !argNode.elements.some(ts.isSpreadElement)) {
861
+ // A number[] literal (contextually typed by the lib's readonly
862
+ // number[] slot — build it element-wise, the Set-seed pattern).
863
+ if (args.length === 1) {
864
+ const elems = argNode.elements.map((el) => lowerer.lowerExprExpecting(el, F64));
865
+ const seed = { kind: "arrayLit", elems, type: arrayOf(F64), loc };
866
+ return { kind: "bytesNew", source: seed, type: BYTES_U8, loc };
867
+ }
868
+ }
869
+ else {
870
+ const srcIr = lowerer.mapTypeOf(lowerer.typeOf(argNode));
871
+ if (srcIr?.kind === "string") {
872
+ const encNode = args[1];
873
+ const encName = encNode ? bufEncoding(lowerer, "Buffer.from", encNode) : "utf8";
874
+ const s = lowerer.lowerExprExpecting(argNode, STRING);
875
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
876
+ return { kind: "libCall", fn: "buffer.fromStr", args: [s, enc], type: BYTES_U8, loc };
877
+ }
878
+ if (args.length === 1 && srcIr?.kind === "bytes" && srcIr.elem === "u8") {
879
+ return { kind: "bytesNew", source: lowerer.lowerExpr(argNode), type: BYTES_U8, loc };
880
+ }
881
+ if (args.length === 1 && srcIr?.kind === "array" && srcIr.elem.kind === "f64") {
882
+ return { kind: "bytesNew", source: lowerer.lowerExpr(argNode), type: BYTES_U8, loc };
883
+ }
884
+ }
885
+ }
886
+ lowerer.noLowering("Buffer.from with this argument shape", call, "supported: Buffer.from(string, encoding?) with a literal encoding, Buffer.from(u8Array) — a copy — " +
887
+ "Buffer.from(number[]), or Buffer.from(x.buffer, byteOffset?, length?) — a view sharing x's " +
888
+ "storage (no free-standing ArrayBuffer value exists; narrow unions first)");
889
+ }
890
+ if (member === "alloc" || member === "allocUnsafe") {
891
+ const maxArgs = member === "alloc" ? 3 : 1;
892
+ if (args.length < 1 || args.length > maxArgs || args.some(ts.isSpreadElement)) {
893
+ lowerer.noLowering(`Buffer.${member} with ${args.length} arguments`, call);
894
+ }
895
+ // allocUnsafe's contents are UNSPECIFIED in Node (uninitialized pool
896
+ // memory); a zero-filled buffer is a valid instance of unspecified,
897
+ // and the deterministic choice — a program observing the difference
898
+ // is depending on garbage.
899
+ const size = lowerer.lowerExprExpecting(args[0], F64);
900
+ const fresh = { kind: "bytesNew", source: size, type: BYTES_U8, loc };
901
+ if (args.length === 1)
902
+ return fresh;
903
+ // alloc(size, fill, encoding?): the fill semantics ARE fill()'s —
904
+ // the fresh buffer is the receiver of a whole-range fill.
905
+ const fillT = lowerer.mapTypeOf(lowerer.typeOf(args[1]));
906
+ if (fillT?.kind === "string") {
907
+ const encName = args[2] ? bufEncoding(lowerer, "Buffer.alloc", args[2]) : "utf8";
908
+ const s = lowerer.lowerExprExpecting(args[1], STRING);
909
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
910
+ return { kind: "bytesIntrinsic", method: "fillStr", receiver: fresh, args: [s, enc], type: BYTES_U8, loc };
911
+ }
912
+ if (args.length > 2) {
913
+ lowerer.noLowering("Buffer.alloc with an encoding on a non-string fill", args[2]);
914
+ }
915
+ if (fillT?.kind === "f64") {
916
+ const v = lowerer.lowerExprExpecting(args[1], F64);
917
+ return { kind: "bytesIntrinsic", method: "fillNum", receiver: fresh, args: [v], type: BYTES_U8, loc };
918
+ }
919
+ if (fillT?.kind === "bytes" && fillT.elem === "u8") {
920
+ const pattern = lowerer.lowerExpr(args[1]);
921
+ return { kind: "bytesIntrinsic", method: "fill", receiver: fresh, args: [pattern], type: BYTES_U8, loc };
922
+ }
923
+ lowerer.noLowering(`Buffer.alloc with a '${lowerer.checker.typeToString(lowerer.typeOf(args[1]))}' fill`, args[1], "number, string, and Buffer/Uint8Array fills are the lowered shapes");
924
+ }
925
+ if (member === "concat") {
926
+ if (args.length < 1 || args.length > 2 || args.some(ts.isSpreadElement)) {
927
+ lowerer.noLowering(`Buffer.concat with ${args.length} arguments`, call);
928
+ }
929
+ const argNode = args[0];
930
+ let list;
931
+ if (ts.isArrayLiteralExpression(argNode) && !argNode.elements.some(ts.isSpreadElement)) {
932
+ const elems = argNode.elements.map((el) => lowerer.lowerExprExpecting(el, BYTES_U8));
933
+ list = { kind: "arrayLit", elems, type: arrayOf(BYTES_U8), loc };
934
+ }
935
+ else {
936
+ list = lowerer.lowerExpr(argNode);
937
+ if (!typeEquals(list.type, arrayOf(BYTES_U8))) {
938
+ lowerer.noLowering(`Buffer.concat of '${lowerer.fmt(list.type)}' values`, argNode, "one Uint8Array[]/Buffer[] value (or literal) is the lowered list shape");
939
+ }
940
+ }
941
+ if (args.length === 2) {
942
+ // The totalLength form truncates or zero-pads (and THROWS Node's
943
+ // 'length' RangeError on bad totals).
944
+ const total = lowerer.lowerExprExpecting(args[1], F64);
945
+ return { kind: "libCall", fn: "buffer.concatLen", args: [list, total], type: BYTES_U8, loc };
946
+ }
947
+ return { kind: "libCall", fn: "buffer.concat", args: [list], type: BYTES_U8, loc };
948
+ }
949
+ if (member === "compare") {
950
+ // The static form: Buffer.compare(a, b) IS a.compare(b).
951
+ if (args.length !== 2 || args.some(ts.isSpreadElement)) {
952
+ lowerer.noLowering(`Buffer.compare with ${args.length} arguments`, call);
953
+ }
954
+ const sides = args.map((a) => lowerer.lowerExpr(a));
955
+ if (sides.every((v) => v.type.kind === "bytes" && v.type.elem === "u8")) {
956
+ return { kind: "bytesIntrinsic", method: "compareBuf", receiver: sides[0], args: [sides[1]], type: F64, loc };
957
+ }
958
+ // A side that is not statically bytes (the invalid-input probes,
959
+ // untyped JS helpers): Node's "buf1"/"buf2" argument ladder runs
960
+ // at runtime — a well-typed dyn still compares.
961
+ const dyns = sides.map((v, i) => {
962
+ if (v.type.kind === "dyn")
963
+ return v;
964
+ if (v.kind === "unitLit" || lowerer.dynConvertible(v.type)) {
965
+ return { kind: "dynFrom", value: v, type: DYN, loc: v.loc };
966
+ }
967
+ lowerer.noLowering(`Buffer.compare of '${lowerer.fmt(v.type)}' values`, args[i], "Buffer/Uint8Array values compare (narrow unions first)");
968
+ });
969
+ return { kind: "libCall", fn: "buffer.compareChk", args: dyns, type: F64, loc };
970
+ }
971
+ if (member === "isBuffer") {
972
+ // The type-predicate narrowing test. Lowered where it DECIDES
973
+ // something: a union-typed argument with a Buffer arm becomes a
974
+ // runtime tag test (tsc's narrowing then types the branches, the
975
+ // discriminated-union machinery). Statically-decided arguments are
976
+ // fenced — the answer is a constant, and the operand's evaluation
977
+ // would have to be discarded.
978
+ if (args.length === 1 && !ts.isSpreadElement(args[0])) {
979
+ const v = lowerer.lowerExpr(args[0]);
980
+ if (v.type.kind === "union") {
981
+ const def = lowerer.unions.get(v.type.unionId);
982
+ const tag = def ? def.arms.findIndex((a) => a.kind === "bytes" && a.elem === "u8") : -1;
983
+ if (tag >= 0) {
984
+ return { kind: "unionIsTag", unionId: v.type.unionId, tag, negated: false, value: v, type: BOOL, loc };
985
+ }
986
+ }
987
+ lowerer.noLowering(`Buffer.isBuffer of '${lowerer.fmt(v.type)}' values`, args[0], "the check lowers as a runtime tag test on unions with a Buffer arm — here the answer is static");
988
+ }
989
+ lowerer.noLowering("Buffer.isBuffer with this argument shape", call);
990
+ }
991
+ if (member === "byteLength") {
992
+ // Buffer.byteLength(string, enc?) — the UTF-16-aware per-encoding
993
+ // count — or of a typed array/Buffer (its byte length, a property
994
+ // read at heart).
995
+ if (args.length >= 1 && args.length <= 2 && !ts.isSpreadElement(args[0])) {
996
+ const srcIr = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
997
+ if (srcIr?.kind === "string") {
998
+ const encName = args[1] ? bufEncoding(lowerer, "Buffer.byteLength", args[1]) : "utf8";
999
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
1000
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
1001
+ return { kind: "libCall", fn: "buffer.byteLenStr", args: [s, enc], type: F64, loc };
1002
+ }
1003
+ if (srcIr?.kind === "bytes" && args.length === 1) {
1004
+ const receiver = lowerer.lowerExpr(args[0]);
1005
+ return { kind: "bytesIntrinsic", method: "byteLength", receiver, args: [], type: F64, loc };
1006
+ }
1007
+ }
1008
+ lowerer.noLowering("Buffer.byteLength with this argument shape", call, "supported: Buffer.byteLength(string, literalEncoding?) or Buffer.byteLength(typedArray)");
1009
+ }
1010
+ if (member === "isEncoding") {
1011
+ // The runtime alias-set test — a plain bool over any string value
1012
+ // (Node's case-insensitive normalizeEncoding check).
1013
+ if (args.length === 1 && !ts.isSpreadElement(args[0]) && lowerer.mapTypeOf(lowerer.typeOf(args[0]))?.kind === "string") {
1014
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
1015
+ return { kind: "libCall", fn: "buffer.isEncoding", args: [s], type: BOOL, loc };
1016
+ }
1017
+ lowerer.noLowering("Buffer.isEncoding with this argument shape", call, "one string-typed argument is the lowered form");
1018
+ }
1019
+ return null; // of, copyBytesFrom, ... → the SC2020 member fence
1020
+ }
1021
+ //# sourceMappingURL=bytes.js.map