@scriptc/compiler 0.0.35 → 0.1.1

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 (439) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +14 -11
  2. package/ambient/scriptc-overrides.d.ts +0 -7
  3. package/ambient/scriptc.d.ts +1 -1
  4. package/dist/backend/build-cache.d.ts +44 -0
  5. package/dist/backend/build-cache.js +241 -0
  6. package/dist/backend/build-cache.js.map +1 -0
  7. package/dist/backend/{emission/emit-async.d.ts → c/async.d.ts} +21 -30
  8. package/dist/backend/{emission/emit-async.js → c/async.js} +270 -286
  9. package/dist/backend/c/async.js.map +1 -0
  10. package/dist/backend/{emission/emitter.d.ts → c/c-emitter.d.ts} +6 -23
  11. package/dist/backend/{emission/emitter.js → c/c-emitter.js} +53 -107
  12. package/dist/backend/c/c-emitter.js.map +1 -0
  13. package/dist/backend/c/exprs.d.ts +8 -0
  14. package/dist/backend/c/exprs.js +7937 -0
  15. package/dist/backend/c/exprs.js.map +1 -0
  16. package/dist/backend/{emission/emit-island.d.ts → c/island.d.ts} +5 -5
  17. package/dist/backend/{emission/emit-island.js → c/island.js} +24 -22
  18. package/dist/backend/c/island.js.map +1 -0
  19. package/dist/backend/{emission → c}/may-throw.d.ts +1 -1
  20. package/dist/backend/{emission → c}/may-throw.js +4 -1
  21. package/dist/backend/c/may-throw.js.map +1 -0
  22. package/dist/backend/{emission/emit-shapes.d.ts → c/shapes.d.ts} +19 -19
  23. package/dist/backend/{emission/emit-shapes.js → c/shapes.js} +78 -87
  24. package/dist/backend/c/shapes.js.map +1 -0
  25. package/dist/backend/{emission/emit-stmts.d.ts → c/stmts.d.ts} +12 -12
  26. package/dist/backend/{emission/emit-stmts.js → c/stmts.js} +395 -343
  27. package/dist/backend/c/stmts.js.map +1 -0
  28. package/dist/backend/{emission/emit-types.d.ts → c/types.d.ts} +1 -1
  29. package/dist/backend/{emission/emit-types.js → c/types.js} +42 -286
  30. package/dist/backend/c/types.js.map +1 -0
  31. package/dist/backend/c/types.test.js +25 -0
  32. package/dist/backend/c/types.test.js.map +1 -0
  33. package/dist/backend/{emission/emit-walkers.d.ts → c/walkers.d.ts} +19 -41
  34. package/dist/backend/{emission/emit-walkers.js → c/walkers.js} +242 -304
  35. package/dist/backend/c/walkers.js.map +1 -0
  36. package/dist/backend/external-c.d.ts +33 -0
  37. package/dist/backend/external-c.js +51 -0
  38. package/dist/backend/external-c.js.map +1 -0
  39. package/dist/backend/ffi-callbacks.d.ts +1 -1
  40. package/dist/backend/ffi-callbacks.js +4 -3
  41. package/dist/backend/ffi-callbacks.js.map +1 -1
  42. package/dist/backend/{library-identity.d.ts → library-identity-markers.d.ts} +0 -4
  43. package/dist/backend/{library-identity.js → library-identity-markers.js} +10 -9
  44. package/dist/backend/library-identity-markers.js.map +1 -0
  45. package/dist/backend/link-plan.d.ts +37 -0
  46. package/dist/backend/link-plan.js +26 -0
  47. package/dist/backend/link-plan.js.map +1 -0
  48. package/dist/backend/linker.d.ts +22 -0
  49. package/dist/backend/linker.js +236 -0
  50. package/dist/backend/linker.js.map +1 -0
  51. package/dist/backend/llvm/blocks.d.ts +4 -0
  52. package/dist/backend/llvm/blocks.js +29 -0
  53. package/dist/backend/llvm/blocks.js.map +1 -1
  54. package/dist/backend/llvm/classes.d.ts +2 -19
  55. package/dist/backend/llvm/classes.js +20 -52
  56. package/dist/backend/llvm/classes.js.map +1 -1
  57. package/dist/backend/llvm/common.d.ts +4 -0
  58. package/dist/backend/llvm/common.js +27 -0
  59. package/dist/backend/llvm/common.js.map +1 -0
  60. package/dist/backend/llvm/dyn.d.ts +3 -8
  61. package/dist/backend/llvm/dyn.js +159 -224
  62. package/dist/backend/llvm/dyn.js.map +1 -1
  63. package/dist/backend/llvm/emitter.d.ts +4 -1
  64. package/dist/backend/llvm/emitter.js +548 -9988
  65. package/dist/backend/llvm/emitter.js.map +1 -1
  66. package/dist/backend/llvm/expr-async.d.ts +4 -0
  67. package/dist/backend/llvm/expr-async.js +726 -0
  68. package/dist/backend/llvm/expr-async.js.map +1 -0
  69. package/dist/backend/llvm/expr-bytes.d.ts +13 -0
  70. package/dist/backend/llvm/expr-bytes.js +456 -0
  71. package/dist/backend/llvm/expr-bytes.js.map +1 -0
  72. package/dist/backend/llvm/expr-callbacks.d.ts +22 -0
  73. package/dist/backend/llvm/expr-callbacks.js +520 -0
  74. package/dist/backend/llvm/expr-callbacks.js.map +1 -0
  75. package/dist/backend/llvm/expr-calls.d.ts +2 -0
  76. package/dist/backend/llvm/expr-calls.js +618 -0
  77. package/dist/backend/llvm/expr-calls.js.map +1 -0
  78. package/dist/backend/llvm/expr-containers.d.ts +25 -0
  79. package/dist/backend/llvm/expr-containers.js +637 -0
  80. package/dist/backend/llvm/expr-containers.js.map +1 -0
  81. package/dist/backend/llvm/expr-context.d.ts +255 -0
  82. package/dist/backend/llvm/expr-context.js +2 -0
  83. package/dist/backend/llvm/expr-context.js.map +1 -0
  84. package/dist/backend/llvm/expr-control.d.ts +2 -0
  85. package/dist/backend/llvm/expr-control.js +473 -0
  86. package/dist/backend/llvm/expr-control.js.map +1 -0
  87. package/dist/backend/llvm/expr-dispatch.d.ts +4 -0
  88. package/dist/backend/llvm/expr-dispatch.js +153 -0
  89. package/dist/backend/llvm/expr-dispatch.js.map +1 -0
  90. package/dist/backend/llvm/expr-dynamic.d.ts +2 -0
  91. package/dist/backend/llvm/expr-dynamic.js +810 -0
  92. package/dist/backend/llvm/expr-dynamic.js.map +1 -0
  93. package/dist/backend/llvm/expr-island.d.ts +15 -0
  94. package/dist/backend/llvm/expr-island.js +690 -0
  95. package/dist/backend/llvm/expr-island.js.map +1 -0
  96. package/dist/backend/llvm/expr-primitives.d.ts +6 -0
  97. package/dist/backend/llvm/expr-primitives.js +642 -0
  98. package/dist/backend/llvm/expr-primitives.js.map +1 -0
  99. package/dist/backend/llvm/expr-records.d.ts +9 -0
  100. package/dist/backend/llvm/expr-records.js +299 -0
  101. package/dist/backend/llvm/expr-records.js.map +1 -0
  102. package/dist/backend/llvm/expr-stream-bridges.d.ts +13 -0
  103. package/dist/backend/llvm/expr-stream-bridges.js +420 -0
  104. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -0
  105. package/dist/backend/llvm/expr-stream-callbacks.d.ts +12 -0
  106. package/dist/backend/llvm/expr-stream-callbacks.js +360 -0
  107. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -0
  108. package/dist/backend/llvm/lib-dispatch.d.ts +5 -0
  109. package/dist/backend/llvm/lib-dispatch.js +267 -0
  110. package/dist/backend/llvm/lib-dispatch.js.map +1 -0
  111. package/dist/backend/llvm/lib-filesystem.d.ts +6 -0
  112. package/dist/backend/llvm/lib-filesystem.js +594 -0
  113. package/dist/backend/llvm/lib-filesystem.js.map +1 -0
  114. package/dist/backend/llvm/lib-network.d.ts +2 -0
  115. package/dist/backend/llvm/lib-network.js +429 -0
  116. package/dist/backend/llvm/lib-network.js.map +1 -0
  117. package/dist/backend/llvm/lib-process.d.ts +5 -0
  118. package/dist/backend/llvm/lib-process.js +585 -0
  119. package/dist/backend/llvm/lib-process.js.map +1 -0
  120. package/dist/backend/llvm/lib-shared.d.ts +6 -0
  121. package/dist/backend/llvm/lib-shared.js +687 -0
  122. package/dist/backend/llvm/lib-shared.js.map +1 -0
  123. package/dist/backend/llvm/lib-stream.d.ts +2 -0
  124. package/dist/backend/llvm/lib-stream.js +470 -0
  125. package/dist/backend/llvm/lib-stream.js.map +1 -0
  126. package/dist/backend/llvm/shapes.d.ts +12 -2
  127. package/dist/backend/llvm/shapes.js +66 -307
  128. package/dist/backend/llvm/shapes.js.map +1 -1
  129. package/dist/backend/llvm/shapes.test.js +52 -0
  130. package/dist/backend/llvm/shapes.test.js.map +1 -0
  131. package/dist/backend/llvm/unsupported.d.ts +1 -1
  132. package/dist/backend/llvm/walkers.d.ts +2 -3
  133. package/dist/backend/llvm/walkers.js +195 -222
  134. package/dist/backend/llvm/walkers.js.map +1 -1
  135. package/dist/backend/native-codegen.d.ts +45 -0
  136. package/dist/backend/native-codegen.js +275 -0
  137. package/dist/backend/native-codegen.js.map +1 -0
  138. package/dist/backend/native-codegen.test.js +226 -0
  139. package/dist/backend/native-codegen.test.js.map +1 -0
  140. package/dist/backend/native-link-info.d.ts +96 -0
  141. package/dist/backend/native-link-info.js +243 -0
  142. package/dist/backend/native-link-info.js.map +1 -0
  143. package/dist/backend/native-link-info.test.d.ts +1 -0
  144. package/dist/backend/native-link-info.test.js +134 -0
  145. package/dist/backend/native-link-info.test.js.map +1 -0
  146. package/dist/backend/{cc.d.ts → native-toolchain.d.ts} +54 -34
  147. package/dist/backend/{cc.js → native-toolchain.js} +231 -810
  148. package/dist/backend/native-toolchain.js.map +1 -0
  149. package/dist/backend/native-toolchain.test.d.ts +1 -0
  150. package/dist/backend/{cc-cache.test.js → native-toolchain.test.js} +219 -7
  151. package/dist/backend/native-toolchain.test.js.map +1 -0
  152. package/dist/backend/object-localize.js +1 -1
  153. package/dist/backend/runtime-abi.d.ts +10 -0
  154. package/dist/backend/runtime-abi.js +11 -0
  155. package/dist/backend/runtime-abi.js.map +1 -0
  156. package/dist/backend/runtime-pack-targets.test.d.ts +1 -0
  157. package/dist/backend/runtime-pack-targets.test.js +54 -0
  158. package/dist/backend/runtime-pack-targets.test.js.map +1 -0
  159. package/dist/backend/runtime-pack.d.ts +112 -0
  160. package/dist/backend/runtime-pack.js +305 -0
  161. package/dist/backend/runtime-pack.js.map +1 -0
  162. package/dist/backend/runtime-pack.test.d.ts +1 -0
  163. package/dist/backend/runtime-pack.test.js +473 -0
  164. package/dist/backend/runtime-pack.test.js.map +1 -0
  165. package/dist/backend/targets.d.ts +76 -0
  166. package/dist/backend/targets.js +262 -0
  167. package/dist/backend/targets.js.map +1 -0
  168. package/dist/backend/targets.test.d.ts +1 -0
  169. package/dist/backend/targets.test.js +41 -0
  170. package/dist/backend/targets.test.js.map +1 -0
  171. package/dist/backend/vendor-archives.d.ts +41 -0
  172. package/dist/backend/vendor-archives.js +462 -0
  173. package/dist/backend/vendor-archives.js.map +1 -0
  174. package/dist/compat/fetch-profile.d.ts +0 -1
  175. package/dist/compat/fetch-profile.js +0 -1
  176. package/dist/compat/fetch-profile.js.map +1 -1
  177. package/dist/coverage/report.js +3 -3
  178. package/dist/coverage/report.js.map +1 -1
  179. package/dist/coverage/surface-manifest.js +35 -33
  180. package/dist/coverage/surface-manifest.js.map +1 -1
  181. package/dist/diagnostics/diagnostic.d.ts +11 -12
  182. package/dist/diagnostics/diagnostic.js +19 -17
  183. package/dist/diagnostics/diagnostic.js.map +1 -1
  184. package/dist/diagnostics/render.d.ts +1 -1
  185. package/dist/diagnostics/render.js +1 -1
  186. package/dist/diagnostics/render.js.map +1 -1
  187. package/dist/errors.d.ts +5 -0
  188. package/dist/errors.js +9 -0
  189. package/dist/errors.js.map +1 -0
  190. package/dist/executable/{early-cache.d.ts → executable-cache.d.ts} +2 -2
  191. package/dist/executable/{early-cache.js → executable-cache.js} +36 -98
  192. package/dist/executable/executable-cache.js.map +1 -0
  193. package/dist/executable/executable-cache.test.d.ts +1 -0
  194. package/dist/executable/{early-cache.test.js → executable-cache.test.js} +3 -3
  195. package/dist/executable/executable-cache.test.js.map +1 -0
  196. package/dist/ffi/{profile.js → ffi-manifest.js} +1 -1
  197. package/dist/ffi/ffi-manifest.js.map +1 -0
  198. package/dist/frontend/builtin-modules.d.ts +21 -0
  199. package/dist/frontend/builtin-modules.js +82 -0
  200. package/dist/frontend/builtin-modules.js.map +1 -0
  201. package/dist/frontend/cjs-lexer.d.ts +7 -0
  202. package/dist/frontend/cjs-lexer.js +15 -17
  203. package/dist/frontend/cjs-lexer.js.map +1 -1
  204. package/dist/frontend/dts-paths.d.ts +26 -0
  205. package/dist/frontend/dts-paths.js +41 -0
  206. package/dist/frontend/dts-paths.js.map +1 -0
  207. package/dist/frontend/input-tracker.d.ts +0 -2
  208. package/dist/frontend/input-tracker.js +1 -4
  209. package/dist/frontend/input-tracker.js.map +1 -1
  210. package/dist/frontend/lib-contract.d.ts +1 -5
  211. package/dist/frontend/lib-contract.js +1 -1
  212. package/dist/frontend/lib-contract.js.map +1 -1
  213. package/dist/frontend/lib-exports.d.ts +1 -1
  214. package/dist/frontend/lowering/array-values.d.ts +8 -0
  215. package/dist/frontend/lowering/array-values.js +60 -0
  216. package/dist/frontend/lowering/array-values.js.map +1 -0
  217. package/dist/frontend/lowering/call-position.d.ts +4 -0
  218. package/dist/frontend/lowering/call-position.js +7 -0
  219. package/dist/frontend/lowering/call-position.js.map +1 -0
  220. package/dist/frontend/lowering/callback-arg.d.ts +20 -0
  221. package/dist/frontend/lowering/callback-arg.js +44 -0
  222. package/dist/frontend/lowering/callback-arg.js.map +1 -0
  223. package/dist/frontend/lowering/lib-boundary.d.ts +1 -1
  224. package/dist/frontend/lowering/lib-boundary.js +34 -34
  225. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  226. package/dist/frontend/lowering/lower-array-sort.d.ts +22 -0
  227. package/dist/frontend/lowering/lower-array-sort.js +619 -0
  228. package/dist/frontend/lowering/lower-array-sort.js.map +1 -0
  229. package/dist/frontend/lowering/lower-assert.d.ts +3 -3
  230. package/dist/frontend/lowering/lower-assert.js +214 -241
  231. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  232. package/dist/frontend/lowering/lower-builtins.d.ts +74 -146
  233. package/dist/frontend/lowering/lower-builtins.js +1285 -1233
  234. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  235. package/dist/frontend/lowering/lower-calls.d.ts +59 -192
  236. package/dist/frontend/lowering/lower-calls.js +1644 -1506
  237. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  238. package/dist/frontend/lowering/lower-classes.d.ts +62 -125
  239. package/dist/frontend/lowering/lower-classes.js +832 -866
  240. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  241. package/dist/frontend/lowering/lower-comptime.d.ts +5 -12
  242. package/dist/frontend/lowering/lower-comptime.js +32 -31
  243. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  244. package/dist/frontend/lowering/lower-containers.d.ts +35 -135
  245. package/dist/frontend/lowering/lower-containers.js +1984 -2227
  246. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  247. package/dist/frontend/lowering/lower-dgram.d.ts +3 -7
  248. package/dist/frontend/lowering/lower-dgram.js +97 -111
  249. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  250. package/dist/frontend/lowering/lower-enums.d.ts +4 -4
  251. package/dist/frontend/lowering/lower-enums.js +30 -30
  252. package/dist/frontend/lowering/lower-enums.js.map +1 -1
  253. package/dist/frontend/lowering/{lower-emitter.d.ts → lower-event-emitter.d.ts} +7 -18
  254. package/dist/frontend/lowering/{lower-emitter.js → lower-event-emitter.js} +172 -174
  255. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -0
  256. package/dist/frontend/lowering/lower-expando.d.ts +5 -5
  257. package/dist/frontend/lowering/lower-expando.js +40 -40
  258. package/dist/frontend/lowering/lower-expando.js.map +1 -1
  259. package/dist/frontend/lowering/lower-exprs.d.ts +60 -264
  260. package/dist/frontend/lowering/lower-exprs.js +2361 -1765
  261. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  262. package/dist/frontend/lowering/lower-generators.d.ts +6 -6
  263. package/dist/frontend/lowering/lower-generators.js +73 -72
  264. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  265. package/dist/frontend/lowering/lower-inspect.d.ts +5 -17
  266. package/dist/frontend/lowering/lower-inspect.js +273 -261
  267. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  268. package/dist/frontend/lowering/lower-island.d.ts +39 -49
  269. package/dist/frontend/lowering/lower-island.js +447 -513
  270. package/dist/frontend/lowering/lower-island.js.map +1 -1
  271. package/dist/frontend/lowering/lower-mixins.d.ts +7 -10
  272. package/dist/frontend/lowering/lower-mixins.js +85 -85
  273. package/dist/frontend/lowering/lower-mixins.js.map +1 -1
  274. package/dist/frontend/lowering/lower-modules.d.ts +12 -18
  275. package/dist/frontend/lowering/lower-modules.js +284 -283
  276. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  277. package/dist/frontend/lowering/lower-namespaces.d.ts +23 -49
  278. package/dist/frontend/lowering/lower-namespaces.js +123 -115
  279. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  280. package/dist/frontend/lowering/lower-server.d.ts +18 -25
  281. package/dist/frontend/lowering/lower-server.js +909 -899
  282. package/dist/frontend/lowering/lower-server.js.map +1 -1
  283. package/dist/frontend/lowering/lower-stmts.d.ts +30 -149
  284. package/dist/frontend/lowering/lower-stmts.js +1463 -1285
  285. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  286. package/dist/frontend/lowering/lower-stream.d.ts +12 -12
  287. package/dist/frontend/lowering/lower-stream.js +300 -301
  288. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  289. package/dist/frontend/lowering/lower-test.d.ts +5 -5
  290. package/dist/frontend/lowering/lower-test.js +82 -82
  291. package/dist/frontend/lowering/lower-test.js.map +1 -1
  292. package/dist/frontend/lowering/lowerer.d.ts +134 -22
  293. package/dist/frontend/lowering/lowerer.js +1277 -126
  294. package/dist/frontend/lowering/lowerer.js.map +1 -1
  295. package/dist/frontend/lowering/pairs-snapshot.d.ts +11 -0
  296. package/dist/frontend/lowering/pairs-snapshot.js +85 -0
  297. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -0
  298. package/dist/frontend/lowering/static-this.d.ts +6 -0
  299. package/dist/frontend/lowering/static-this.js +24 -0
  300. package/dist/frontend/lowering/static-this.js.map +1 -0
  301. package/dist/frontend/lowering/surfaces.d.ts +24 -35
  302. package/dist/frontend/lowering/surfaces.js +78 -66
  303. package/dist/frontend/lowering/surfaces.js.map +1 -1
  304. package/dist/frontend/npm-static-rewrite.js +6 -28
  305. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  306. package/dist/frontend/npm-static.d.ts +0 -10
  307. package/dist/frontend/npm-static.js +4 -7
  308. package/dist/frontend/npm-static.js.map +1 -1
  309. package/dist/frontend/npm.d.ts +0 -24
  310. package/dist/frontend/npm.js +11 -85
  311. package/dist/frontend/npm.js.map +1 -1
  312. package/dist/frontend/program.d.ts +3 -1
  313. package/dist/frontend/program.js +9 -4
  314. package/dist/frontend/program.js.map +1 -1
  315. package/dist/frontend/provenance-registry.d.ts +0 -2
  316. package/dist/frontend/provenance-registry.js +0 -10
  317. package/dist/frontend/provenance-registry.js.map +1 -1
  318. package/dist/frontend/provenance.js +4 -7
  319. package/dist/frontend/provenance.js.map +1 -1
  320. package/dist/frontend/resolve.d.ts +7 -2
  321. package/dist/frontend/resolve.js +12 -17
  322. package/dist/frontend/resolve.js.map +1 -1
  323. package/dist/frontend/resolve.test.d.ts +1 -0
  324. package/dist/frontend/resolve.test.js +29 -0
  325. package/dist/frontend/resolve.test.js.map +1 -0
  326. package/dist/frontend/ts7/adapter.d.ts +2 -2
  327. package/dist/frontend/ts7/adapter.js +1 -1
  328. package/dist/frontend/ts7/adapter.js.map +1 -1
  329. package/dist/frontend/ts7/checker.js +2 -36
  330. package/dist/frontend/ts7/checker.js.map +1 -1
  331. package/dist/frontend/ts7/enums.js +2 -1
  332. package/dist/frontend/ts7/enums.js.map +1 -1
  333. package/dist/frontend/ts7/{program.js → program-adapter.js} +7 -6
  334. package/dist/frontend/ts7/program-adapter.js.map +1 -0
  335. package/dist/frontend/ts7/world-check.d.ts +1 -3
  336. package/dist/frontend/ts7/world-check.js +3 -1
  337. package/dist/frontend/ts7/world-check.js.map +1 -1
  338. package/dist/frontend/tsc-codes.d.ts +8 -0
  339. package/dist/frontend/tsc-codes.js +109 -0
  340. package/dist/frontend/tsc-codes.js.map +1 -0
  341. package/dist/frontend/{types.d.ts → type-mapper.d.ts} +2 -25
  342. package/dist/frontend/{types.js → type-mapper.js} +12 -11
  343. package/dist/frontend/type-mapper.js.map +1 -0
  344. package/dist/frontend/workspace-registry.d.ts +26 -0
  345. package/dist/frontend/workspace-registry.js +71 -0
  346. package/dist/frontend/workspace-registry.js.map +1 -0
  347. package/dist/index.d.ts +113 -31
  348. package/dist/index.js +536 -128
  349. package/dist/index.js.map +1 -1
  350. package/dist/ir/analysis.d.ts +37 -0
  351. package/dist/ir/analysis.js +118 -0
  352. package/dist/ir/analysis.js.map +1 -0
  353. package/dist/ir/analysis.test.d.ts +1 -0
  354. package/dist/ir/analysis.test.js +21 -0
  355. package/dist/ir/analysis.test.js.map +1 -0
  356. package/dist/ir/build.d.ts +9 -0
  357. package/dist/ir/build.js +33 -0
  358. package/dist/ir/build.js.map +1 -0
  359. package/dist/ir/integer-loops.d.ts +1 -1
  360. package/dist/ir/{nodes.d.ts → ir.d.ts} +119 -37
  361. package/dist/ir/{nodes.js → ir.js} +170 -166
  362. package/dist/ir/ir.js.map +1 -0
  363. package/dist/ir/ir.test.d.ts +1 -0
  364. package/dist/ir/ir.test.js +17 -0
  365. package/dist/ir/ir.test.js.map +1 -0
  366. package/dist/ir/serialize.d.ts +2 -2
  367. package/dist/ir/serialize.js +3 -2
  368. package/dist/ir/serialize.js.map +1 -1
  369. package/dist/ir/validate.d.ts +1 -1
  370. package/dist/ir/validate.js +93 -41
  371. package/dist/ir/validate.js.map +1 -1
  372. package/dist/library/cache-primitives.d.ts +24 -0
  373. package/dist/library/cache-primitives.js +83 -0
  374. package/dist/library/cache-primitives.js.map +1 -0
  375. package/dist/library/cache-reset.test.d.ts +1 -0
  376. package/dist/library/cache-reset.test.js +47 -0
  377. package/dist/library/cache-reset.test.js.map +1 -0
  378. package/dist/library/{implementation-identity.js → compiler-self-identity.js} +1 -1
  379. package/dist/library/compiler-self-identity.js.map +1 -0
  380. package/dist/library/fence-eval.d.ts +3 -1
  381. package/dist/library/fence-eval.js +8 -2
  382. package/dist/library/fence-eval.js.map +1 -1
  383. package/dist/library/int-infer.d.ts +1 -36
  384. package/dist/library/int-infer.js +29 -18
  385. package/dist/library/int-infer.js.map +1 -1
  386. package/dist/library/int-infer.test.js +4 -4
  387. package/dist/library/{early-cache.d.ts → library-cache.d.ts} +1 -1
  388. package/dist/library/{early-cache.js → library-cache.js} +34 -89
  389. package/dist/library/library-cache.js.map +1 -0
  390. package/dist/library/library-cache.test.d.ts +1 -0
  391. package/dist/library/{early-cache.test.js → library-cache.test.js} +7 -7
  392. package/dist/library/library-cache.test.js.map +1 -0
  393. package/dist/library/{profile.d.ts → library-profile.d.ts} +4 -7
  394. package/dist/library/{profile.js → library-profile.js} +18 -11
  395. package/dist/library/library-profile.js.map +1 -0
  396. package/dist/library/semantic-source.js +2 -1
  397. package/dist/library/semantic-source.js.map +1 -1
  398. package/dist/library/sidecar.d.ts +5 -2
  399. package/dist/library/sidecar.js +11 -5
  400. package/dist/library/sidecar.js.map +1 -1
  401. package/dist/startup-cache.d.ts +11 -3
  402. package/dist/startup-cache.js +17 -2
  403. package/dist/startup-cache.js.map +1 -1
  404. package/package.json +19 -2
  405. package/surface-manifest.json +5 -5
  406. package/dist/backend/cc-cache.test.js.map +0 -1
  407. package/dist/backend/cc.js.map +0 -1
  408. package/dist/backend/emission/emit-async.js.map +0 -1
  409. package/dist/backend/emission/emit-exprs.d.ts +0 -13
  410. package/dist/backend/emission/emit-exprs.js +0 -7407
  411. package/dist/backend/emission/emit-exprs.js.map +0 -1
  412. package/dist/backend/emission/emit-island.js.map +0 -1
  413. package/dist/backend/emission/emit-shapes.js.map +0 -1
  414. package/dist/backend/emission/emit-stmts.js.map +0 -1
  415. package/dist/backend/emission/emit-types.js.map +0 -1
  416. package/dist/backend/emission/emit-walkers.js.map +0 -1
  417. package/dist/backend/emission/emitter.js.map +0 -1
  418. package/dist/backend/emission/may-throw.js.map +0 -1
  419. package/dist/backend/library-identity.js.map +0 -1
  420. package/dist/executable/early-cache.js.map +0 -1
  421. package/dist/executable/early-cache.test.js.map +0 -1
  422. package/dist/ffi/profile.js.map +0 -1
  423. package/dist/frontend/lowering/lower-emitter.js.map +0 -1
  424. package/dist/frontend/shared.d.ts +0 -82
  425. package/dist/frontend/shared.js +0 -308
  426. package/dist/frontend/shared.js.map +0 -1
  427. package/dist/frontend/ts7/program.js.map +0 -1
  428. package/dist/frontend/types.js.map +0 -1
  429. package/dist/ir/nodes.js.map +0 -1
  430. package/dist/library/early-cache.js.map +0 -1
  431. package/dist/library/early-cache.test.js.map +0 -1
  432. package/dist/library/implementation-identity.js.map +0 -1
  433. package/dist/library/profile.js.map +0 -1
  434. /package/dist/backend/{cc-cache.test.d.ts → c/types.test.d.ts} +0 -0
  435. /package/dist/{executable/early-cache.test.d.ts → backend/llvm/shapes.test.d.ts} +0 -0
  436. /package/dist/{library/early-cache.test.d.ts → backend/native-codegen.test.d.ts} +0 -0
  437. /package/dist/ffi/{profile.d.ts → ffi-manifest.d.ts} +0 -0
  438. /package/dist/frontend/ts7/{program.d.ts → program-adapter.d.ts} +0 -0
  439. /package/dist/library/{implementation-identity.d.ts → compiler-self-identity.d.ts} +0 -0
@@ -1,24 +1,26 @@
1
+ import { InternalCompilerError } from "../../errors.js";
1
2
  import { mangleField, mangleGlobal, mangleLocal, mangleRawParam } from "../mangle.js";
2
- import { BOOL, CAUGHT, RUNTIME_ERROR_CLASSES, isRefCounted } from "../../ir/nodes.js";
3
- import { boxAccess, cDecl, cStringLiteral, elemAccess, vAdapters } from "./emit-types.js";
4
- import { OVERFLOW_MEMBER } from "./emit-shapes.js";
5
- import { emitBytesReceiver } from "./emit-exprs.js";
3
+ import { BOOL, CAUGHT, RUNTIME_ERROR_CLASSES, isRefCounted } from "../../ir/ir.js";
4
+ import { boxAccess, cDecl, cStringLiteral, elemAccess, vAdapters } from "./types.js";
5
+ import { OVERFLOW_MEMBER } from "./shapes.js";
6
+ import { emitBytesReceiver } from "./exprs.js";
6
7
  import { matchIntegerBytesForLoop } from "../../ir/integer-loops.js";
7
- export function emitFunction(E, fn) {
8
- E.tempCounter = 0;
9
- E.frames = [];
10
- E.scopes = [];
11
- E.jumpTargets = [];
12
- E.tryStack = [];
13
- E.finallyStack = [];
14
- E.currentReturnType = fn.returnType;
15
- E.currentGenerator = fn.generator ?? null;
16
- E.labelCounter = 0;
17
- E.currentLocals = new Map(fn.locals.map((l) => [l.id, l]));
18
- E.captureIds = new Set((fn.captures ?? []).map((c) => c.localId));
19
- E.integerLoopBindings.clear();
20
- E.line(`${E.signature(fn)} {${E.srcComment(fn.loc)}`);
21
- E.indent++;
8
+ import { endsWithJump, matchStringSelfConcat } from "../../ir/analysis.js";
9
+ export function emitFunction(emitter, fn) {
10
+ emitter.tempCounter = 0;
11
+ emitter.frames = [];
12
+ emitter.scopes = [];
13
+ emitter.jumpTargets = [];
14
+ emitter.tryStack = [];
15
+ emitter.finallyStack = [];
16
+ emitter.currentReturnType = fn.returnType;
17
+ emitter.currentGenerator = fn.generator ?? null;
18
+ emitter.labelCounter = 0;
19
+ emitter.currentLocals = new Map(fn.locals.map((l) => [l.id, l]));
20
+ emitter.captureIds = new Set((fn.captures ?? []).map((c) => c.localId));
21
+ emitter.integerLoopBindings.clear();
22
+ emitter.line(`${emitter.signature(fn)} {${emitter.srcComment(fn.loc)}`);
23
+ emitter.indent++;
22
24
  // The pending-return slot: a `return` crossing a finally computes its
23
25
  // value FIRST (before the finally runs — snapshotting it here is what
24
26
  // makes finally mutations of returned locals invisible, Node-exact),
@@ -26,54 +28,54 @@ export function emitFunction(E, fn) {
26
28
  // the slot. Declared only when some return actually crosses a finally.
27
29
  if (fn.returnType.kind !== "void" && returnCrossesFinally(fn.body)) {
28
30
  const init = isRefCounted(fn.returnType) ? "NULL" : "0";
29
- E.line(`${cDecl(fn.returnType, "sc_pret")} = ${init}; /* pending return (through finally) */`);
31
+ emitter.line(`${cDecl(fn.returnType, "sc_pret")} = ${init}; /* pending return (through finally) */`);
30
32
  }
31
33
  // Captured bindings come in through the environment — borrowed for the
32
34
  // whole call (the closure owns them): bound here, never released here.
33
35
  (fn.captures ?? []).forEach((c, i) => {
34
- E.line(`ScrBox *${mangleLocal(c.localId)} = sc_env->caps[${i}]; /* captured ${c.name} */`);
36
+ emitter.line(`ScrBox *${mangleLocal(c.localId)} = sc_env->caps[${i}]; /* captured ${c.name} */`);
35
37
  });
36
38
  const paramIds = new Set(fn.params.map((p) => p.localId));
37
39
  for (const local of fn.locals) {
38
- if (paramIds.has(local.id) || E.captureIds.has(local.id))
40
+ if (paramIds.has(local.id) || emitter.captureIds.has(local.id))
39
41
  continue;
40
42
  if (local.boxed) {
41
- E.line(`ScrBox *${mangleLocal(local.id)} = NULL; /* ${local.name} (boxed) */`);
43
+ emitter.line(`ScrBox *${mangleLocal(local.id)} = NULL; /* ${local.name} (boxed) */`);
42
44
  }
43
45
  else {
44
46
  const init = isRefCounted(local.type) ? " = NULL" : "";
45
- E.line(`${cDecl(local.type, mangleLocal(local.id))}${init}; /* ${local.name} */`);
47
+ emitter.line(`${cDecl(local.type, mangleLocal(local.id))}${init}; /* ${local.name} */`);
46
48
  }
47
49
  }
48
50
  // Function scope owns refcounted params (callees own their params).
49
51
  // Boxed params: allocate the shared binding and move the raw value in.
50
52
  const fnScope = [];
51
53
  for (const p of fn.params) {
52
- const local = E.currentLocals.get(p.localId);
54
+ const local = emitter.currentLocals.get(p.localId);
53
55
  if (local.boxed) {
54
56
  const box = mangleLocal(p.localId);
55
- E.line(`ScrBox *${box} = ${E.boxNewC(p.type)}; /* ${p.name} (boxed param) */`);
56
- E.line(`scr_box_set_${boxAccess(p.type)}(${box}, ${mangleRawParam(p.localId)});`);
57
+ emitter.line(`ScrBox *${box} = ${emitter.boxNewC(p.type)}; /* ${p.name} (boxed param) */`);
58
+ emitter.line(`scr_box_set_${boxAccess(p.type)}(${box}, ${mangleRawParam(p.localId)});`);
57
59
  fnScope.push({ name: box, type: p.type, boxed: true });
58
60
  }
59
61
  else if (isRefCounted(p.type)) {
60
62
  fnScope.push({ name: mangleLocal(p.localId), type: p.type });
61
63
  }
62
64
  }
63
- E.scopes.push(fnScope);
64
- E.emitStmts(fn.body);
65
+ emitter.scopes.push(fnScope);
66
+ emitter.emitStmts(fn.body);
65
67
  // Implicit exit of a void function: release function-scope refcounted
66
68
  // locals (unless the body already ended in an explicit return or a
67
69
  // throw, whose unwind released everything down to depth 0).
68
70
  const last = fn.body[fn.body.length - 1]?.kind;
69
71
  const endedWithReturn = last === "return" || last === "throw" || last === "rethrow" || last === "runtimeFence";
70
72
  if (fn.returnType.kind === "void" && !endedWithReturn) {
71
- E.releaseFrame(E.scopes[0]);
73
+ emitter.releaseFrame(emitter.scopes[0]);
72
74
  }
73
- E.scopes.pop();
74
- E.indent--;
75
- E.line(`}`);
76
- E.line(``);
75
+ emitter.scopes.pop();
76
+ emitter.indent--;
77
+ emitter.line(`}`);
78
+ emitter.line(``);
77
79
  }
78
80
  /** The statement bodies nested directly under a statement — the shared
79
81
  * walk for returnCrossesFinally. */
@@ -120,29 +122,29 @@ function returnCrossesFinally(stmts) {
120
122
  * end). `setup` runs after the scope opens, before the statements — the
121
123
  * catch-binding hook: it may emit prelude lines and register entries the
122
124
  * scope owns (released on every exit, jumps and unwinds included). */
123
- export function emitBlock(E, stmts, setup) {
124
- E.line(`{`);
125
- E.indent++;
125
+ export function emitBlock(emitter, stmts, setup) {
126
+ emitter.line(`{`);
127
+ emitter.indent++;
126
128
  const scope = [];
127
- E.scopes.push(scope);
129
+ emitter.scopes.push(scope);
128
130
  setup?.(scope);
129
- E.emitStmts(stmts);
130
- const endedWithJump = E.endsWithJump(stmts);
131
- E.scopes.pop();
131
+ emitter.emitStmts(stmts);
132
+ const endedWithJump = endsWithJump(stmts);
133
+ emitter.scopes.pop();
132
134
  if (!endedWithJump)
133
- E.releaseFrame(scope);
134
- E.indent--;
135
- E.line(`}`);
135
+ emitter.releaseFrame(scope);
136
+ emitter.indent--;
137
+ emitter.line(`}`);
136
138
  }
137
- export function emitStmts(E, stmts) {
139
+ export function emitStmts(emitter, stmts) {
138
140
  for (const s of stmts)
139
- E.emitStmt(s);
141
+ emitter.emitStmt(s);
140
142
  }
141
- export function emitStmt(E, s) {
142
- E.frames.push([]);
143
+ export function emitStmt(emitter, s) {
144
+ emitter.frames.push([]);
143
145
  switch (s.kind) {
144
146
  case "varDecl": {
145
- const local = E.currentLocals.get(s.localId);
147
+ const local = emitter.currentLocals.get(s.localId);
146
148
  const target = mangleLocal(s.localId);
147
149
  if (s.init === null) {
148
150
  // Declared, uninitialized (`let x: number;`). tsc's TS2454 rejects
@@ -163,13 +165,13 @@ export function emitStmt(E, s) {
163
165
  // bit pattern to spend on it.
164
166
  const boxNew = local.tdz && boxAccess(local.type) !== "ref"
165
167
  ? "scr_box_new(SCR_BOX_ARR)"
166
- : E.boxNewC(local.type);
167
- E.line(`${target} = ${boxNew};${E.srcComment(s.loc)} /* let ${local.name}; */`);
168
- E.scopes[E.scopes.length - 1].push({ name: target, type: local.type, boxed: true });
168
+ : emitter.boxNewC(local.type);
169
+ emitter.line(`${target} = ${boxNew};${emitter.srcComment(s.loc)} /* let ${local.name}; */`);
170
+ emitter.scopes[emitter.scopes.length - 1].push({ name: target, type: local.type, boxed: true });
169
171
  }
170
172
  else if (isRefCounted(local.type)) {
171
- E.line(`${target} = NULL;${E.srcComment(s.loc)} /* let ${local.name}; */`);
172
- E.scopes[E.scopes.length - 1].push({ name: target, type: local.type });
173
+ emitter.line(`${target} = NULL;${emitter.srcComment(s.loc)} /* let ${local.name}; */`);
174
+ emitter.scopes[emitter.scopes.length - 1].push({ name: target, type: local.type });
173
175
  }
174
176
  // Scalars need nothing: the C local exists from the prologue and
175
177
  // no read happens before an assign writes it.
@@ -178,203 +180,253 @@ export function emitStmt(E, s) {
178
180
  if (local.boxed) {
179
181
  // Box FIRST, then evaluate the initializer: a named function
180
182
  // expression's closure captures this box during init evaluation.
181
- E.line(`${target} = ${E.boxNewC(local.type)};${E.srcComment(s.loc)}`);
182
- E.scopes[E.scopes.length - 1].push({ name: target, type: local.type, boxed: true });
183
- const v = E.emitExpr(s.init);
183
+ emitter.line(`${target} = ${emitter.boxNewC(local.type)};${emitter.srcComment(s.loc)}`);
184
+ emitter.scopes[emitter.scopes.length - 1].push({ name: target, type: local.type, boxed: true });
185
+ const v = emitter.emitExpr(s.init);
184
186
  if (isRefCounted(v.type))
185
- E.moveTemp(v); // the box takes ownership
186
- E.line(`scr_box_set_${boxAccess(local.type)}(${target}, ${v.name});`);
187
+ emitter.moveTemp(v); // the box takes ownership
188
+ emitter.line(`scr_box_set_${boxAccess(local.type)}(${target}, ${v.name});`);
187
189
  break;
188
190
  }
189
- const v = E.emitExpr(s.init);
190
- E.moveTemp(v);
191
- E.line(`${target} = ${v.name};${E.srcComment(s.loc)}`);
191
+ const v = emitter.emitExpr(s.init);
192
+ emitter.moveTemp(v);
193
+ emitter.line(`${target} = ${v.name};${emitter.srcComment(s.loc)}`);
192
194
  if (isRefCounted(v.type)) {
193
- E.scopes[E.scopes.length - 1].push({ name: target, type: v.type });
195
+ emitter.scopes[emitter.scopes.length - 1].push({ name: target, type: v.type });
194
196
  }
195
197
  break;
196
198
  }
197
199
  case "assign": {
198
- const local = E.currentLocals.get(s.localId);
200
+ const local = emitter.currentLocals.get(s.localId);
201
+ const concat = s.value;
202
+ const suffix = matchStringSelfConcat(s.localId, concat);
203
+ if (suffix && concat.kind === "strConcat") {
204
+ // Snapshot the old left value before evaluating the suffix. The
205
+ // snapshot is a normal frame-owned +1: the suffix may reassign the
206
+ // destination or throw, in which case unwinding must still release
207
+ // it while leaving the original binding intact.
208
+ const snapshot = emitter.emitExpr(concat.left);
209
+ const right = emitter.emitExpr(suffix);
210
+ const target = local ? mangleLocal(s.localId) : mangleGlobal(s.localId);
211
+ if (local?.boxed) {
212
+ // set_ref unlinks then releases the binding's CURRENT value. It
213
+ // may differ from snapshot when the suffix itself assigned target.
214
+ emitter.line(`scr_box_set_ref(${target}, NULL);`);
215
+ }
216
+ else {
217
+ const old = `sc_t${emitter.tempCounter++}`;
218
+ emitter.line(`ScrStr *${old} = ${target};`);
219
+ emitter.line(`${target} = NULL;`);
220
+ emitter.releaseValue(old, snapshot.type);
221
+ }
222
+ const result = emitter.newTemp(s.value.type, `scr_str_concat(${snapshot.name}, ${right.name})`);
223
+ if (local?.boxed) {
224
+ emitter.moveTemp(result); // the box takes the concat result's +1
225
+ emitter.line(`scr_box_set_ref(${target}, ${result.name});${emitter.srcComment(s.loc)}`);
226
+ }
227
+ else {
228
+ emitter.moveTemp(result); // binding takes the concat result's +1
229
+ emitter.line(`${target} = ${result.name};${emitter.srcComment(s.loc)}`);
230
+ }
231
+ break;
232
+ }
199
233
  if (!local) {
200
234
  // Module global: plain static storage, never boxed. Old-value
201
235
  // release is NULL-tolerant (statics start NULL).
202
- const g = E.globalsById.get(s.localId);
236
+ const g = emitter.globalsById.get(s.localId);
203
237
  if (!g)
204
- throw new Error(`emitter bug: assign to unknown binding ${s.localId}`);
238
+ throw new InternalCompilerError(`emitter bug: assign to unknown binding ${s.localId}`);
205
239
  const target = mangleGlobal(g.id);
206
- const v = E.emitExpr(s.value);
207
- E.moveTemp(v);
240
+ const v = emitter.emitExpr(s.value);
241
+ emitter.moveTemp(v);
208
242
  if (isRefCounted(v.type))
209
- E.releaseValue(target, v.type);
210
- E.line(`${target} = ${v.name};${E.srcComment(s.loc)}`);
243
+ emitter.releaseValue(target, v.type);
244
+ emitter.line(`${target} = ${v.name};${emitter.srcComment(s.loc)}`);
211
245
  break;
212
246
  }
213
247
  const target = mangleLocal(s.localId);
214
- const v = E.emitExpr(s.value);
248
+ const v = emitter.emitExpr(s.value);
215
249
  if (local.boxed) {
216
250
  // A scalar TDZ box (forward-captured const): the initializing
217
251
  // write mints the one-element array cell — set_ref moves it in
218
252
  // (and the empty-slot sentinel ends here).
219
253
  if (local.tdz && boxAccess(local.type) !== "ref") {
220
254
  const acc = boxAccess(local.type);
221
- const cell = `sc_t${E.tempCounter++}`;
222
- E.line(`ScrArr *${cell} = ${E.arrNewC(local.type, 1)};${E.srcComment(s.loc)}`);
223
- E.line(`scr_arr_push_${acc}(${cell}, ${v.name});`);
224
- E.line(`scr_box_set_ref(${target}, ${cell});`);
255
+ const cell = `sc_t${emitter.tempCounter++}`;
256
+ emitter.line(`ScrArr *${cell} = ${emitter.arrNewC(local.type, 1)};${emitter.srcComment(s.loc)}`);
257
+ emitter.line(`scr_arr_push_${acc}(${cell}, ${v.name});`);
258
+ emitter.line(`scr_box_set_ref(${target}, ${cell});`);
225
259
  break;
226
260
  }
227
261
  if (isRefCounted(v.type))
228
- E.moveTemp(v); // set_ref releases the old value
229
- E.line(`scr_box_set_${boxAccess(local.type)}(${target}, ${v.name});${E.srcComment(s.loc)}`);
262
+ emitter.moveTemp(v); // set_ref releases the old value
263
+ emitter.line(`scr_box_set_${boxAccess(local.type)}(${target}, ${v.name});${emitter.srcComment(s.loc)}`);
230
264
  break;
231
265
  }
232
- E.moveTemp(v);
266
+ emitter.moveTemp(v);
233
267
  if (isRefCounted(v.type))
234
- E.releaseValue(target, v.type);
235
- E.line(`${target} = ${v.name};${E.srcComment(s.loc)}`);
268
+ emitter.releaseValue(target, v.type);
269
+ emitter.line(`${target} = ${v.name};${emitter.srcComment(s.loc)}`);
236
270
  break;
237
271
  }
238
272
  case "exprStmt":
239
- E.emitExpr(s.expr);
273
+ emitter.emitExpr(s.expr);
240
274
  break;
241
275
  case "if": {
242
- const cond = E.emitCondition(s.cond);
243
- E.line(`if (${cond}) `);
244
- E.mergeBrace(() => E.emitBlock(s.then));
276
+ const cond = emitter.emitCondition(s.cond);
277
+ emitter.line(`if (${cond}) `);
278
+ emitter.mergeBrace(() => emitter.emitBlock(s.then));
245
279
  if (s.else_) {
246
- E.line(`else `);
247
- E.mergeBrace(() => E.emitBlock(s.else_));
280
+ emitter.line(`else `);
281
+ emitter.mergeBrace(() => emitter.emitBlock(s.else_));
248
282
  }
249
283
  break;
250
284
  }
251
285
  case "while": {
252
- E.line(`for (;;) {${E.srcComment(s.loc)}`);
253
- E.indent++;
254
- const cond = E.emitCondition(s.cond);
255
- E.line(`if (!(${cond})) break;`);
286
+ emitter.line(`for (;;) {${emitter.srcComment(s.loc)}`);
287
+ emitter.indent++;
288
+ const cond = emitter.emitCondition(s.cond);
289
+ emitter.line(`if (!(${cond})) break;`);
256
290
  // C continue re-evaluates the condition at the top: exactly right
257
291
  // for the unlabeled loop. A LABELED while allocates a continue
258
292
  // label placed at the END of the body (falling off it re-enters
259
293
  // the condition — the same point) so a labeled continue from a
260
294
  // NESTED loop can goto it, and a lazy end label for labeled break.
261
- const loop = E.loopTarget(null, s.labels);
262
- E.jumpTargets.push(loop);
263
- E.emitBlock(s.body);
264
- E.jumpTargets.pop();
295
+ const loop = emitter.loopTarget(null, s.labels);
296
+ emitter.jumpTargets.push(loop);
297
+ emitter.emitBlock(s.body);
298
+ emitter.jumpTargets.pop();
265
299
  if (loop.usedContinue && loop.continueLabel)
266
- E.line(`${loop.continueLabel}:;`);
267
- E.indent--;
268
- E.line(`}`);
300
+ emitter.line(`${loop.continueLabel}:;`);
301
+ emitter.indent--;
302
+ emitter.line(`}`);
269
303
  if (loop.usedEnd)
270
- E.line(`${loop.endLabel}:;`);
304
+ emitter.line(`${loop.endLabel}:;`);
271
305
  break;
272
306
  }
273
307
  case "doWhile": {
274
308
  // `for (;;) { body; cont: cond; if (!cond) break; }` — the body runs
275
309
  // before the first condition check (at least once), and `continue`
276
310
  // routes through the label so the condition still evaluates.
277
- E.line(`for (;;) {${E.srcComment(s.loc)}`);
278
- E.indent++;
279
- const loop = E.loopTarget(`sc_cont_${E.labelCounter++}`, s.labels);
280
- E.jumpTargets.push(loop);
281
- E.emitBlock(s.body);
282
- E.jumpTargets.pop();
311
+ emitter.line(`for (;;) {${emitter.srcComment(s.loc)}`);
312
+ emitter.indent++;
313
+ const loop = emitter.loopTarget(`sc_cont_${emitter.labelCounter++}`, s.labels);
314
+ emitter.jumpTargets.push(loop);
315
+ emitter.emitBlock(s.body);
316
+ emitter.jumpTargets.pop();
283
317
  if (loop.usedContinue)
284
- E.line(`${loop.continueLabel}:;`);
285
- const cond = E.emitCondition(s.cond);
286
- E.line(`if (!(${cond})) break;`);
287
- E.indent--;
288
- E.line(`}`);
318
+ emitter.line(`${loop.continueLabel}:;`);
319
+ const cond = emitter.emitCondition(s.cond);
320
+ emitter.line(`if (!(${cond})) break;`);
321
+ emitter.indent--;
322
+ emitter.line(`}`);
289
323
  if (loop.usedEnd)
290
- E.line(`${loop.endLabel}:;`);
324
+ emitter.line(`${loop.endLabel}:;`);
291
325
  break;
292
326
  }
293
327
  case "switch":
294
- E.emitSwitch(s);
328
+ emitter.emitSwitch(s);
295
329
  break;
296
330
  case "for": {
297
331
  // Desugared in place; the init's scope wraps the whole loop, so
298
332
  // break/continue must NOT release it (scopeDepth captured after).
299
- const integerLoop = matchIntegerBytesForLoop(s, E.currentLocals);
300
- E.line(`{${E.srcComment(s.loc)}`);
301
- E.indent++;
302
- E.scopes.push([]);
333
+ const integerLoop = matchIntegerBytesForLoop(s, emitter.currentLocals);
334
+ emitter.line(`{${emitter.srcComment(s.loc)}`);
335
+ emitter.indent++;
336
+ emitter.scopes.push([]);
303
337
  let integerShadow = null;
304
338
  if (integerLoop) {
305
- integerShadow = `sc_i${E.tempCounter++}`;
306
- E.line(`uint64_t ${integerShadow} = 0; /* integer induction ${E.currentLocals.get(integerLoop.localId).name} */`);
307
- E.integerLoopBindings.set(integerLoop.localId, integerShadow);
339
+ integerShadow = `sc_i${emitter.tempCounter++}`;
340
+ emitter.line(`uint64_t ${integerShadow} = 0; /* integer induction ${emitter.currentLocals.get(integerLoop.localId).name} */`);
341
+ emitter.integerLoopBindings.set(integerLoop.localId, integerShadow);
308
342
  }
309
343
  else if (s.init) {
310
- E.emitStmt(s.init);
344
+ emitter.emitStmt(s.init);
311
345
  }
312
- E.line(`for (;;) {`);
313
- E.indent++;
346
+ emitter.line(`for (;;) {`);
347
+ emitter.indent++;
314
348
  if (integerLoop && integerShadow) {
315
- const receiver = emitBytesReceiver(E, integerLoop.limitReceiver, []);
316
- E.line(`if (!(${integerShadow} < ${receiver.name}->len)) break;`);
349
+ const receiver = emitBytesReceiver(emitter, integerLoop.limitReceiver, []);
350
+ emitter.line(`if (!(${integerShadow} < ${receiver.name}->len)) break;`);
317
351
  }
318
352
  else if (s.cond) {
319
- const cond = E.emitCondition(s.cond);
320
- E.line(`if (!(${cond})) break;`);
353
+ const cond = emitter.emitCondition(s.cond);
354
+ emitter.line(`if (!(${cond})) break;`);
321
355
  }
322
356
  // C continue would skip the update; route it through a label instead.
323
- const loop = E.loopTarget(`sc_cont_${E.labelCounter++}`, s.labels);
324
- E.jumpTargets.push(loop);
325
- E.emitBlock(s.body);
326
- E.jumpTargets.pop();
357
+ const loop = emitter.loopTarget(`sc_cont_${emitter.labelCounter++}`, s.labels);
358
+ emitter.jumpTargets.push(loop);
359
+ emitter.emitBlock(s.body);
360
+ emitter.jumpTargets.pop();
327
361
  if (loop.usedContinue)
328
- E.line(`${loop.continueLabel}:;`);
362
+ emitter.line(`${loop.continueLabel}:;`);
329
363
  // JS `for (let i ...)`: each iteration gets a FRESH binding holding a
330
364
  // copy of the previous one, and the update mutates the fresh binding
331
365
  // — that's why closures made in iteration k keep seeing iteration
332
366
  // k's value. Only observable (and only emitted) when captured.
333
367
  if (s.init?.kind === "varDecl") {
334
- const initLocal = E.currentLocals.get(s.init.localId);
368
+ const initLocal = emitter.currentLocals.get(s.init.localId);
335
369
  if (initLocal?.boxed) {
336
370
  const box = mangleLocal(initLocal.id);
337
- const fresh = `sc_t${E.tempCounter++}`;
371
+ const fresh = `sc_t${emitter.tempCounter++}`;
338
372
  const acc = boxAccess(initLocal.type);
339
- E.line(`ScrBox *${fresh} = ${E.boxNewC(initLocal.type)}; /* per-iteration ${initLocal.name} */`);
340
- E.line(`scr_box_set_${acc}(${fresh}, scr_box_get_${acc}(${box}));`);
341
- E.line(`scr_box_release(${box});`);
342
- E.line(`${box} = ${fresh};`);
373
+ emitter.line(`ScrBox *${fresh} = ${emitter.boxNewC(initLocal.type)}; /* per-iteration ${initLocal.name} */`);
374
+ emitter.line(`scr_box_set_${acc}(${fresh}, scr_box_get_${acc}(${box}));`);
375
+ emitter.line(`scr_box_release(${box});`);
376
+ emitter.line(`${box} = ${fresh};`);
343
377
  // The wrapper scope's entry releases whatever `box` points to at
344
378
  // loop exit — which is now the freshest binding. Nothing to fix.
345
379
  }
346
380
  }
347
381
  if (integerLoop && integerShadow)
348
- E.line(`${integerShadow}++;`);
382
+ emitter.line(`${integerShadow}++;`);
349
383
  else if (s.update)
350
- E.emitStmt(s.update);
351
- E.indent--;
352
- E.line(`}`);
384
+ emitter.emitStmt(s.update);
385
+ emitter.indent--;
386
+ emitter.line(`}`);
353
387
  // A labeled break lands exactly where C break does: BEFORE the
354
388
  // init scope's release (the goto path must run the same releases
355
389
  // as the fall-through path).
356
390
  if (loop.usedEnd)
357
- E.line(`${loop.endLabel}:;`);
358
- E.releaseFrame(E.scopes.pop());
391
+ emitter.line(`${loop.endLabel}:;`);
392
+ emitter.releaseFrame(emitter.scopes.pop());
359
393
  if (integerLoop)
360
- E.integerLoopBindings.delete(integerLoop.localId);
361
- E.indent--;
362
- E.line(`}`);
394
+ emitter.integerLoopBindings.delete(integerLoop.localId);
395
+ emitter.indent--;
396
+ emitter.line(`}`);
363
397
  break;
364
398
  }
365
399
  case "arraySet": {
366
400
  // Evaluation order matches JS: array, index, then value. Ownership
367
401
  // of a refcounted value moves into the array (the runtime releases
368
402
  // the replaced element itself).
369
- const arr = E.emitExpr(s.arr);
370
- const idx = E.emitExpr(s.index);
371
- const v = E.emitExpr(s.value);
403
+ const arr = emitter.emitExpr(s.arr);
404
+ const idx = emitter.emitExpr(s.index);
405
+ const v = emitter.emitExpr(s.value);
372
406
  if (s.arr.type.kind !== "array")
373
- throw new Error("emitter bug: arraySet on non-array");
407
+ throw new InternalCompilerError("emitter bug: arraySet on non-array");
374
408
  const acc = elemAccess(s.arr.type.elem);
375
409
  if (acc === "ref")
376
- E.moveTemp(v);
377
- E.line(`scr_arr_set_${acc}(${arr.name}, ${idx.name}, ${v.name});${E.srcComment(s.loc)}`);
410
+ emitter.moveTemp(v);
411
+ emitter.line(`scr_arr_set_${acc}(${arr.name}, ${idx.name}, ${v.name});${emitter.srcComment(s.loc)}`);
412
+ break;
413
+ }
414
+ case "arraySetLength": {
415
+ const arr = emitter.emitExpr(s.arr);
416
+ const length = emitter.emitExpr(s.length);
417
+ if (s.arr.type.kind !== "array")
418
+ throw new InternalCompilerError("emitter bug: arraySetLength on non-array");
419
+ emitter.line(`scr_arr_set_len(${arr.name}, ${length.name});${emitter.srcComment(s.loc)}`);
420
+ emitter.emitPendingCheck();
421
+ break;
422
+ }
423
+ case "arraySetUndefined":
424
+ case "arrayDelete": {
425
+ const arr = emitter.emitExpr(s.arr);
426
+ const idx = emitter.emitExpr(s.index);
427
+ if (s.arr.type.kind !== "array")
428
+ throw new InternalCompilerError(`emitter bug: ${s.kind} on non-array`);
429
+ emitter.line(`${s.kind === "arraySetUndefined" ? "scr_arr_set_undefined" : "scr_arr_delete"}(${arr.name}, ${idx.name});${emitter.srcComment(s.loc)}`);
378
430
  break;
379
431
  }
380
432
  case "bytesSet": {
@@ -383,13 +435,13 @@ export function emitStmt(E, s) {
383
435
  // JS-exactly), so no ownership moves. Any invalid index traps — no
384
436
  // append. The IR carries the element kind; do not rediscover it in
385
437
  // the generic runtime accessor on every loop iteration.
386
- const arr = emitBytesReceiver(E, s.arr, [s.index, s.value]);
387
- const integerIndex = E.integerLoopIndex(s.index);
388
- const idx = integerIndex === null ? E.emitExpr(s.index).name : integerIndex;
389
- const v = E.emitExpr(s.value);
438
+ const arr = emitBytesReceiver(emitter, s.arr, [s.index, s.value]);
439
+ const integerIndex = emitter.integerLoopIndex(s.index);
440
+ const idx = integerIndex === null ? emitter.emitExpr(s.index).name : integerIndex;
441
+ const v = emitter.emitExpr(s.value);
390
442
  if (s.arr.type.kind !== "bytes")
391
- throw new Error("emitter bug: bytesSet on non-bytes");
392
- E.line(`${E.bytesElementHelper("set", s.arr.type.elem, integerIndex !== null)}(${arr.name}, ${idx}, ${v.name});${E.srcComment(s.loc)}`);
443
+ throw new InternalCompilerError("emitter bug: bytesSet on non-bytes");
444
+ emitter.line(`${emitter.bytesElementHelper("set", s.arr.type.elem, integerIndex !== null)}(${arr.name}, ${idx}, ${v.name});${emitter.srcComment(s.loc)}`);
393
445
  break;
394
446
  }
395
447
  case "fieldSet":
@@ -401,31 +453,31 @@ export function emitStmt(E, s) {
401
453
  // cycle collection, which must never see a heap edge whose count
402
454
  // was already given up (scr_cycle.c). Classes and records share
403
455
  // the struct layout, so one emission.
404
- const obj = E.emitExpr(s.obj);
405
- const v = E.emitExpr(s.value);
456
+ const obj = emitter.emitExpr(s.obj);
457
+ const v = emitter.emitExpr(s.value);
406
458
  // Runtime error classes use ScrError's own member names.
407
459
  const member = s.kind === "fieldSet" && RUNTIME_ERROR_CLASSES.has(s.className)
408
460
  ? s.field
409
461
  : mangleField(s.field);
410
462
  const field = `${obj.name}->${member}`;
411
463
  if (isRefCounted(v.type)) {
412
- E.moveTemp(v);
413
- const old = `sc_t${E.tempCounter++}`;
414
- E.line(`${cDecl(v.type, old)} = ${field};`);
415
- E.line(`${field} = ${v.name};${E.srcComment(s.loc)}`);
416
- E.releaseValue(old, v.type);
464
+ emitter.moveTemp(v);
465
+ const old = `sc_t${emitter.tempCounter++}`;
466
+ emitter.line(`${cDecl(v.type, old)} = ${field};`);
467
+ emitter.line(`${field} = ${v.name};${emitter.srcComment(s.loc)}`);
468
+ emitter.releaseValue(old, v.type);
417
469
  }
418
470
  else {
419
- E.line(`${field} = ${v.name};${E.srcComment(s.loc)}`);
471
+ emitter.line(`${field} = ${v.name};${emitter.srcComment(s.loc)}`);
420
472
  }
421
473
  break;
422
474
  }
423
475
  case "recordKeyDelete": {
424
476
  // `delete obj[k]` on a pure index-signature shape: a Map delete on
425
477
  // the overflow (key and value released; absent keys no-op).
426
- const obj = E.emitExpr(s.obj);
427
- const key = E.emitExpr(s.key);
428
- E.line(`scr_map_delete_str(${obj.name}->${OVERFLOW_MEMBER}, ${key.name});${E.srcComment(s.loc)}`);
478
+ const obj = emitter.emitExpr(s.obj);
479
+ const key = emitter.emitExpr(s.key);
480
+ emitter.line(`scr_map_delete_str(${obj.name}->${OVERFLOW_MEMBER}, ${key.name});${emitter.srcComment(s.loc)}`);
429
481
  break;
430
482
  }
431
483
  case "recordKeySet": {
@@ -434,25 +486,25 @@ export function emitStmt(E, s) {
434
486
  // overflow map). Evaluation order: obj, key, value. The helper OWNS
435
487
  // the value (+1 moves in). MAY THROW when a dyn value must validate
436
488
  // against a declared field's type — the pending check runs then.
437
- const obj = E.emitExpr(s.obj);
438
- const key = E.emitExpr(s.key);
439
- const v = E.emitExpr(s.value);
489
+ const obj = emitter.emitExpr(s.obj);
490
+ const key = emitter.emitExpr(s.key);
491
+ const v = emitter.emitExpr(s.value);
440
492
  if (isRefCounted(v.type))
441
- E.moveTemp(v);
493
+ emitter.moveTemp(v);
442
494
  // A LITERAL key naming no declared field is a plain overflow map
443
495
  // insert — no helper, no validation, no throw.
444
496
  if (s.overflowOnly) {
445
497
  const acc = v.type.kind === "f64" ? "f64" : v.type.kind === "bool" ? "bool" : "ref";
446
- E.line(`scr_map_set_str_${acc}(${obj.name}->${OVERFLOW_MEMBER}, ${key.name}, ${v.name});${E.srcComment(s.loc)}`);
498
+ emitter.line(`scr_map_set_str_${acc}(${obj.name}->${OVERFLOW_MEMBER}, ${key.name}, ${v.name});${emitter.srcComment(s.loc)}`);
447
499
  break;
448
500
  }
449
- const helper = E.recordKeySetHelper(s.shapeId);
450
- E.line(`${helper}(${obj.name}, ${key.name}, ${v.name});${E.srcComment(s.loc)}`);
451
- const shape = E.recordsById.get(s.shapeId);
501
+ const helper = emitter.recordKeySetHelper(s.shapeId);
502
+ emitter.line(`${helper}(${obj.name}, ${key.name}, ${v.name});${emitter.srcComment(s.loc)}`);
503
+ const shape = emitter.recordsById.get(s.shapeId);
452
504
  // MAY THROW: a dyn value validating against a declared field, or a
453
505
  // signature-free shape's key MISS (scr_record_key_miss).
454
506
  if (shape && (!shape.indexValue || (shape.indexValue.kind === "dyn" && shape.fields.length > 0))) {
455
- E.emitPendingCheck();
507
+ emitter.emitPendingCheck();
456
508
  }
457
509
  break;
458
510
  }
@@ -463,72 +515,72 @@ export function emitStmt(E, s) {
463
515
  // when the whole loop ends (and by `return`'s frame sweep). A real
464
516
  // C for-loop makes plain `continue` correct: the update still runs.
465
517
  if (s.iterable.type.kind !== "array")
466
- throw new Error("emitter bug: forOf over non-array");
518
+ throw new InternalCompilerError("emitter bug: forOf over non-array");
467
519
  const elem = s.iterable.type.elem;
468
- const arr = E.emitExpr(s.iterable);
469
- const idx = `sc_t${E.tempCounter++}`;
470
- E.line(`for (double ${idx} = 0; ${idx} < scr_arr_len(${arr.name}); ${idx} += 1) {${E.srcComment(s.loc)}`);
471
- E.indent++;
520
+ const arr = emitter.emitExpr(s.iterable);
521
+ const idx = `sc_t${emitter.tempCounter++}`;
522
+ emitter.line(`for (double ${idx} = 0; ${idx} < scr_arr_len(${arr.name}); ${idx} += 1) {${emitter.srcComment(s.loc)}`);
523
+ emitter.indent++;
472
524
  // A real C for-loop makes plain `continue` correct (the update
473
525
  // still runs); a LABELED forOf allocates a continue label placed at
474
526
  // the END of the iteration (after the per-iteration scope release —
475
527
  // the goto path released it itself) so nested loops can goto it.
476
- const loop = E.loopTarget(null, s.labels);
477
- E.jumpTargets.push(loop);
528
+ const loop = emitter.loopTarget(null, s.labels);
529
+ emitter.jumpTargets.push(loop);
478
530
  // The loop variable is a fresh const per iteration: its scope opens
479
531
  // here, holds the (for ref elements: owned +1) current element, and
480
532
  // releases it at the end of each iteration.
481
- E.scopes.push([]);
533
+ emitter.scopes.push([]);
482
534
  const local = mangleLocal(s.localId);
483
- const localInfo = E.currentLocals.get(s.localId);
535
+ const localInfo = emitter.currentLocals.get(s.localId);
484
536
  if (localInfo?.boxed) {
485
537
  // Captured loop variable: a fresh box per iteration, matching the
486
538
  // fresh const binding (closures made in iteration k keep seeing
487
539
  // iteration k's element). The box takes ownership of a ref
488
540
  // element's +1 and is released with the iteration's scope.
489
- E.line(`${local} = ${E.boxNewC(elem)}; /* per-iteration ${localInfo.name} */`);
490
- E.line(`scr_box_set_${boxAccess(elem)}(${local}, scr_arr_get_${elemAccess(elem)}(${arr.name}, ${idx}));`);
491
- E.scopes[E.scopes.length - 1].push({ name: local, type: elem, boxed: true });
541
+ emitter.line(`${local} = ${emitter.boxNewC(elem)}; /* per-iteration ${localInfo.name} */`);
542
+ emitter.line(`scr_box_set_${boxAccess(elem)}(${local}, scr_arr_get_${elemAccess(elem)}(${arr.name}, ${idx}));`);
543
+ emitter.scopes[emitter.scopes.length - 1].push({ name: local, type: elem, boxed: true });
492
544
  }
493
545
  else {
494
- E.line(`${local} = scr_arr_get_${elemAccess(elem)}(${arr.name}, ${idx});`);
546
+ emitter.line(`${local} = scr_arr_get_${elemAccess(elem)}(${arr.name}, ${idx});`);
495
547
  if (isRefCounted(elem))
496
- E.scopes[E.scopes.length - 1].push({ name: local, type: elem });
548
+ emitter.scopes[emitter.scopes.length - 1].push({ name: local, type: elem });
497
549
  }
498
- E.emitStmts(s.body);
499
- const endedWithJump = E.endsWithJump(s.body);
500
- const scope = E.scopes.pop();
550
+ emitter.emitStmts(s.body);
551
+ const endedWithJump = endsWithJump(s.body);
552
+ const scope = emitter.scopes.pop();
501
553
  if (!endedWithJump)
502
- E.releaseFrame(scope);
503
- E.jumpTargets.pop();
554
+ emitter.releaseFrame(scope);
555
+ emitter.jumpTargets.pop();
504
556
  if (loop.usedContinue && loop.continueLabel)
505
- E.line(`${loop.continueLabel}:;`);
506
- E.indent--;
507
- E.line(`}`);
557
+ emitter.line(`${loop.continueLabel}:;`);
558
+ emitter.indent--;
559
+ emitter.line(`}`);
508
560
  if (loop.usedEnd)
509
- E.line(`${loop.endLabel}:;`);
561
+ emitter.line(`${loop.endLabel}:;`);
510
562
  break;
511
563
  }
512
564
  case "block": {
513
565
  if (s.labels === undefined) {
514
- E.emitBlock(s.body);
566
+ emitter.emitBlock(s.body);
515
567
  break;
516
568
  }
517
569
  // A labeled block: `break lbl` inside jumps to the end label
518
570
  // (releasing the block's scope itself); nothing else can target it.
519
571
  const target = {
520
572
  kind: "block",
521
- endLabel: `sc_end_${E.labelCounter++}`,
573
+ endLabel: `sc_end_${emitter.labelCounter++}`,
522
574
  usedEnd: false,
523
575
  labels: s.labels,
524
- scopeDepth: E.scopes.length,
525
- frameDepth: E.frames.length,
576
+ scopeDepth: emitter.scopes.length,
577
+ frameDepth: emitter.frames.length,
526
578
  };
527
- E.jumpTargets.push(target);
528
- E.emitBlock(s.body);
529
- E.jumpTargets.pop();
579
+ emitter.jumpTargets.push(target);
580
+ emitter.emitBlock(s.body);
581
+ emitter.jumpTargets.pop();
530
582
  if (target.usedEnd)
531
- E.line(`${target.endLabel}:;`);
583
+ emitter.line(`${target.endLabel}:;`);
532
584
  break;
533
585
  }
534
586
  case "break": {
@@ -542,16 +594,16 @@ export function emitStmt(E, s) {
542
594
  // loop's releases after the loop and a switch's after its end
543
595
  // label are still on this jump's path.
544
596
  let target;
545
- for (let i = E.jumpTargets.length - 1; i >= 0; i--) {
546
- const t = E.jumpTargets[i];
597
+ for (let i = emitter.jumpTargets.length - 1; i >= 0; i--) {
598
+ const t = emitter.jumpTargets[i];
547
599
  if (s.label !== undefined ? t.labels?.includes(s.label) : t.kind !== "block") {
548
600
  target = t;
549
601
  break;
550
602
  }
551
603
  }
552
604
  if (!target)
553
- throw new Error("emitter bug: break target not found");
554
- E.releaseForJump(target.frameDepth, target.scopeDepth);
605
+ throw new InternalCompilerError("emitter bug: break target not found");
606
+ emitter.releaseForJump(target.frameDepth, target.scopeDepth);
555
607
  if (target.kind !== "loop" || s.label !== undefined) {
556
608
  // Switches are emitted as goto chains and blocks aren't C loops
557
609
  // at all, so a C `break` cannot target either; and a LABELED
@@ -559,10 +611,10 @@ export function emitStmt(E, s) {
559
611
  // All three jump to the target's end label (labeled loops always
560
612
  // allocate one — loopTarget).
561
613
  target.usedEnd = true;
562
- E.line(`goto ${target.endLabel};${E.srcComment(s.loc)}`);
614
+ emitter.line(`goto ${target.endLabel};${emitter.srcComment(s.loc)}`);
563
615
  }
564
616
  else {
565
- E.line(`break;${E.srcComment(s.loc)}`);
617
+ emitter.line(`break;${emitter.srcComment(s.loc)}`);
566
618
  }
567
619
  break;
568
620
  }
@@ -571,30 +623,30 @@ export function emitStmt(E, s) {
571
623
  // labeled blocks in between (their scopes are still released — the
572
624
  // jump exits them). Labeled: binds to the loop carrying the label.
573
625
  let loop;
574
- for (let i = E.jumpTargets.length - 1; i >= 0; i--) {
575
- const t = E.jumpTargets[i];
626
+ for (let i = emitter.jumpTargets.length - 1; i >= 0; i--) {
627
+ const t = emitter.jumpTargets[i];
576
628
  if (t.kind === "loop" && (s.label === undefined || t.labels?.includes(s.label))) {
577
629
  loop = t;
578
630
  break;
579
631
  }
580
632
  }
581
633
  if (!loop)
582
- throw new Error("emitter bug: continue target not found");
583
- E.releaseForJump(loop.frameDepth, loop.scopeDepth);
634
+ throw new InternalCompilerError("emitter bug: continue target not found");
635
+ emitter.releaseForJump(loop.frameDepth, loop.scopeDepth);
584
636
  if (loop.continueLabel) {
585
637
  // Labeled loops always allocate one (a labeled continue may
586
638
  // target an outer loop a C continue could never reach); for/
587
639
  // do-while allocate one for their update/condition point.
588
640
  loop.usedContinue = true;
589
- E.line(`goto ${loop.continueLabel};${E.srcComment(s.loc)}`);
641
+ emitter.line(`goto ${loop.continueLabel};${emitter.srcComment(s.loc)}`);
590
642
  }
591
643
  else {
592
- E.line(`continue;${E.srcComment(s.loc)}`);
644
+ emitter.line(`continue;${emitter.srcComment(s.loc)}`);
593
645
  }
594
646
  break;
595
647
  }
596
648
  case "return": {
597
- const fin = E.finallyStack[E.finallyStack.length - 1];
649
+ const fin = emitter.finallyStack[emitter.finallyStack.length - 1];
598
650
  if (fin) {
599
651
  // Crossing ≥1 finally: the value is computed and snapshotted
600
652
  // FIRST (a finally mutating the returned local cannot change
@@ -602,26 +654,26 @@ export function emitStmt(E, s) {
602
654
  // region releases and control runs that region's pending-return
603
655
  // finally copy; its tail dispatches further out or returns.
604
656
  if (s.value) {
605
- const v = E.emitExpr(s.value);
606
- E.moveTemp(v); // ownership parks in the slot until the dispatch returns it
607
- E.line(`sc_pret = ${v.name};${E.srcComment(s.loc)}`);
657
+ const v = emitter.emitExpr(s.value);
658
+ emitter.moveTemp(v); // ownership parks in the slot until the dispatch returns it
659
+ emitter.line(`sc_pret = ${v.name};${emitter.srcComment(s.loc)}`);
608
660
  }
609
661
  fin.used = true;
610
- E.releaseForJump(fin.frameDepth, fin.scopeDepth);
611
- E.line(`goto ${fin.label};${s.value ? "" : E.srcComment(s.loc)}`);
662
+ emitter.releaseForJump(fin.frameDepth, fin.scopeDepth);
663
+ emitter.line(`goto ${fin.label};${s.value ? "" : emitter.srcComment(s.loc)}`);
612
664
  break;
613
665
  }
614
666
  if (s.value) {
615
- const v = E.emitExpr(s.value);
616
- E.moveTemp(v);
667
+ const v = emitter.emitExpr(s.value);
668
+ emitter.moveTemp(v);
617
669
  // Everything down to function depth releases; the moved result is
618
670
  // exempt (already struck from its frame).
619
- E.releaseForJump(0, 0);
620
- E.line(`return ${v.name};${E.srcComment(s.loc)}`);
671
+ emitter.releaseForJump(0, 0);
672
+ emitter.line(`return ${v.name};${emitter.srcComment(s.loc)}`);
621
673
  }
622
674
  else {
623
- E.releaseForJump(0, 0);
624
- E.line(`return;${E.srcComment(s.loc)}`);
675
+ emitter.releaseForJump(0, 0);
676
+ emitter.line(`return;${emitter.srcComment(s.loc)}`);
625
677
  }
626
678
  break;
627
679
  }
@@ -629,34 +681,34 @@ export function emitStmt(E, s) {
629
681
  // Evaluate, move ownership into the runtime's exception cell, then
630
682
  // unwind unconditionally (the innermost try handler, or out of the
631
683
  // function) — the same release path as return/break/continue.
632
- const v = E.emitExpr(s.value);
684
+ const v = emitter.emitExpr(s.value);
633
685
  const t = s.value.type;
634
686
  if (isRefCounted(t))
635
- E.moveTemp(v); // the cell takes ownership
687
+ emitter.moveTemp(v); // the cell takes ownership
636
688
  if (t.kind === "date") {
637
- throw new Error("emitter bug: Date throw reached backend");
689
+ throw new InternalCompilerError("emitter bug: Date throw reached backend");
638
690
  }
639
691
  else if (t.kind === "f64") {
640
- E.line(`scr_throw_f64(${v.name});${E.srcComment(s.loc)}`);
692
+ emitter.line(`scr_throw_f64(${v.name});${emitter.srcComment(s.loc)}`);
641
693
  }
642
694
  else if (t.kind === "bool") {
643
- E.line(`scr_throw_bool(${v.name});${E.srcComment(s.loc)}`);
695
+ emitter.line(`scr_throw_bool(${v.name});${emitter.srcComment(s.loc)}`);
644
696
  }
645
697
  else if (t.kind === "string") {
646
- E.line(`scr_throw_str(${v.name});${E.srcComment(s.loc)}`);
698
+ emitter.line(`scr_throw_str(${v.name});${emitter.srcComment(s.loc)}`);
647
699
  }
648
- else if (t.kind === "object" && E.classMeta.get(t.className)?.hierarchy) {
700
+ else if (t.kind === "object" && emitter.classMeta.get(t.className)?.hierarchy) {
649
701
  // Hierarchy instances carry a vtable word: the OBJ kind keeps the
650
702
  // dynamic class inspectable (catch-binding instanceof, and the
651
703
  // uncaught printer's "name: message" for Error instances).
652
704
  const rc = vAdapters(t);
653
- E.line(`scr_throw_obj(${v.name}, &${rc.retain}, &${rc.release}, ${E.traceArgC(t)});${E.srcComment(s.loc)}`);
705
+ emitter.line(`scr_throw_obj(${v.name}, &${rc.retain}, &${rc.release}, ${emitter.traceArgC(t)});${emitter.srcComment(s.loc)}`);
654
706
  }
655
707
  else {
656
708
  const rc = vAdapters(t);
657
- E.line(`scr_throw_ref(${v.name}, &${rc.retain}, &${rc.release}, ${E.traceArgC(t)});${E.srcComment(s.loc)}`);
709
+ emitter.line(`scr_throw_ref(${v.name}, &${rc.retain}, &${rc.release}, ${emitter.traceArgC(t)});${emitter.srcComment(s.loc)}`);
658
710
  }
659
- E.emitUnwind();
711
+ emitter.emitUnwind();
660
712
  break;
661
713
  }
662
714
  case "runtimeFence": {
@@ -664,29 +716,29 @@ export function emitStmt(E, s) {
664
716
  // the construct (message) with the SC code stamped on `code`,
665
717
  // then unwind exactly like `throw`.
666
718
  const bytes = Buffer.from(s.message, "utf8");
667
- E.line(`scr_throw_error_msg_code(SCR_ERR_ERROR, ${cStringLiteral(bytes)}, ${bytes.length}, "${s.code}");${E.srcComment(s.loc)}`);
668
- E.emitUnwind();
719
+ emitter.line(`scr_throw_error_msg_code(SCR_ERR_ERROR, ${cStringLiteral(bytes)}, ${bytes.length}, "${s.code}");${emitter.srcComment(s.loc)}`);
720
+ emitter.emitUnwind();
669
721
  break;
670
722
  }
671
723
  case "rethrow":
672
724
  // Re-raise the saved snapshot (payload retained — the binding local
673
725
  // releases with its scope) and unwind like `throw`.
674
- E.line(`scr_rethrow(${mangleLocal(s.localId)});${E.srcComment(s.loc)}`);
675
- E.emitUnwind();
726
+ emitter.line(`scr_rethrow(${mangleLocal(s.localId)});${emitter.srcComment(s.loc)}`);
727
+ emitter.emitUnwind();
676
728
  break;
677
729
  case "tryCatch":
678
- E.emitTryCatch(s);
730
+ emitter.emitTryCatch(s);
679
731
  break;
680
732
  default: {
681
733
  const _exhaustive = s;
682
734
  void _exhaustive;
683
735
  }
684
736
  }
685
- const frame = E.frames.pop();
737
+ const frame = emitter.frames.pop();
686
738
  // return/throw already released their frames on the jump path; emitting
687
739
  // the fall-through releases after them would be dead double-release code.
688
740
  if (s.kind !== "return" && s.kind !== "throw" && s.kind !== "rethrow" && s.kind !== "runtimeFence")
689
- E.releaseFrame(frame);
741
+ emitter.releaseFrame(frame);
690
742
  }
691
743
  /** try/catch/finally via pending-flag unwinding. Entering a try emits NO
692
744
  * code: the try context is compile-time state (tryStack) that redirects
@@ -719,8 +771,8 @@ export function emitStmt(E, s) {
719
771
  * normal, exception, and pending-return are the only paths a finally
720
772
  * must model; jumps out of PLAIN try/catch need nothing here —
721
773
  * release-on-jump already walks the try scopes. */
722
- export function emitTryCatch(E, s) {
723
- const id = E.labelCounter++;
774
+ export function emitTryCatch(emitter, s) {
775
+ const id = emitter.labelCounter++;
724
776
  const hasCatch = s.catchBody !== null;
725
777
  const hasFinally = s.finallyBody !== null;
726
778
  const catchLabel = `sc_catch_${id}`;
@@ -732,8 +784,8 @@ export function emitTryCatch(E, s) {
732
784
  const handler = {
733
785
  label: hasCatch ? catchLabel : finExcLabel,
734
786
  used: false,
735
- frameDepth: E.frames.length,
736
- scopeDepth: E.scopes.length,
787
+ frameDepth: emitter.frames.length,
788
+ scopeDepth: emitter.scopes.length,
737
789
  };
738
790
  // The pending-return region: returns inside tryBody/catchBody snapshot
739
791
  // their value and jump here-ish (the pending-return finally copy below)
@@ -742,77 +794,77 @@ export function emitTryCatch(E, s) {
742
794
  ? {
743
795
  label: `sc_finret_${id}`,
744
796
  used: false,
745
- frameDepth: E.frames.length,
746
- scopeDepth: E.scopes.length,
797
+ frameDepth: emitter.frames.length,
798
+ scopeDepth: emitter.scopes.length,
747
799
  }
748
800
  : null;
749
- E.line(`/* try */${E.srcComment(s.loc)}`);
801
+ emitter.line(`/* try */${emitter.srcComment(s.loc)}`);
750
802
  if (retEntry)
751
- E.finallyStack.push(retEntry);
752
- E.tryStack.push(handler);
753
- E.emitBlock(s.tryBody);
754
- E.tryStack.pop();
803
+ emitter.finallyStack.push(retEntry);
804
+ emitter.tryStack.push(handler);
805
+ emitter.emitBlock(s.tryBody);
806
+ emitter.tryStack.pop();
755
807
  // Exceptions raised in the CATCH body unwind to the exception-path
756
808
  // finally (pending stays set through it) when one exists.
757
809
  const excHandler = {
758
810
  label: finExcLabel,
759
811
  used: !hasCatch && handler.used,
760
- frameDepth: E.frames.length,
761
- scopeDepth: E.scopes.length,
812
+ frameDepth: emitter.frames.length,
813
+ scopeDepth: emitter.scopes.length,
762
814
  };
763
815
  if (hasCatch && handler.used) {
764
- if (!E.endsWithJump(s.tryBody)) {
765
- E.line(`goto ${afterTryLabel};`);
816
+ if (!endsWithJump(s.tryBody)) {
817
+ emitter.line(`goto ${afterTryLabel};`);
766
818
  afterTryLabelUsed = true;
767
819
  }
768
820
  if (hasFinally)
769
- E.tryStack.push(excHandler);
821
+ emitter.tryStack.push(excHandler);
770
822
  // Generator bodies: a pending GENRET sentinel (.return(v) injected at
771
823
  // a yield) is a RETURN completion, not a throw — catch must not take
772
824
  // it. Re-unwind past this handler (finally still runs — the unwind
773
825
  // targets the exception-path finally or the enclosing context; the
774
826
  // runtime depths here equal the handler's, so no double release).
775
827
  const genretPrologue = () => {
776
- if (E.currentGenerator === null)
828
+ if (emitter.currentGenerator === null)
777
829
  return;
778
- E.line(`if (scr_exc_genret_pending()) { /* .return(): not catchable */`);
779
- E.indent++;
780
- E.emitUnwind();
781
- E.indent--;
782
- E.line(`}`);
830
+ emitter.line(`if (scr_exc_genret_pending()) { /* .return(): not catchable */`);
831
+ emitter.indent++;
832
+ emitter.emitUnwind();
833
+ emitter.indent--;
834
+ emitter.line(`}`);
783
835
  };
784
836
  if (s.catchLocalId !== null) {
785
837
  // catch (e): the exception MOVES into the binding's snapshot box,
786
838
  // owned by the catch body's scope (released on every exit — normal
787
839
  // fall-through, jumps out, and unwinds from the body).
788
840
  const binding = mangleLocal(s.catchLocalId);
789
- E.line(`${catchLabel}:; /* catch (${E.currentLocals.get(s.catchLocalId)?.name ?? "e"}) — takes the exception */`);
841
+ emitter.line(`${catchLabel}:; /* catch (${emitter.currentLocals.get(s.catchLocalId)?.name ?? "e"}) — takes the exception */`);
790
842
  genretPrologue();
791
- E.emitBlock(s.catchBody, (scope) => {
792
- E.line(`${binding} = scr_exc_take();`);
843
+ emitter.emitBlock(s.catchBody, (scope) => {
844
+ emitter.line(`${binding} = scr_exc_take();`);
793
845
  scope.push({ name: binding, type: CAUGHT });
794
846
  });
795
847
  }
796
848
  else {
797
- E.line(`${catchLabel}:; /* catch — takes the exception */`);
849
+ emitter.line(`${catchLabel}:; /* catch — takes the exception */`);
798
850
  genretPrologue();
799
- E.line(`scr_exc_clear();`);
800
- E.emitBlock(s.catchBody);
851
+ emitter.line(`scr_exc_clear();`);
852
+ emitter.emitBlock(s.catchBody);
801
853
  }
802
854
  if (hasFinally)
803
- E.tryStack.pop();
855
+ emitter.tryStack.pop();
804
856
  // Normal completion of the catch falls through to afterTryLabel.
805
857
  }
806
858
  if (retEntry)
807
- E.finallyStack.pop();
859
+ emitter.finallyStack.pop();
808
860
  if (hasFinally) {
809
861
  if (afterTryLabelUsed)
810
- E.line(`${afterTryLabel}:;`);
811
- E.line(`/* finally (normal path) */`);
812
- E.emitBlock(s.finallyBody);
862
+ emitter.line(`${afterTryLabel}:;`);
863
+ emitter.line(`/* finally (normal path) */`);
864
+ emitter.emitBlock(s.finallyBody);
813
865
  const needEnd = excHandler.used || retEntry.used;
814
866
  if (needEnd)
815
- E.line(`goto ${endLabel};`);
867
+ emitter.line(`goto ${endLabel};`);
816
868
  if (excHandler.used) {
817
869
  // The pending exception is STASHED across the finally body (a
818
870
  // ScrCaught snapshot, re-raised after) so the body runs with a
@@ -825,14 +877,14 @@ export function emitTryCatch(E, s) {
825
877
  // JS's replace semantics); normal completion re-raises the stash
826
878
  // and keeps propagating.
827
879
  const stash = `sc_fexc_${id}`;
828
- E.line(`${finExcLabel}:; /* finally (exception path — stashed) */`);
829
- E.line(`ScrCaught *${stash} = scr_exc_take();`);
830
- E.scopes.push([{ name: stash, type: CAUGHT }]);
831
- E.emitBlock(s.finallyBody);
832
- E.scopes.pop(); // normal completion keeps the stash for the re-raise
833
- E.line(`scr_rethrow(${stash});`);
834
- E.line(`scr_caught_release(${stash});`);
835
- E.emitUnwind();
880
+ emitter.line(`${finExcLabel}:; /* finally (exception path — stashed) */`);
881
+ emitter.line(`ScrCaught *${stash} = scr_exc_take();`);
882
+ emitter.scopes.push([{ name: stash, type: CAUGHT }]);
883
+ emitter.emitBlock(s.finallyBody);
884
+ emitter.scopes.pop(); // normal completion keeps the stash for the re-raise
885
+ emitter.line(`scr_rethrow(${stash});`);
886
+ emitter.line(`scr_caught_release(${stash});`);
887
+ emitter.emitUnwind();
836
888
  }
837
889
  if (retEntry.used) {
838
890
  // Pending-return path: a return in the try/catch body parked its
@@ -843,30 +895,30 @@ export function emitTryCatch(E, s) {
843
895
  // actual return. A THROW inside this copy replaces the pending
844
896
  // return (JS): the slot's owned value rides a synthetic scope
845
897
  // entry so the unwind releases it.
846
- E.line(`${retEntry.label}:; /* finally (pending-return path) */`);
847
- const retT = E.currentReturnType;
898
+ emitter.line(`${retEntry.label}:; /* finally (pending-return path) */`);
899
+ const retT = emitter.currentReturnType;
848
900
  const own = isRefCounted(retT);
849
901
  if (own)
850
- E.scopes.push([{ name: "sc_pret", type: retT }]);
851
- E.emitBlock(s.finallyBody);
902
+ emitter.scopes.push([{ name: "sc_pret", type: retT }]);
903
+ emitter.emitBlock(s.finallyBody);
852
904
  if (own)
853
- E.scopes.pop();
854
- const outer = E.finallyStack[E.finallyStack.length - 1];
905
+ emitter.scopes.pop();
906
+ const outer = emitter.finallyStack[emitter.finallyStack.length - 1];
855
907
  if (outer) {
856
908
  outer.used = true;
857
- E.releaseForJump(outer.frameDepth, outer.scopeDepth);
858
- E.line(`goto ${outer.label};`);
909
+ emitter.releaseForJump(outer.frameDepth, outer.scopeDepth);
910
+ emitter.line(`goto ${outer.label};`);
859
911
  }
860
912
  else {
861
- E.releaseForJump(0, 0);
862
- E.line(retT.kind === "void" ? `return;` : `return sc_pret;`);
913
+ emitter.releaseForJump(0, 0);
914
+ emitter.line(retT.kind === "void" ? `return;` : `return sc_pret;`);
863
915
  }
864
916
  }
865
917
  if (needEnd)
866
- E.line(`${endLabel}:;`);
918
+ emitter.line(`${endLabel}:;`);
867
919
  }
868
920
  else if (afterTryLabelUsed) {
869
- E.line(`${endLabel}:;`);
921
+ emitter.line(`${endLabel}:;`);
870
922
  }
871
923
  }
872
924
  /** JS-exact switch as a goto chain — C `switch` cannot express lazily
@@ -887,27 +939,27 @@ export function emitTryCatch(E, s) {
887
939
  * it still holds the pointer a previous iteration's scope exit already
888
940
  * released. The declarations are therefore NULL-reset up front; the
889
941
  * scope-exit releases rely on the runtime's NULL-tolerant release calls. */
890
- export function emitSwitch(E, s) {
942
+ export function emitSwitch(emitter, s) {
891
943
  if (s.disc.type.kind !== "f64" && s.disc.type.kind !== "string" && s.disc.type.kind !== "bool") {
892
- throw new Error(`emitter bug: switch on ${s.disc.type.kind}`);
944
+ throw new InternalCompilerError(`emitter bug: switch on ${s.disc.type.kind}`);
893
945
  }
894
- const id = E.labelCounter++;
946
+ const id = emitter.labelCounter++;
895
947
  const endLabel = `sc_swend_${id}`;
896
948
  const caseLabel = (i) => `sc_swcase_${id}_${i}`;
897
949
  // The disc temp lives in the whole statement's frame: for a string
898
950
  // discriminant it stays alive across every test and body, released when
899
951
  // the switch statement ends (break lands before that release; return
900
952
  // sweeps frames itself).
901
- const disc = E.emitExpr(s.disc);
953
+ const disc = emitter.emitExpr(s.disc);
902
954
  // NULL-reset refcounted/boxed locals declared at the top level of case
903
955
  // bodies (nested blocks manage their own scopes on normal control flow).
904
956
  for (const c of s.cases) {
905
957
  for (const stmt of c.body) {
906
958
  if (stmt.kind !== "varDecl")
907
959
  continue;
908
- const local = E.currentLocals.get(stmt.localId);
960
+ const local = emitter.currentLocals.get(stmt.localId);
909
961
  if (local.boxed || isRefCounted(local.type)) {
910
- E.line(`${mangleLocal(local.id)} = NULL; /* case-scoped ${local.name} */`);
962
+ emitter.line(`${mangleLocal(local.id)} = NULL; /* case-scoped ${local.name} */`);
911
963
  }
912
964
  }
913
965
  }
@@ -919,16 +971,16 @@ export function emitSwitch(E, s) {
919
971
  defaultIdx = i;
920
972
  return;
921
973
  }
922
- E.frames.push([]);
923
- const t = E.emitExpr(c.test);
974
+ emitter.frames.push([]);
975
+ const t = emitter.emitExpr(c.test);
924
976
  const cmp = c.test.type.kind === "string"
925
977
  ? `scr_str_eq(${disc.name}, ${t.name})`
926
978
  : `${disc.name} == ${t.name}`;
927
- const hit = E.newTemp(BOOL, cmp);
928
- E.releaseFrame(E.frames.pop());
929
- E.line(`if (${hit.name}) goto ${caseLabel(i)};`);
979
+ const hit = emitter.newTemp(BOOL, cmp);
980
+ emitter.releaseFrame(emitter.frames.pop());
981
+ emitter.line(`if (${hit.name}) goto ${caseLabel(i)};`);
930
982
  });
931
- E.line(`goto ${defaultIdx >= 0 ? caseLabel(defaultIdx) : endLabel};`);
983
+ emitter.line(`goto ${defaultIdx >= 0 ? caseLabel(defaultIdx) : endLabel};`);
932
984
  // Bodies in source order: entering one falls through the rest (JS-exact)
933
985
  // until a break jumps to the end label.
934
986
  const target = {
@@ -936,33 +988,33 @@ export function emitSwitch(E, s) {
936
988
  endLabel,
937
989
  usedEnd: defaultIdx < 0,
938
990
  ...(s.labels !== undefined && { labels: s.labels }),
939
- scopeDepth: E.scopes.length,
940
- frameDepth: E.frames.length,
991
+ scopeDepth: emitter.scopes.length,
992
+ frameDepth: emitter.frames.length,
941
993
  };
942
- E.jumpTargets.push(target);
943
- E.scopes.push([]);
994
+ emitter.jumpTargets.push(target);
995
+ emitter.scopes.push([]);
944
996
  s.cases.forEach((c, i) => {
945
- E.line(`${caseLabel(i)}:;`);
946
- E.indent++;
947
- E.emitStmts(c.body);
948
- E.indent--;
997
+ emitter.line(`${caseLabel(i)}:;`);
998
+ emitter.indent++;
999
+ emitter.emitStmts(c.body);
1000
+ emitter.indent--;
949
1001
  });
950
- E.jumpTargets.pop();
951
- const scope = E.scopes.pop();
1002
+ emitter.jumpTargets.pop();
1003
+ const scope = emitter.scopes.pop();
952
1004
  // Natural fall-off of the last body releases the shared scope here; a
953
1005
  // jump (break/return/continue/throw) already released it before jumping.
954
1006
  const lastBody = s.cases[s.cases.length - 1]?.body;
955
- if (!lastBody || !E.endsWithJump(lastBody))
956
- E.releaseFrame(scope);
1007
+ if (!lastBody || !endsWithJump(lastBody))
1008
+ emitter.releaseFrame(scope);
957
1009
  if (target.usedEnd)
958
- E.line(`${endLabel}:;`);
1010
+ emitter.line(`${endLabel}:;`);
959
1011
  }
960
1012
  /** Emits `if (cond) ` followed by a block on the same line for readability. */
961
- export function mergeBrace(E, emitBlockFn) {
962
- const head = E.lines.pop();
963
- const before = E.lines.length;
1013
+ export function mergeBrace(emitter, emitBlockFn) {
1014
+ const head = emitter.lines.pop();
1015
+ const before = emitter.lines.length;
964
1016
  emitBlockFn();
965
- E.lines[before] = head + E.lines[before].trimStart();
1017
+ emitter.lines[before] = head + emitter.lines[before].trimStart();
966
1018
  }
967
1019
  /** Evaluates `expr` in its own statement frame inside an already-open
968
1020
  * branch and moves the result into the C lvalue `target`: the chosen
@@ -970,20 +1022,20 @@ export function mergeBrace(E, emitBlockFn) {
970
1022
  * releases inside the branch. The shared core of the lazily-branched
971
1023
  * expressions (`logical`, `ternary`); the caller owns the surrounding
972
1024
  * braces/indentation and registers `target` in ITS frame. */
973
- export function emitBranchInto(E, target, expr) {
974
- E.frames.push([]);
975
- const v = E.emitExpr(expr);
976
- E.moveTemp(v);
977
- E.line(`${target} = ${v.name};`);
978
- E.releaseFrame(E.frames.pop());
1025
+ export function emitBranchInto(emitter, target, expr) {
1026
+ emitter.frames.push([]);
1027
+ const v = emitter.emitExpr(expr);
1028
+ emitter.moveTemp(v);
1029
+ emitter.line(`${target} = ${v.name};`);
1030
+ emitter.releaseFrame(emitter.frames.pop());
979
1031
  }
980
1032
  /** Evaluates a condition; its string temps are released before the branch,
981
1033
  * which is safe because the result is a scalar bool. */
982
- export function emitCondition(E, cond) {
983
- const t = E.emitExpr(cond);
984
- const frame = E.currentFrame();
985
- E.releaseFrame(frame);
1034
+ export function emitCondition(emitter, cond) {
1035
+ const t = emitter.emitExpr(cond);
1036
+ const frame = emitter.currentFrame();
1037
+ emitter.releaseFrame(frame);
986
1038
  frame.length = 0;
987
1039
  return t.name;
988
1040
  }
989
- //# sourceMappingURL=emit-stmts.js.map
1041
+ //# sourceMappingURL=stmts.js.map