@scriptc/compiler 0.0.35 → 0.0.36

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