@scriptc/compiler 0.1.1 → 0.1.3

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 (279) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +104 -31
  2. package/ambient/scriptc.d.ts +2 -1
  3. package/dist/backend/build-cache.js.map +1 -1
  4. package/dist/backend/c/async.d.ts +5 -0
  5. package/dist/backend/c/async.js +81 -2
  6. package/dist/backend/c/async.js.map +1 -1
  7. package/dist/backend/c/c-emitter.d.ts +25 -10
  8. package/dist/backend/c/c-emitter.js +74 -22
  9. package/dist/backend/c/c-emitter.js.map +1 -1
  10. package/dist/backend/c/exprs.d.ts +8 -1
  11. package/dist/backend/c/exprs.js +371 -18
  12. package/dist/backend/c/exprs.js.map +1 -1
  13. package/dist/backend/c/island.js.map +1 -1
  14. package/dist/backend/c/may-throw.js.map +1 -1
  15. package/dist/backend/c/shapes.js +15 -13
  16. package/dist/backend/c/shapes.js.map +1 -1
  17. package/dist/backend/c/stmts.d.ts +3 -5
  18. package/dist/backend/c/stmts.js +58 -17
  19. package/dist/backend/c/stmts.js.map +1 -1
  20. package/dist/backend/c/types.d.ts +4 -0
  21. package/dist/backend/c/types.js +18 -1
  22. package/dist/backend/c/types.js.map +1 -1
  23. package/dist/backend/c/types.test.js +8 -1
  24. package/dist/backend/c/types.test.js.map +1 -1
  25. package/dist/backend/c/walkers.js +63 -16
  26. package/dist/backend/c/walkers.js.map +1 -1
  27. package/dist/backend/external-c.js.map +1 -1
  28. package/dist/backend/json-literal.d.ts +7 -0
  29. package/dist/backend/json-literal.js +17 -0
  30. package/dist/backend/json-literal.js.map +1 -0
  31. package/dist/backend/json-literal.test.d.ts +1 -0
  32. package/dist/backend/json-literal.test.js +17 -0
  33. package/dist/backend/json-literal.test.js.map +1 -0
  34. package/dist/backend/link-plan.d.ts +1 -1
  35. package/dist/backend/link-plan.js +5 -1
  36. package/dist/backend/link-plan.js.map +1 -1
  37. package/dist/backend/linker.js.map +1 -1
  38. package/dist/backend/llvm/blocks.js.map +1 -1
  39. package/dist/backend/llvm/classes.js +8 -7
  40. package/dist/backend/llvm/classes.js.map +1 -1
  41. package/dist/backend/llvm/common.d.ts +4 -0
  42. package/dist/backend/llvm/common.js +6 -0
  43. package/dist/backend/llvm/common.js.map +1 -1
  44. package/dist/backend/llvm/common.test.d.ts +1 -0
  45. package/dist/backend/llvm/common.test.js +9 -0
  46. package/dist/backend/llvm/common.test.js.map +1 -0
  47. package/dist/backend/llvm/dyn.d.ts +4 -0
  48. package/dist/backend/llvm/dyn.js +80 -16
  49. package/dist/backend/llvm/dyn.js.map +1 -1
  50. package/dist/backend/llvm/emitter.js +132 -25
  51. package/dist/backend/llvm/emitter.js.map +1 -1
  52. package/dist/backend/llvm/expr-async.js +85 -3
  53. package/dist/backend/llvm/expr-async.js.map +1 -1
  54. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  55. package/dist/backend/llvm/expr-calls.js.map +1 -1
  56. package/dist/backend/llvm/expr-containers.js.map +1 -1
  57. package/dist/backend/llvm/expr-context.d.ts +5 -0
  58. package/dist/backend/llvm/expr-control.js.map +1 -1
  59. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  60. package/dist/backend/llvm/expr-dynamic.js +15 -3
  61. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  62. package/dist/backend/llvm/expr-island.js.map +1 -1
  63. package/dist/backend/llvm/expr-primitives.js +8 -0
  64. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  65. package/dist/backend/llvm/expr-records.js +3 -3
  66. package/dist/backend/llvm/expr-records.js.map +1 -1
  67. package/dist/backend/llvm/expr-stream-bridges.js +222 -10
  68. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  69. package/dist/backend/llvm/expr-stream-callbacks.d.ts +3 -0
  70. package/dist/backend/llvm/expr-stream-callbacks.js +53 -0
  71. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  72. package/dist/backend/llvm/lib-dispatch.js +24 -0
  73. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  74. package/dist/backend/llvm/lib-process.js +50 -5
  75. package/dist/backend/llvm/lib-process.js.map +1 -1
  76. package/dist/backend/llvm/lib-shared.js +64 -0
  77. package/dist/backend/llvm/lib-shared.js.map +1 -1
  78. package/dist/backend/llvm/lib-stream.js +6 -3
  79. package/dist/backend/llvm/lib-stream.js.map +1 -1
  80. package/dist/backend/llvm/shapes.js +10 -8
  81. package/dist/backend/llvm/shapes.js.map +1 -1
  82. package/dist/backend/llvm/split.js.map +1 -1
  83. package/dist/backend/llvm/unsupported.js.map +1 -1
  84. package/dist/backend/llvm/walkers.js +7 -5
  85. package/dist/backend/llvm/walkers.js.map +1 -1
  86. package/dist/backend/native-codegen.js.map +1 -1
  87. package/dist/backend/native-codegen.test.js +2 -0
  88. package/dist/backend/native-codegen.test.js.map +1 -1
  89. package/dist/backend/native-link-info.d.ts +2 -1
  90. package/dist/backend/native-link-info.js +4 -0
  91. package/dist/backend/native-link-info.js.map +1 -1
  92. package/dist/backend/native-link-info.test.js +24 -1
  93. package/dist/backend/native-link-info.test.js.map +1 -1
  94. package/dist/backend/native-toolchain.d.ts +8 -6
  95. package/dist/backend/native-toolchain.js +28 -13
  96. package/dist/backend/native-toolchain.js.map +1 -1
  97. package/dist/backend/native-toolchain.test.js +36 -1
  98. package/dist/backend/native-toolchain.test.js.map +1 -1
  99. package/dist/backend/runtime-pack-targets.test.js +1 -1
  100. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  101. package/dist/backend/runtime-pack.js.map +1 -1
  102. package/dist/backend/runtime-pack.test.js +1 -0
  103. package/dist/backend/runtime-pack.test.js.map +1 -1
  104. package/dist/backend/targets.d.ts +5 -0
  105. package/dist/backend/targets.js +9 -0
  106. package/dist/backend/targets.js.map +1 -1
  107. package/dist/backend/targets.test.js +6 -1
  108. package/dist/backend/targets.test.js.map +1 -1
  109. package/dist/backend/vendor-archives.js.map +1 -1
  110. package/dist/compat/fetch-profile.js +4 -2
  111. package/dist/compat/fetch-profile.js.map +1 -1
  112. package/dist/coverage/report.js.map +1 -1
  113. package/dist/coverage/surface-manifest.js +13 -0
  114. package/dist/coverage/surface-manifest.js.map +1 -1
  115. package/dist/diagnostics/diagnostic.d.ts +6 -5
  116. package/dist/diagnostics/diagnostic.js +10 -9
  117. package/dist/diagnostics/diagnostic.js.map +1 -1
  118. package/dist/diagnostics/render.js.map +1 -1
  119. package/dist/executable/executable-cache.d.ts +1 -0
  120. package/dist/executable/executable-cache.js +1 -0
  121. package/dist/executable/executable-cache.js.map +1 -1
  122. package/dist/executable/executable-cache.test.js +1 -0
  123. package/dist/executable/executable-cache.test.js.map +1 -1
  124. package/dist/ffi/ffi-manifest.js.map +1 -1
  125. package/dist/frontend/cjs-lexer.js.map +1 -1
  126. package/dist/frontend/dts-paths.js.map +1 -1
  127. package/dist/frontend/input-tracker.d.ts +10 -0
  128. package/dist/frontend/input-tracker.js +26 -3
  129. package/dist/frontend/input-tracker.js.map +1 -1
  130. package/dist/frontend/input-tracker.test.js +8 -1
  131. package/dist/frontend/input-tracker.test.js.map +1 -1
  132. package/dist/frontend/lib-contract.js.map +1 -1
  133. package/dist/frontend/lowering/array-values.d.ts +4 -0
  134. package/dist/frontend/lowering/array-values.js +18 -2
  135. package/dist/frontend/lowering/array-values.js.map +1 -1
  136. package/dist/frontend/lowering/callback-arg.js.map +1 -1
  137. package/dist/frontend/lowering/containers/bytes.d.ts +31 -0
  138. package/dist/frontend/lowering/containers/bytes.js +1105 -0
  139. package/dist/frontend/lowering/containers/bytes.js.map +1 -0
  140. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +17 -0
  141. package/dist/frontend/lowering/containers/string-and-regexp.js +345 -0
  142. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -0
  143. package/dist/frontend/lowering/expressions/evaluation-safety.d.ts +13 -0
  144. package/dist/frontend/lowering/expressions/evaluation-safety.js +76 -0
  145. package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -0
  146. package/dist/frontend/lowering/expressions/object-literals.d.ts +44 -0
  147. package/dist/frontend/lowering/expressions/object-literals.js +1815 -0
  148. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -0
  149. package/dist/frontend/lowering/expressions/optional-chains.d.ts +31 -0
  150. package/dist/frontend/lowering/expressions/optional-chains.js +382 -0
  151. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -0
  152. package/dist/frontend/lowering/expressions/try-lower-expression.d.ts +7 -0
  153. package/dist/frontend/lowering/expressions/try-lower-expression.js +26 -0
  154. package/dist/frontend/lowering/expressions/try-lower-expression.js.map +1 -0
  155. package/dist/frontend/lowering/lib-boundary.js +7 -2
  156. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  157. package/dist/frontend/lowering/lower-assert.js +16 -10
  158. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  159. package/dist/frontend/lowering/lower-async-iteration.d.ts +7 -0
  160. package/dist/frontend/lowering/lower-async-iteration.js +657 -0
  161. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -0
  162. package/dist/frontend/lowering/lower-builtins.d.ts +40 -21
  163. package/dist/frontend/lowering/lower-builtins.js +611 -115
  164. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  165. package/dist/frontend/lowering/lower-calls.d.ts +21 -10
  166. package/dist/frontend/lowering/lower-calls.js +516 -75
  167. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  168. package/dist/frontend/lowering/lower-classes.d.ts +7 -13
  169. package/dist/frontend/lowering/lower-classes.js +128 -35
  170. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  171. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  172. package/dist/frontend/lowering/lower-containers.d.ts +1 -47
  173. package/dist/frontend/lowering/lower-containers.js +147 -1475
  174. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  175. package/dist/frontend/lowering/lower-event-emitter.js +51 -5
  176. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  177. package/dist/frontend/lowering/lower-exprs.d.ts +0 -78
  178. package/dist/frontend/lowering/lower-exprs.js +503 -2353
  179. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  180. package/dist/frontend/lowering/lower-generators.d.ts +18 -3
  181. package/dist/frontend/lowering/lower-generators.js +145 -9
  182. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  183. package/dist/frontend/lowering/lower-inspect.js +10 -3
  184. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  185. package/dist/frontend/lowering/lower-island.d.ts +6 -0
  186. package/dist/frontend/lowering/lower-island.js +37 -5
  187. package/dist/frontend/lowering/lower-island.js.map +1 -1
  188. package/dist/frontend/lowering/lower-modules.js +60 -15
  189. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  190. package/dist/frontend/lowering/lower-node-module.d.ts +18 -0
  191. package/dist/frontend/lowering/lower-node-module.js +302 -0
  192. package/dist/frontend/lowering/lower-node-module.js.map +1 -0
  193. package/dist/frontend/lowering/lower-server.js +1 -1
  194. package/dist/frontend/lowering/lower-server.js.map +1 -1
  195. package/dist/frontend/lowering/lower-stmts.d.ts +10 -28
  196. package/dist/frontend/lowering/lower-stmts.js +542 -259
  197. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  198. package/dist/frontend/lowering/lower-stream.js +4 -4
  199. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  200. package/dist/frontend/lowering/lowerer.d.ts +41 -38
  201. package/dist/frontend/lowering/lowerer.js +148 -62
  202. package/dist/frontend/lowering/lowerer.js.map +1 -1
  203. package/dist/frontend/lowering/optional-arguments.d.ts +9 -0
  204. package/dist/frontend/lowering/optional-arguments.js +57 -0
  205. package/dist/frontend/lowering/optional-arguments.js.map +1 -0
  206. package/dist/frontend/lowering/surfaces.d.ts +5 -3
  207. package/dist/frontend/lowering/surfaces.js +33 -13
  208. package/dist/frontend/lowering/surfaces.js.map +1 -1
  209. package/dist/frontend/npm-static-declarations.d.ts +35 -0
  210. package/dist/frontend/npm-static-declarations.js +519 -0
  211. package/dist/frontend/npm-static-declarations.js.map +1 -0
  212. package/dist/frontend/npm-static-declarations.test.d.ts +1 -0
  213. package/dist/frontend/npm-static-declarations.test.js +132 -0
  214. package/dist/frontend/npm-static-declarations.test.js.map +1 -0
  215. package/dist/frontend/npm-static.d.ts +2 -0
  216. package/dist/frontend/npm-static.js +26 -10
  217. package/dist/frontend/npm-static.js.map +1 -1
  218. package/dist/frontend/npm.d.ts +60 -0
  219. package/dist/frontend/npm.js +38 -4
  220. package/dist/frontend/npm.js.map +1 -1
  221. package/dist/frontend/npm.test.d.ts +1 -0
  222. package/dist/frontend/npm.test.js +50 -0
  223. package/dist/frontend/npm.test.js.map +1 -0
  224. package/dist/frontend/program.d.ts +3 -2
  225. package/dist/frontend/program.js +513 -70
  226. package/dist/frontend/program.js.map +1 -1
  227. package/dist/frontend/resolve.d.ts +26 -3
  228. package/dist/frontend/resolve.js +166 -29
  229. package/dist/frontend/resolve.js.map +1 -1
  230. package/dist/frontend/resolve.test.js +24 -1
  231. package/dist/frontend/resolve.test.js.map +1 -1
  232. package/dist/frontend/runtime-resolve.d.ts +22 -0
  233. package/dist/frontend/runtime-resolve.js +101 -0
  234. package/dist/frontend/runtime-resolve.js.map +1 -0
  235. package/dist/frontend/runtime-resolve.test.d.ts +1 -0
  236. package/dist/frontend/runtime-resolve.test.js +18 -0
  237. package/dist/frontend/runtime-resolve.test.js.map +1 -0
  238. package/dist/frontend/ts7/adapter.js +12 -13
  239. package/dist/frontend/ts7/adapter.js.map +1 -1
  240. package/dist/frontend/ts7/ast.js.map +1 -1
  241. package/dist/frontend/ts7/census-check.js +3 -3
  242. package/dist/frontend/ts7/census-check.js.map +1 -1
  243. package/dist/frontend/ts7/checker.d.ts +3 -0
  244. package/dist/frontend/ts7/checker.js +12 -3
  245. package/dist/frontend/ts7/checker.js.map +1 -1
  246. package/dist/frontend/ts7/enums.js.map +1 -1
  247. package/dist/frontend/ts7/program-adapter.js +42 -3
  248. package/dist/frontend/ts7/program-adapter.js.map +1 -1
  249. package/dist/frontend/type-mapper.js +171 -16
  250. package/dist/frontend/type-mapper.js.map +1 -1
  251. package/dist/index.js +11 -5
  252. package/dist/index.js.map +1 -1
  253. package/dist/ir/analysis.js +1 -0
  254. package/dist/ir/analysis.js.map +1 -1
  255. package/dist/ir/ir.d.ts +125 -52
  256. package/dist/ir/ir.js +136 -7
  257. package/dist/ir/ir.js.map +1 -1
  258. package/dist/ir/serialize.d.ts +1 -1
  259. package/dist/ir/serialize.js +1 -1
  260. package/dist/ir/validate.js +120 -63
  261. package/dist/ir/validate.js.map +1 -1
  262. package/dist/library/cache-primitives.js.map +1 -1
  263. package/dist/library/cache-reset.test.js.map +1 -1
  264. package/dist/library/compiler-self-identity.js.map +1 -1
  265. package/dist/library/int-infer.js.map +1 -1
  266. package/dist/library/int-infer.test.js +4 -4
  267. package/dist/library/int-infer.test.js.map +1 -1
  268. package/dist/library/library-cache.d.ts +1 -0
  269. package/dist/library/library-cache.js +1 -0
  270. package/dist/library/library-cache.js.map +1 -1
  271. package/dist/library/library-cache.test.js +18 -5
  272. package/dist/library/library-cache.test.js.map +1 -1
  273. package/dist/library/library-profile.js.map +1 -1
  274. package/dist/library/sidecar-validate.js.map +1 -1
  275. package/dist/library/sidecar.js.map +1 -1
  276. package/dist/startup-cache.js.map +1 -1
  277. package/dist/wasi-paths.js.map +1 -1
  278. package/package.json +18 -18
  279. package/surface-manifest.json +91 -20
@@ -0,0 +1,1105 @@
1
+ import * as ts from "../../ts7/adapter.js";
2
+ import { BIGINT_T, 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
+ const bigKind = own(BUF_BIGINT_METHODS, name);
443
+ if (bigKind !== undefined && declOnBuffer && receiverIr.elem === "u8") {
444
+ const write = name.startsWith("write");
445
+ const required = write ? 1 : 0;
446
+ if (nArgs < required || nArgs > required + 1) {
447
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
448
+ }
449
+ const receiver = lowerer.lowerExpr(access.expression);
450
+ const offsetNode = call.arguments[required];
451
+ const offset = offsetNode
452
+ ? lowerer.lowerExprExpecting(offsetNode, F64)
453
+ : { kind: "numLit", value: 0, type: F64, loc };
454
+ const sign = { kind: "boolLit", value: bigKind.sign, type: BOOL, loc };
455
+ const le = { kind: "boolLit", value: bigKind.le, type: BOOL, loc };
456
+ if (!write) {
457
+ return { kind: "libCall", fn: "bigint.bufferRead", args: [receiver, offset, sign, le], type: BIGINT_T, loc };
458
+ }
459
+ const value = lowerer.lowerExprExpecting(call.arguments[0], BIGINT_T);
460
+ return { kind: "libCall", fn: "bigint.bufferWrite", args: [receiver, value, offset, sign, le], type: F64, loc };
461
+ }
462
+ // The Buffer numeric read/write families — every fixed-width kind in
463
+ // both endiannesses ("Uint" and "UInt" alike: Node aliases both), plus
464
+ // the variable-width read/writeUIntLE quartet. The kind token rides as
465
+ // a strLit args[0]; omitted offsets complete to Node's default 0.
466
+ const numKind = own(BUF_NUM_METHODS, name);
467
+ if (numKind !== undefined) {
468
+ if (receiverIr.elem !== "u8") {
469
+ lowerer.noLowering(`.${name} on a '${lowerer.fmt(receiverIr)}'`, call, "the numeric families read/write Buffer bytes");
470
+ }
471
+ const write = name.startsWith("write");
472
+ const required = write ? 1 : 0; // value; offset defaults to 0
473
+ if (nArgs < required || nArgs > required + 1) {
474
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
475
+ }
476
+ const receiver = lowerer.lowerExpr(access.expression);
477
+ const kind = { kind: "strLit", value: numKind, type: STRING, loc };
478
+ const args = [kind, ...call.arguments.map((a) => lowerer.lowerExprExpecting(a, F64))];
479
+ if (nArgs === required) {
480
+ args.push({ kind: "numLit", value: 0, type: F64, loc }); // Node's offset default
481
+ }
482
+ return { kind: "bytesIntrinsic", method: write ? "writeNum" : "readNum", receiver, args, type: F64, loc };
483
+ }
484
+ const varKind = own(BUF_NUM_VAR_METHODS, name);
485
+ if (varKind !== undefined) {
486
+ if (receiverIr.elem !== "u8") {
487
+ lowerer.noLowering(`.${name} on a '${lowerer.fmt(receiverIr)}'`, call, "the numeric families read/write Buffer bytes");
488
+ }
489
+ const write = name.startsWith("write");
490
+ const required = write ? 3 : 2; // Node declares offset AND byteLength required
491
+ if (nArgs !== required) {
492
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
493
+ }
494
+ const receiver = lowerer.lowerExpr(access.expression);
495
+ const kind = { kind: "strLit", value: varKind, type: STRING, loc };
496
+ const args = [kind, ...call.arguments.map((a) => lowerer.lowerExprExpecting(a, F64))];
497
+ return { kind: "bytesIntrinsic", method: write ? "writeNumVar" : "readNumVar", receiver, args, type: F64, loc };
498
+ }
499
+ // DataView getters (DataView maps to bytes<u8>, so the receiver kind
500
+ // and stdlib provenance land here; the checker keeps these names off
501
+ // typed arrays and Buffers). The multi-byte kinds take the optional
502
+ // littleEndian bool (omitted = big-endian, the JS default). All THROW
503
+ // Node's RangeError on a bad offset (may-throw seeds).
504
+ const dvBigGetter = own(DV_BIG_GETTERS, name);
505
+ if (dvBigGetter !== undefined && receiverIr.elem === "u8") {
506
+ if (nArgs < 1 || nArgs > 2)
507
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
508
+ const receiver = lowerer.lowerExpr(access.expression);
509
+ const offset = lowerer.lowerExprExpecting(call.arguments[0], F64);
510
+ const sign = { kind: "boolLit", value: dvBigGetter.sign, type: BOOL, loc };
511
+ const le = call.arguments[1]
512
+ ? lowerer.lowerExprExpecting(call.arguments[1], BOOL)
513
+ : { kind: "boolLit", value: false, type: BOOL, loc };
514
+ return { kind: "libCall", fn: "bigint.dataViewGet", args: [receiver, offset, sign, le], type: BIGINT_T, loc };
515
+ }
516
+ const dvGetter = own(DV_GETTERS, name);
517
+ if (dvGetter !== undefined && receiverIr.elem === "u8") {
518
+ const maxArgs = dvGetter.le ? 2 : 1;
519
+ if (nArgs < 1 || nArgs > maxArgs) {
520
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
521
+ }
522
+ const receiver = lowerer.lowerExpr(access.expression);
523
+ const args = [lowerer.lowerExprExpecting(call.arguments[0], F64)];
524
+ if (nArgs === 2)
525
+ args.push(lowerer.lowerExprExpecting(call.arguments[1], BOOL));
526
+ return { kind: "bytesIntrinsic", method: dvGetter.method, receiver, args, type: F64, loc };
527
+ }
528
+ // DataView setters — the getters' mirror: (byteOffset, value) plus the
529
+ // optional littleEndian bool on the multi-byte kinds. Void results;
530
+ // the same constant Node RangeError on a bad offset (may-throw seeds).
531
+ // setBigUint64/setBigInt64 never lower (bigint ARGUMENTS have no
532
+ // representation and no composed form exists) — they keep the member
533
+ // fence, as does setFloat16.
534
+ const dvSetter = own(DV_SETTERS, name);
535
+ if ((name === "setBigUint64" || name === "setBigInt64") && receiverIr.elem === "u8") {
536
+ if (nArgs < 2 || nArgs > 3)
537
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
538
+ const receiver = lowerer.lowerExpr(access.expression);
539
+ const offset = lowerer.lowerExprExpecting(call.arguments[0], F64);
540
+ const value = lowerer.lowerExprExpecting(call.arguments[1], BIGINT_T);
541
+ const le = call.arguments[2]
542
+ ? lowerer.lowerExprExpecting(call.arguments[2], BOOL)
543
+ : { kind: "boolLit", value: false, type: BOOL, loc };
544
+ return { kind: "libCall", fn: "bigint.dataViewSet", args: [receiver, offset, value, le], type: VOID, loc };
545
+ }
546
+ if (dvSetter !== undefined && receiverIr.elem === "u8") {
547
+ const maxArgs = dvSetter.le ? 3 : 2;
548
+ if (nArgs < 2 || nArgs > maxArgs) {
549
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
550
+ }
551
+ const receiver = lowerer.lowerExpr(access.expression);
552
+ const args = [
553
+ lowerer.lowerExprExpecting(call.arguments[0], F64),
554
+ lowerer.lowerExprExpecting(call.arguments[1], F64),
555
+ ];
556
+ if (nArgs === 3)
557
+ args.push(lowerer.lowerExprExpecting(call.arguments[2], BOOL));
558
+ return { kind: "bytesIntrinsic", method: dvSetter.method, receiver, args, type: VOID, loc };
559
+ }
560
+ return null;
561
+ }
562
+ /** Node's Buffer encoding names → the runtime's canonical spelling (every
563
+ * alias folds at compile time; the runtime sees only canonical names).
564
+ * Shared by toString, Buffer.from, and Buffer.byteLength. */
565
+ const BUF_ENCODINGS = {
566
+ utf8: "utf8",
567
+ "utf-8": "utf8",
568
+ hex: "hex",
569
+ base64: "base64",
570
+ base64url: "base64url",
571
+ latin1: "latin1",
572
+ binary: "latin1",
573
+ ascii: "ascii",
574
+ utf16le: "utf16le",
575
+ "utf-16le": "utf16le",
576
+ ucs2: "utf16le",
577
+ "ucs-2": "utf16le",
578
+ };
579
+ /** A literal encoding's canonical name, or undefined for a spelling Node
580
+ * does not know — the ladder callers (stream options) turn unknown
581
+ * literals into Node's runtime ERR_UNKNOWN_ENCODING throw. */
582
+ export function knownBufEncoding(name) {
583
+ return own(BUF_ENCODINGS, name);
584
+ }
585
+ /** The literal encoding argument of a Buffer surface, normalized — or a
586
+ * fence when it isn't a literal alias Node knows. */
587
+ export function bufEncoding(lowerer, what, encNode) {
588
+ const t = lowerer.typeOf(encNode);
589
+ const v = t.isStringLiteralType() ? own(BUF_ENCODINGS, t.value) : undefined;
590
+ if (v === undefined) {
591
+ 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');
592
+ }
593
+ return v;
594
+ }
595
+ /** The fixed-width Buffer numeric methods by source name → the readNum/
596
+ * writeNum kind token. Node declares BOTH capitalizations ("UInt" is the
597
+ * original, "Uint" the aliased spelling) — the tables carry both. */
598
+ const BUF_NUM_METHODS = (() => {
599
+ const out = {};
600
+ for (const rw of ["read", "write"]) {
601
+ for (const u of ["UInt", "Uint"]) {
602
+ out[`${rw}${u}8`] = "u8";
603
+ out[`${rw}${u}16BE`] = "u16be";
604
+ out[`${rw}${u}16LE`] = "u16le";
605
+ out[`${rw}${u}32BE`] = "u32be";
606
+ out[`${rw}${u}32LE`] = "u32le";
607
+ }
608
+ out[`${rw}Int8`] = "i8";
609
+ out[`${rw}Int16BE`] = "i16be";
610
+ out[`${rw}Int16LE`] = "i16le";
611
+ out[`${rw}Int32BE`] = "i32be";
612
+ out[`${rw}Int32LE`] = "i32le";
613
+ out[`${rw}FloatBE`] = "f32be";
614
+ out[`${rw}FloatLE`] = "f32le";
615
+ out[`${rw}DoubleBE`] = "f64be";
616
+ out[`${rw}DoubleLE`] = "f64le";
617
+ }
618
+ return out;
619
+ })();
620
+ const BUF_BIGINT_METHODS = {
621
+ readBigInt64BE: { sign: true, le: false },
622
+ readBigInt64LE: { sign: true, le: true },
623
+ readBigUInt64BE: { sign: false, le: false },
624
+ readBigUInt64LE: { sign: false, le: true },
625
+ readBigUint64BE: { sign: false, le: false },
626
+ readBigUint64LE: { sign: false, le: true },
627
+ writeBigInt64BE: { sign: true, le: false },
628
+ writeBigInt64LE: { sign: true, le: true },
629
+ writeBigUInt64BE: { sign: false, le: false },
630
+ writeBigUInt64LE: { sign: false, le: true },
631
+ writeBigUint64BE: { sign: false, le: false },
632
+ writeBigUint64LE: { sign: false, le: true },
633
+ };
634
+ /** The variable-width quartet (offset + byteLength) → sign/endian token. */
635
+ const BUF_NUM_VAR_METHODS = {
636
+ readUIntBE: "ube",
637
+ readUintBE: "ube",
638
+ readUIntLE: "ule",
639
+ readUintLE: "ule",
640
+ readIntBE: "ibe",
641
+ readIntLE: "ile",
642
+ writeUIntBE: "ube",
643
+ writeUintBE: "ube",
644
+ writeUIntLE: "ule",
645
+ writeUintLE: "ule",
646
+ writeIntBE: "ibe",
647
+ writeIntLE: "ile",
648
+ };
649
+ /** The Buffer-declared comparison/search/mutation methods on a u8
650
+ * receiver: equals, compare, indexOf/lastIndexOf/includes (number,
651
+ * string-with-encoding, and Buffer needles), fill, copy, swap16/32/64,
652
+ * and write. Null when `name` isn't one of them (the numeric families
653
+ * and the generic bytes surface try next). Encodings must be literals
654
+ * (bufEncoding's fence); a trailing string-typed argument is the
655
+ * encoding, exactly Node's overloads. */
656
+ function lowerBufferInstanceMethod(lowerer, call, access, name, loc) {
657
+ const args = call.arguments;
658
+ const nArgs = args.length;
659
+ if (args.some(ts.isSpreadElement))
660
+ return null;
661
+ const isStringArg = (i) => lowerer.mapTypeOf(lowerer.typeOf(args[i]))?.kind === "string";
662
+ const u8Arg = (i) => {
663
+ const v = lowerer.lowerExpr(args[i]);
664
+ if (!(v.type.kind === "bytes" && v.type.elem === "u8")) {
665
+ lowerer.noLowering(`.${name} of '${lowerer.fmt(v.type)}' values`, args[i], "a Buffer/Uint8Array argument is the lowered shape (narrow unions first)");
666
+ }
667
+ return v;
668
+ };
669
+ // The checked-dynamic crossing for a compare/equals argument slot: dyn
670
+ // passes through, convertible statics (the invalid-input probes'
671
+ // literals) wrap in dynFrom, `undefined` literals ride the same wrap.
672
+ // Fences (never returns) when the value cannot cross — an island jsval.
673
+ const chkArg = (i) => {
674
+ // Object literals take the dyn literal path directly (method members
675
+ // box as dyn functions — the typed record fence never applies).
676
+ if (ts.isObjectLiteralExpression(args[i])) {
677
+ return lowerDynObjectLiteral(lowerer, args[i]);
678
+ }
679
+ const v = lowerer.lowerExpr(args[i]);
680
+ if (v.type.kind === "dyn")
681
+ return v;
682
+ if (v.kind === "unitLit" || lowerer.dynConvertible(v.type)) {
683
+ return { kind: "dynFrom", value: v, type: DYN, loc: v.loc };
684
+ }
685
+ lowerer.noLowering(`.${name} of '${lowerer.fmt(v.type)}' values`, args[i], "a Buffer/Uint8Array argument is the lowered shape (narrow unions first)");
686
+ };
687
+ const argIrKind = (i) => lowerer.mapTypeOf(lowerer.typeOf(args[i]));
688
+ if (name === "equals") {
689
+ if (nArgs !== 1)
690
+ lowerer.noLowering(`.equals with ${nArgs} arguments`, call);
691
+ if (argIrKind(0)?.kind === "bytes") {
692
+ const other = u8Arg(0);
693
+ const receiver = lowerer.lowerExpr(access.expression);
694
+ return { kind: "bytesIntrinsic", method: "equals", receiver, args: [other], type: BOOL, loc };
695
+ }
696
+ // Not statically bytes (the invalid-input probes, untyped JS
697
+ // helpers): Node's "otherBuffer" argument ladder runs at runtime.
698
+ const receiver = lowerer.lowerExpr(access.expression);
699
+ return { kind: "libCall", fn: "bytes.equalsChk", args: [receiver, chkArg(0)], type: BOOL, loc };
700
+ }
701
+ if (name === "compare") {
702
+ if (nArgs > 5)
703
+ lowerer.noLowering(`.compare with ${nArgs} arguments`, call);
704
+ const fast = nArgs >= 1 &&
705
+ argIrKind(0)?.kind === "bytes" &&
706
+ call.arguments.slice(1).every((a) => lowerer.mapTypeOf(lowerer.typeOf(a))?.kind === "f64");
707
+ if (fast) {
708
+ const target = u8Arg(0);
709
+ const idx = call.arguments.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
710
+ const receiver = lowerer.lowerExpr(access.expression);
711
+ return { kind: "bytesIntrinsic", method: "compareBuf", receiver, args: [target, ...idx], type: F64, loc };
712
+ }
713
+ // An absent/ill-typed target or offset (`a.compare()`, string
714
+ // offsets, explicit undefined): Node's target/targetStart/targetEnd/
715
+ // sourceStart/sourceEnd ladder runs at runtime; absent slots pass
716
+ // the undefined dyn (Node defaults apply there).
717
+ const receiver = lowerer.lowerExpr(access.expression);
718
+ const slots = [];
719
+ for (let i = 0; i < 5; i++)
720
+ slots.push(i < nArgs ? chkArg(i) : dynUndefinedExpr(loc));
721
+ return { kind: "libCall", fn: "bytes.compareChk", args: [receiver, ...slots], type: F64, loc };
722
+ }
723
+ if (name === "indexOf" || name === "lastIndexOf" || name === "includes") {
724
+ if (nArgs < 1 || nArgs > 3)
725
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
726
+ // The overloads: (v), (v, byteOffset), (v, encoding), (v, byteOffset,
727
+ // encoding) — a trailing string-typed arg is the encoding.
728
+ let encName = "utf8";
729
+ let offNode;
730
+ if (nArgs === 3) {
731
+ offNode = args[1];
732
+ encName = bufEncoding(lowerer, `.${name}`, args[2]);
733
+ }
734
+ else if (nArgs === 2) {
735
+ if (isStringArg(1))
736
+ encName = bufEncoding(lowerer, `.${name}`, args[1]);
737
+ else
738
+ offNode = args[1];
739
+ }
740
+ const resultT = name === "includes" ? BOOL : F64;
741
+ const vT = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
742
+ const receiver = lowerer.lowerExpr(access.expression);
743
+ if (vT?.kind === "f64") {
744
+ // A number needle wraps & 0xFF at runtime (Buffer semantics; the
745
+ // encoding is irrelevant, like Node).
746
+ const v = lowerer.lowerExprExpecting(args[0], F64);
747
+ const numArgs = [v, ...(offNode ? [lowerer.lowerExprExpecting(offNode, F64)] : [])];
748
+ const method = name === "indexOf" ? "indexOfNum" : name === "lastIndexOf" ? "lastIndexOfNum" : "includesNum";
749
+ return { kind: "bytesIntrinsic", method, receiver, args: numArgs, type: resultT, loc };
750
+ }
751
+ let needle;
752
+ let align = 1;
753
+ if (vT?.kind === "string") {
754
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
755
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
756
+ needle = { kind: "libCall", fn: "buffer.fromStr", args: [s, enc], type: BYTES_U8, loc };
757
+ if (encName === "utf16le")
758
+ align = 2;
759
+ }
760
+ else if (vT?.kind === "bytes" && vT.elem === "u8") {
761
+ needle = lowerer.lowerExpr(args[0]);
762
+ }
763
+ else {
764
+ lowerer.noLowering(`.${name} of '${lowerer.checker.typeToString(lowerer.typeOf(args[0]))}' values`, args[0], "string, number, and Buffer/Uint8Array needles search (narrow unions first)");
765
+ }
766
+ const alignLit = { kind: "numLit", value: align, type: F64, loc };
767
+ const searchArgs = [needle, alignLit, ...(offNode ? [lowerer.lowerExprExpecting(offNode, F64)] : [])];
768
+ return { kind: "bytesIntrinsic", method: name, receiver, args: searchArgs, type: resultT, loc };
769
+ }
770
+ if (name === "fill") {
771
+ if (nArgs < 1 || nArgs > 4)
772
+ lowerer.noLowering(`.fill with ${nArgs} arguments`, call);
773
+ // A trailing string-typed arg past the value is the encoding.
774
+ let encNode;
775
+ let idxNodes = call.arguments.slice(1);
776
+ if (idxNodes.length > 0 && isStringArg(nArgs - 1)) {
777
+ encNode = idxNodes[idxNodes.length - 1];
778
+ idxNodes = idxNodes.slice(0, -1);
779
+ }
780
+ if (idxNodes.length > 2)
781
+ lowerer.noLowering(`.fill with ${nArgs} arguments`, call);
782
+ const idx = idxNodes.map((a) => lowerer.lowerExprExpecting(a, F64));
783
+ const receiverT = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
784
+ if (receiverT?.kind !== "bytes")
785
+ lowerer.badType(access.expression, lowerer.typeOf(access.expression));
786
+ const vT = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
787
+ const receiver = lowerer.lowerExpr(access.expression);
788
+ if (vT?.kind === "string") {
789
+ const encName = encNode ? bufEncoding(lowerer, ".fill", encNode) : "utf8";
790
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
791
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
792
+ return { kind: "bytesIntrinsic", method: "fillStr", receiver, args: [s, enc, ...idx], type: BYTES_U8, loc };
793
+ }
794
+ if (encNode)
795
+ lowerer.noLowering(".fill with an encoding on a non-string value", encNode);
796
+ if (vT?.kind === "f64") {
797
+ const v = lowerer.lowerExprExpecting(args[0], F64);
798
+ return { kind: "bytesIntrinsic", method: "fillNum", receiver, args: [v, ...idx], type: BYTES_U8, loc };
799
+ }
800
+ const pattern = u8Arg(0);
801
+ return { kind: "bytesIntrinsic", method: "fill", receiver, args: [pattern, ...idx], type: BYTES_U8, loc };
802
+ }
803
+ if (name === "copy") {
804
+ if (nArgs < 1 || nArgs > 4)
805
+ lowerer.noLowering(`.copy with ${nArgs} arguments`, call);
806
+ const target = u8Arg(0);
807
+ const idx = call.arguments.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
808
+ const receiver = lowerer.lowerExpr(access.expression);
809
+ return { kind: "bytesIntrinsic", method: "copy", receiver, args: [target, ...idx], type: F64, loc };
810
+ }
811
+ if (name === "swap16" || name === "swap32" || name === "swap64") {
812
+ if (nArgs !== 0)
813
+ lowerer.noLowering(`.${name} with ${nArgs} arguments`, call);
814
+ const receiver = lowerer.lowerExpr(access.expression);
815
+ return { kind: "bytesIntrinsic", method: name, receiver, args: [], type: BYTES_U8, loc };
816
+ }
817
+ if (name === "write") {
818
+ if (nArgs < 1 || nArgs > 4)
819
+ lowerer.noLowering(`.write with ${nArgs} arguments`, call);
820
+ // (str), (str, enc), (str, offset), (str, offset, enc),
821
+ // (str, offset, length), (str, offset, length, enc).
822
+ let encNode;
823
+ let idxNodes = call.arguments.slice(1);
824
+ if (idxNodes.length > 0 && isStringArg(nArgs - 1)) {
825
+ encNode = idxNodes[idxNodes.length - 1];
826
+ idxNodes = idxNodes.slice(0, -1);
827
+ }
828
+ if (idxNodes.length > 2)
829
+ lowerer.noLowering(`.write with ${nArgs} arguments`, call);
830
+ const encName = encNode ? bufEncoding(lowerer, "Buffer.write", encNode) : "utf8";
831
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
832
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
833
+ const offset = idxNodes[0]
834
+ ? lowerer.lowerExprExpecting(idxNodes[0], F64)
835
+ : { kind: "numLit", value: 0, type: F64, loc };
836
+ const writeArgs = [s, enc, offset, ...(idxNodes[1] ? [lowerer.lowerExprExpecting(idxNodes[1], F64)] : [])];
837
+ const receiver = lowerer.lowerExpr(access.expression);
838
+ return { kind: "bytesIntrinsic", method: "writeStr", receiver, args: writeArgs, type: F64, loc };
839
+ }
840
+ return null;
841
+ }
842
+ const DV_BIG_GETTERS = {
843
+ getBigInt64: { sign: true },
844
+ getBigUint64: { sign: false },
845
+ };
846
+ /** The number-returning DataView getter surface by source name. `le` marks
847
+ * the multi-byte kinds whose signature declares optional littleEndian;
848
+ * the BigInt pair routes through DV_BIG_GETTERS above. */
849
+ const DV_GETTERS = {
850
+ getUint8: { method: "dvGetUint8", le: false },
851
+ getInt8: { method: "dvGetInt8", le: false },
852
+ getUint16: { method: "dvGetUint16", le: true },
853
+ getInt16: { method: "dvGetInt16", le: true },
854
+ getUint32: { method: "dvGetUint32", le: true },
855
+ getInt32: { method: "dvGetInt32", le: true },
856
+ getFloat32: { method: "dvGetFloat32", le: true },
857
+ getFloat64: { method: "dvGetFloat64", le: true },
858
+ };
859
+ const DV_SETTERS = {
860
+ setUint8: { method: "dvSetUint8", le: false },
861
+ setInt8: { method: "dvSetInt8", le: false },
862
+ setUint16: { method: "dvSetUint16", le: true },
863
+ setInt16: { method: "dvSetInt16", le: true },
864
+ setUint32: { method: "dvSetUint32", le: true },
865
+ setInt32: { method: "dvSetInt32", le: true },
866
+ setFloat32: { method: "dvSetFloat32", le: true },
867
+ setFloat64: { method: "dvSetFloat64", le: true },
868
+ };
869
+ /** The Buffer statics — `Buffer.from(...)`, `Buffer.alloc(n)`,
870
+ * `Buffer.concat(list)`, `Buffer.isBuffer(x)` — on THE stdlib Buffer
871
+ * global (name + provenance; fallback and @types/node alike). Null when
872
+ * the callee isn't a Buffer-static access. */
873
+ function knownBufferProducer(lowerer, source, seen = new Set()) {
874
+ let node = source;
875
+ while (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isTypeAssertion(node))
876
+ node = node.expression;
877
+ if (ts.isIdentifier(node)) {
878
+ const symbol = lowerer.checker.getSymbolAtLocation(node);
879
+ if (!symbol || seen.has(symbol))
880
+ return false;
881
+ seen.add(symbol);
882
+ return lowerer.checker.declarationsOf(symbol).some((decl) => ts.isVariableDeclaration(decl) &&
883
+ ts.isVariableDeclarationList(decl.parent) &&
884
+ (decl.parent.flags & ts.NodeFlags.Const) !== 0 &&
885
+ decl.initializer !== undefined &&
886
+ knownBufferProducer(lowerer, decl.initializer, seen));
887
+ }
888
+ if (!ts.isCallExpression(node))
889
+ return false;
890
+ const callee = node.expression;
891
+ const bi = ts.isIdentifier(callee)
892
+ ? lowerer.builtinImportOf(callee)
893
+ : ts.isPropertyAccessExpression(callee)
894
+ ? lowerer.builtinMemberOf(callee)
895
+ : null;
896
+ if (bi?.module === "crypto" && (bi.member === "randomBytes" || bi.member === "pbkdf2Sync"))
897
+ return true;
898
+ if (!ts.isPropertyAccessExpression(callee) || callee.name.text !== "digest" || node.arguments.length !== 0)
899
+ return false;
900
+ const type = lowerer.mapTypeOf(lowerer.typeOf(callee.expression));
901
+ return type?.kind === "cryptoHash" || type?.kind === "cryptoHmac";
902
+ }
903
+ export function lowerBufferStaticCall(lowerer, call, access) {
904
+ if (call.questionDotToken || access.questionDotToken)
905
+ return null;
906
+ if (!lowerer.isStdlibGlobal(access.expression, "Buffer"))
907
+ return null;
908
+ const member = access.name.text;
909
+ const loc = locOf(call);
910
+ const args = call.arguments;
911
+ if (member === "from") {
912
+ // Buffer.from(x.buffer[, byteOffset[, length]]): a u8 VIEW sharing
913
+ // x's storage (Node shares the ArrayBuffer; length is in BYTES).
914
+ // The first argument must be the SYNTACTIC `.buffer` of a typed
915
+ // array — the DataView peel — and the construction rides the same
916
+ // dataViewNew intrinsic (offset/length validation throws Node's
917
+ // DataView-shaped RangeErrors; valid indices behave exactly).
918
+ if (args.length >= 1 && args.length <= 3 && !args.some(ts.isSpreadElement) &&
919
+ ts.isPropertyAccessExpression(args[0]) && args[0].name.text === "buffer") {
920
+ const srcNode = args[0].expression;
921
+ const srcIr = lowerer.mapTypeOf(lowerer.typeOf(srcNode));
922
+ if (srcIr?.kind === "bytes") {
923
+ const receiver = lowerer.lowerExpr(srcNode);
924
+ const idxArgs = args.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
925
+ return { kind: "bytesIntrinsic", method: "dataViewNew", receiver, args: idxArgs, type: BYTES_U8, loc };
926
+ }
927
+ }
928
+ if (args.length >= 1 && args.length <= 2 && !ts.isSpreadElement(args[0])) {
929
+ const argNode = args[0];
930
+ if (ts.isArrayLiteralExpression(argNode) && !argNode.elements.some(ts.isSpreadElement)) {
931
+ // A number[] literal (contextually typed by the lib's readonly
932
+ // number[] slot — build it element-wise, the Set-seed pattern).
933
+ if (args.length === 1) {
934
+ const elems = argNode.elements.map((el) => lowerer.lowerExprExpecting(el, F64));
935
+ const seed = { kind: "arrayLit", elems, type: arrayOf(F64), loc };
936
+ return { kind: "bytesNew", source: seed, type: BYTES_U8, loc };
937
+ }
938
+ }
939
+ else {
940
+ const srcIr = lowerer.mapTypeOf(lowerer.typeOf(argNode));
941
+ if (srcIr?.kind === "string") {
942
+ const encNode = args[1];
943
+ const encName = encNode ? bufEncoding(lowerer, "Buffer.from", encNode) : "utf8";
944
+ const s = lowerer.lowerExprExpecting(argNode, STRING);
945
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
946
+ return { kind: "libCall", fn: "buffer.fromStr", args: [s, enc], type: BYTES_U8, loc };
947
+ }
948
+ if (args.length === 1 && srcIr?.kind === "bytes" && srcIr.elem === "u8") {
949
+ return { kind: "bytesNew", source: lowerer.lowerExpr(argNode), type: BYTES_U8, loc };
950
+ }
951
+ if (args.length === 1 && srcIr?.kind === "array" && srcIr.elem.kind === "f64") {
952
+ return { kind: "bytesNew", source: lowerer.lowerExpr(argNode), type: BYTES_U8, loc };
953
+ }
954
+ }
955
+ }
956
+ lowerer.noLowering("Buffer.from with this argument shape", call, "supported: Buffer.from(string, encoding?) with a literal encoding, Buffer.from(u8Array) — a copy — " +
957
+ "Buffer.from(number[]), or Buffer.from(x.buffer, byteOffset?, length?) — a view sharing x's " +
958
+ "storage (no free-standing ArrayBuffer value exists; narrow unions first)");
959
+ }
960
+ if (member === "alloc" || member === "allocUnsafe") {
961
+ const maxArgs = member === "alloc" ? 3 : 1;
962
+ if (args.length < 1 || args.length > maxArgs || args.some(ts.isSpreadElement)) {
963
+ lowerer.noLowering(`Buffer.${member} with ${args.length} arguments`, call);
964
+ }
965
+ // allocUnsafe's contents are UNSPECIFIED in Node (uninitialized pool
966
+ // memory); a zero-filled buffer is a valid instance of unspecified,
967
+ // and the deterministic choice — a program observing the difference
968
+ // is depending on garbage.
969
+ const size = lowerer.lowerExprExpecting(args[0], F64);
970
+ const fresh = { kind: "bytesNew", source: size, type: BYTES_U8, loc };
971
+ if (args.length === 1)
972
+ return fresh;
973
+ // alloc(size, fill, encoding?): the fill semantics ARE fill()'s —
974
+ // the fresh buffer is the receiver of a whole-range fill.
975
+ const fillT = lowerer.mapTypeOf(lowerer.typeOf(args[1]));
976
+ if (fillT?.kind === "string") {
977
+ const encName = args[2] ? bufEncoding(lowerer, "Buffer.alloc", args[2]) : "utf8";
978
+ const s = lowerer.lowerExprExpecting(args[1], STRING);
979
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
980
+ return { kind: "bytesIntrinsic", method: "fillStr", receiver: fresh, args: [s, enc], type: BYTES_U8, loc };
981
+ }
982
+ if (args.length > 2) {
983
+ lowerer.noLowering("Buffer.alloc with an encoding on a non-string fill", args[2]);
984
+ }
985
+ if (fillT?.kind === "f64") {
986
+ const v = lowerer.lowerExprExpecting(args[1], F64);
987
+ return { kind: "bytesIntrinsic", method: "fillNum", receiver: fresh, args: [v], type: BYTES_U8, loc };
988
+ }
989
+ if (fillT?.kind === "bytes" && fillT.elem === "u8") {
990
+ const pattern = lowerer.lowerExpr(args[1]);
991
+ return { kind: "bytesIntrinsic", method: "fill", receiver: fresh, args: [pattern], type: BYTES_U8, loc };
992
+ }
993
+ 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");
994
+ }
995
+ if (member === "concat") {
996
+ if (args.length < 1 || args.length > 2 || args.some(ts.isSpreadElement)) {
997
+ lowerer.noLowering(`Buffer.concat with ${args.length} arguments`, call);
998
+ }
999
+ const argNode = args[0];
1000
+ let list;
1001
+ if (ts.isArrayLiteralExpression(argNode) && !argNode.elements.some(ts.isSpreadElement)) {
1002
+ const elems = argNode.elements.map((el) => lowerer.lowerExprExpecting(el, BYTES_U8));
1003
+ list = { kind: "arrayLit", elems, type: arrayOf(BYTES_U8), loc };
1004
+ }
1005
+ else {
1006
+ list = lowerer.lowerExpr(argNode);
1007
+ if (!typeEquals(list.type, arrayOf(BYTES_U8))) {
1008
+ lowerer.noLowering(`Buffer.concat of '${lowerer.fmt(list.type)}' values`, argNode, "one Uint8Array[]/Buffer[] value (or literal) is the lowered list shape");
1009
+ }
1010
+ }
1011
+ if (args.length === 2) {
1012
+ // The totalLength form truncates or zero-pads (and THROWS Node's
1013
+ // 'length' RangeError on bad totals).
1014
+ const total = lowerer.lowerExprExpecting(args[1], F64);
1015
+ return { kind: "libCall", fn: "buffer.concatLen", args: [list, total], type: BYTES_U8, loc };
1016
+ }
1017
+ return { kind: "libCall", fn: "buffer.concat", args: [list], type: BYTES_U8, loc };
1018
+ }
1019
+ if (member === "compare") {
1020
+ // The static form: Buffer.compare(a, b) IS a.compare(b).
1021
+ if (args.length !== 2 || args.some(ts.isSpreadElement)) {
1022
+ lowerer.noLowering(`Buffer.compare with ${args.length} arguments`, call);
1023
+ }
1024
+ const sides = args.map((a) => lowerer.lowerExpr(a));
1025
+ if (sides.every((v) => v.type.kind === "bytes" && v.type.elem === "u8")) {
1026
+ return { kind: "bytesIntrinsic", method: "compareBuf", receiver: sides[0], args: [sides[1]], type: F64, loc };
1027
+ }
1028
+ // A side that is not statically bytes (the invalid-input probes,
1029
+ // untyped JS helpers): Node's "buf1"/"buf2" argument ladder runs
1030
+ // at runtime — a well-typed dyn still compares.
1031
+ const dyns = sides.map((v, i) => {
1032
+ if (v.type.kind === "dyn")
1033
+ return v;
1034
+ if (v.kind === "unitLit" || lowerer.dynConvertible(v.type)) {
1035
+ return { kind: "dynFrom", value: v, type: DYN, loc: v.loc };
1036
+ }
1037
+ lowerer.noLowering(`Buffer.compare of '${lowerer.fmt(v.type)}' values`, args[i], "Buffer/Uint8Array values compare (narrow unions first)");
1038
+ });
1039
+ return { kind: "libCall", fn: "buffer.compareChk", args: dyns, type: F64, loc };
1040
+ }
1041
+ if (member === "isBuffer") {
1042
+ // The type-predicate narrowing test. Lowered where it DECIDES
1043
+ // something: a union-typed argument with a Buffer arm becomes a
1044
+ // runtime tag test (tsc's narrowing then types the branches, the
1045
+ // discriminated-union machinery). Statically-decided arguments stay
1046
+ // fenced except for standard-library calls (and const aliases of
1047
+ // them) proven to return a real Buffer; those preserve evaluation and
1048
+ // fold true even though Buffer and Uint8Array share one IR storage.
1049
+ if (args.length === 1 && !ts.isSpreadElement(args[0])) {
1050
+ const source = args[0];
1051
+ const v = lowerer.lowerExpr(args[0]);
1052
+ // The bytes IR intentionally unifies Buffer and Uint8Array storage,
1053
+ // but these standard-library producers are known to return a real
1054
+ // Node Buffer. Preserve source evaluation and fold the predicate.
1055
+ if (knownBufferProducer(lowerer, source)) {
1056
+ return {
1057
+ kind: "seqExpr",
1058
+ stmts: [{ kind: "exprStmt", expr: v, loc: v.loc }],
1059
+ result: { kind: "boolLit", value: true, type: BOOL, loc },
1060
+ type: BOOL,
1061
+ loc,
1062
+ };
1063
+ }
1064
+ if (v.type.kind === "union") {
1065
+ const def = lowerer.unions.get(v.type.unionId);
1066
+ const tag = def ? def.arms.findIndex((a) => a.kind === "bytes" && a.elem === "u8") : -1;
1067
+ if (tag >= 0) {
1068
+ return { kind: "unionIsTag", unionId: v.type.unionId, tag, negated: false, value: v, type: BOOL, loc };
1069
+ }
1070
+ }
1071
+ 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");
1072
+ }
1073
+ lowerer.noLowering("Buffer.isBuffer with this argument shape", call);
1074
+ }
1075
+ if (member === "byteLength") {
1076
+ // Buffer.byteLength(string, enc?) — the UTF-16-aware per-encoding
1077
+ // count — or of a typed array/Buffer (its byte length, a property
1078
+ // read at heart).
1079
+ if (args.length >= 1 && args.length <= 2 && !ts.isSpreadElement(args[0])) {
1080
+ const srcIr = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
1081
+ if (srcIr?.kind === "string") {
1082
+ const encName = args[1] ? bufEncoding(lowerer, "Buffer.byteLength", args[1]) : "utf8";
1083
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
1084
+ const enc = { kind: "strLit", value: encName, type: STRING, loc };
1085
+ return { kind: "libCall", fn: "buffer.byteLenStr", args: [s, enc], type: F64, loc };
1086
+ }
1087
+ if (srcIr?.kind === "bytes" && args.length === 1) {
1088
+ const receiver = lowerer.lowerExpr(args[0]);
1089
+ return { kind: "bytesIntrinsic", method: "byteLength", receiver, args: [], type: F64, loc };
1090
+ }
1091
+ }
1092
+ lowerer.noLowering("Buffer.byteLength with this argument shape", call, "supported: Buffer.byteLength(string, literalEncoding?) or Buffer.byteLength(typedArray)");
1093
+ }
1094
+ if (member === "isEncoding") {
1095
+ // The runtime alias-set test — a plain bool over any string value
1096
+ // (Node's case-insensitive normalizeEncoding check).
1097
+ if (args.length === 1 && !ts.isSpreadElement(args[0]) && lowerer.mapTypeOf(lowerer.typeOf(args[0]))?.kind === "string") {
1098
+ const s = lowerer.lowerExprExpecting(args[0], STRING);
1099
+ return { kind: "libCall", fn: "buffer.isEncoding", args: [s], type: BOOL, loc };
1100
+ }
1101
+ lowerer.noLowering("Buffer.isEncoding with this argument shape", call, "one string-typed argument is the lowered form");
1102
+ }
1103
+ return null; // of, copyBytesFrom, ... → the SC2020 member fence
1104
+ }
1105
+ //# sourceMappingURL=bytes.js.map