xbintsc 0.5.6 → 0.5.20

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 (436) hide show
  1. package/AGENTS.md +16 -8
  2. package/README.md +8 -7
  3. package/README.zh-CN.md +6 -6
  4. package/dist/src/binder/declarations.js +14 -3
  5. package/dist/src/binder/declarations.js.map +1 -1
  6. package/dist/src/cli/hints.js +7 -1
  7. package/dist/src/cli/hints.js.map +1 -1
  8. package/dist/src/cli/main.js +115 -15
  9. package/dist/src/cli/main.js.map +1 -1
  10. package/dist/src/cli/watch.d.ts +25 -0
  11. package/dist/src/cli/watch.js +93 -0
  12. package/dist/src/cli/watch.js.map +1 -0
  13. package/dist/src/codegen/generator/calls/access.js +11 -2
  14. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  15. package/dist/src/codegen/generator/calls/closures.js +12 -4
  16. package/dist/src/codegen/generator/calls/closures.js.map +1 -1
  17. package/dist/src/codegen/generator/context.d.ts +8 -0
  18. package/dist/src/codegen/generator/context.js +22 -3
  19. package/dist/src/codegen/generator/context.js.map +1 -1
  20. package/dist/src/codegen/generator/expressions/operators.js +17 -15
  21. package/dist/src/codegen/generator/expressions/operators.js.map +1 -1
  22. package/dist/src/codegen/generator/expressions/primary.js +5 -0
  23. package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
  24. package/dist/src/codegen/generator/module.js +0 -7
  25. package/dist/src/codegen/generator/module.js.map +1 -1
  26. package/dist/src/codegen/generator/numeric.d.ts +6 -3
  27. package/dist/src/codegen/generator/numeric.js +54 -11
  28. package/dist/src/codegen/generator/numeric.js.map +1 -1
  29. package/dist/src/codegen/generator/state.js +23 -0
  30. package/dist/src/codegen/generator/state.js.map +1 -1
  31. package/dist/src/codegen/generator/statements/control-flow.js +1 -4
  32. package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
  33. package/dist/src/codegen/generator/statements/loops.js +48 -16
  34. package/dist/src/codegen/generator/statements/loops.js.map +1 -1
  35. package/dist/src/codegen/generator/tables.js +26 -1
  36. package/dist/src/codegen/generator/tables.js.map +1 -1
  37. package/dist/src/diagnostics/diagnostic.d.ts +3 -1
  38. package/dist/src/diagnostics/diagnostic.js +23 -3
  39. package/dist/src/diagnostics/diagnostic.js.map +1 -1
  40. package/dist/src/driver/app-artifacts.d.ts +42 -0
  41. package/dist/src/driver/app-artifacts.js +53 -0
  42. package/dist/src/driver/app-artifacts.js.map +1 -0
  43. package/dist/src/driver/build-key.d.ts +29 -0
  44. package/dist/src/driver/build-key.js +35 -0
  45. package/dist/src/driver/build-key.js.map +1 -0
  46. package/dist/src/driver/bundler/graph.js +61 -12
  47. package/dist/src/driver/bundler/graph.js.map +1 -1
  48. package/dist/src/driver/bundler/merge.js +7 -1
  49. package/dist/src/driver/bundler/merge.js.map +1 -1
  50. package/dist/src/driver/compiler.d.ts +10 -67
  51. package/dist/src/driver/compiler.js +94 -233
  52. package/dist/src/driver/compiler.js.map +1 -1
  53. package/dist/src/driver/config.d.ts +3 -0
  54. package/dist/src/driver/config.js +8 -0
  55. package/dist/src/driver/config.js.map +1 -1
  56. package/dist/src/driver/frontend.d.ts +37 -0
  57. package/dist/src/driver/frontend.js +92 -0
  58. package/dist/src/driver/frontend.js.map +1 -0
  59. package/dist/src/driver/index.d.ts +1 -1
  60. package/dist/src/driver/index.js.map +1 -1
  61. package/dist/src/driver/options.d.ts +64 -0
  62. package/dist/src/driver/options.js +9 -0
  63. package/dist/src/driver/options.js.map +1 -0
  64. package/dist/src/driver/runtime-objects.d.ts +38 -0
  65. package/dist/src/driver/runtime-objects.js +111 -0
  66. package/dist/src/driver/runtime-objects.js.map +1 -0
  67. package/dist/src/driver/toolchain-provider.d.ts +4 -0
  68. package/dist/src/driver/toolchain-provider.js +4 -0
  69. package/dist/src/driver/toolchain-provider.js.map +1 -1
  70. package/dist/src/driver/toolchain.d.ts +32 -1
  71. package/dist/src/driver/toolchain.js +115 -11
  72. package/dist/src/driver/toolchain.js.map +1 -1
  73. package/dist/src/driver/version.d.ts +12 -0
  74. package/dist/src/driver/version.js +13 -0
  75. package/dist/src/driver/version.js.map +1 -0
  76. package/dist/src/driver/win-icon.d.ts +7 -9
  77. package/dist/src/driver/win-icon.js +37 -35
  78. package/dist/src/driver/win-icon.js.map +1 -1
  79. package/dist/src/parser/declarations/classes.js +5 -0
  80. package/dist/src/parser/declarations/classes.js.map +1 -1
  81. package/dist/src/parser/declarations/functions.js +13 -1
  82. package/dist/src/parser/declarations/functions.js.map +1 -1
  83. package/dist/src/parser/modules.js +8 -3
  84. package/dist/src/parser/modules.js.map +1 -1
  85. package/dist/src/parser/parser.d.ts +1 -0
  86. package/dist/src/parser/parser.js +23 -0
  87. package/dist/src/parser/parser.js.map +1 -1
  88. package/dist/tests/cli/check.test.d.ts +6 -0
  89. package/dist/tests/cli/check.test.js +68 -0
  90. package/dist/tests/cli/check.test.js.map +1 -0
  91. package/dist/tests/cli/main.test.js +19 -0
  92. package/dist/tests/cli/main.test.js.map +1 -1
  93. package/dist/tests/cli/watch.test.d.ts +6 -0
  94. package/dist/tests/cli/watch.test.js +72 -0
  95. package/dist/tests/cli/watch.test.js.map +1 -0
  96. package/dist/tests/codegen/expressions.test.js +15 -3
  97. package/dist/tests/codegen/expressions.test.js.map +1 -1
  98. package/dist/tests/codegen/llvm.test.js +16 -0
  99. package/dist/tests/codegen/llvm.test.js.map +1 -1
  100. package/dist/tests/diagnostics/diagnostic.test.js +8 -0
  101. package/dist/tests/diagnostics/diagnostic.test.js.map +1 -1
  102. package/dist/tests/docs/structure.test.d.ts +1 -0
  103. package/dist/tests/docs/structure.test.js +92 -0
  104. package/dist/tests/docs/structure.test.js.map +1 -0
  105. package/dist/tests/driver/compiler.test.js +6 -0
  106. package/dist/tests/driver/compiler.test.js.map +1 -1
  107. package/dist/tests/driver/config.test.js +9 -0
  108. package/dist/tests/driver/config.test.js.map +1 -1
  109. package/dist/tests/driver/icon.test.js +19 -32
  110. package/dist/tests/driver/icon.test.js.map +1 -1
  111. package/dist/tests/driver/invalid-input.test.d.ts +10 -0
  112. package/dist/tests/driver/invalid-input.test.js +29 -0
  113. package/dist/tests/driver/invalid-input.test.js.map +1 -0
  114. package/dist/tests/driver/modules.test.js +42 -3
  115. package/dist/tests/driver/modules.test.js.map +1 -1
  116. package/dist/tests/driver/toolchain-provider.test.js +27 -1
  117. package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
  118. package/dist/tests/driver/toolchain.test.js +60 -2
  119. package/dist/tests/driver/toolchain.test.js.map +1 -1
  120. package/dist/tests/e2e/array-buffer.test.d.ts +5 -0
  121. package/dist/tests/e2e/array-buffer.test.js +38 -0
  122. package/dist/tests/e2e/array-buffer.test.js.map +1 -0
  123. package/dist/tests/e2e/array-from-iterables.test.d.ts +7 -0
  124. package/dist/tests/e2e/array-from-iterables.test.js +34 -0
  125. package/dist/tests/e2e/array-from-iterables.test.js.map +1 -0
  126. package/dist/tests/e2e/array-symbol-iterator.test.d.ts +8 -0
  127. package/dist/tests/e2e/array-symbol-iterator.test.js +42 -0
  128. package/dist/tests/e2e/array-symbol-iterator.test.js.map +1 -0
  129. package/dist/tests/e2e/async-generators.test.d.ts +1 -0
  130. package/dist/tests/e2e/async-generators.test.js +154 -0
  131. package/dist/tests/e2e/async-generators.test.js.map +1 -0
  132. package/dist/tests/e2e/await-ordering.test.d.ts +5 -0
  133. package/dist/tests/e2e/await-ordering.test.js +37 -0
  134. package/dist/tests/e2e/await-ordering.test.js.map +1 -0
  135. package/dist/tests/e2e/compile-builtins.test.js +1 -1
  136. package/dist/tests/e2e/compile-modules.test.js +7 -0
  137. package/dist/tests/e2e/compile-modules.test.js.map +1 -1
  138. package/dist/tests/e2e/date-parse.test.d.ts +8 -0
  139. package/dist/tests/e2e/date-parse.test.js +38 -0
  140. package/dist/tests/e2e/date-parse.test.js.map +1 -0
  141. package/dist/tests/e2e/default-anonymous-exports.test.d.ts +7 -0
  142. package/dist/tests/e2e/default-anonymous-exports.test.js +23 -0
  143. package/dist/tests/e2e/default-anonymous-exports.test.js.map +1 -0
  144. package/dist/tests/e2e/globals-microtask.test.d.ts +9 -0
  145. package/dist/tests/e2e/globals-microtask.test.js +37 -0
  146. package/dist/tests/e2e/globals-microtask.test.js.map +1 -0
  147. package/dist/tests/e2e/gui-media.test.js +8 -1
  148. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  149. package/dist/tests/e2e/inspect-builtins.test.d.ts +10 -0
  150. package/dist/tests/e2e/inspect-builtins.test.js +43 -0
  151. package/dist/tests/e2e/inspect-builtins.test.js.map +1 -0
  152. package/dist/tests/e2e/json-builtin-objects.test.d.ts +9 -0
  153. package/dist/tests/e2e/json-builtin-objects.test.js +23 -0
  154. package/dist/tests/e2e/json-builtin-objects.test.js.map +1 -0
  155. package/dist/tests/e2e/json-circular.test.d.ts +6 -0
  156. package/dist/tests/e2e/json-circular.test.js +43 -0
  157. package/dist/tests/e2e/json-circular.test.js.map +1 -0
  158. package/dist/tests/e2e/json-parse-reviver.test.d.ts +6 -0
  159. package/dist/tests/e2e/json-parse-reviver.test.js +29 -0
  160. package/dist/tests/e2e/json-parse-reviver.test.js.map +1 -0
  161. package/dist/tests/e2e/json-stringify-replacer.test.d.ts +6 -0
  162. package/dist/tests/e2e/json-stringify-replacer.test.js +27 -0
  163. package/dist/tests/e2e/json-stringify-replacer.test.js.map +1 -0
  164. package/dist/tests/e2e/json-stringify-space.test.d.ts +6 -0
  165. package/dist/tests/e2e/json-stringify-space.test.js +23 -0
  166. package/dist/tests/e2e/json-stringify-space.test.js.map +1 -0
  167. package/dist/tests/e2e/method-dispatch-errors.test.d.ts +9 -0
  168. package/dist/tests/e2e/method-dispatch-errors.test.js +38 -0
  169. package/dist/tests/e2e/method-dispatch-errors.test.js.map +1 -0
  170. package/dist/tests/e2e/native-extensions.test.js +1 -1
  171. package/dist/tests/e2e/native-extensions.test.js.map +1 -1
  172. package/dist/tests/e2e/promise-with-resolvers.test.d.ts +5 -0
  173. package/dist/tests/e2e/promise-with-resolvers.test.js +20 -0
  174. package/dist/tests/e2e/promise-with-resolvers.test.js.map +1 -0
  175. package/dist/tests/e2e/property-descriptors.test.d.ts +5 -0
  176. package/dist/tests/e2e/property-descriptors.test.js +25 -0
  177. package/dist/tests/e2e/property-descriptors.test.js.map +1 -0
  178. package/dist/tests/e2e/property-ic.test.d.ts +1 -0
  179. package/dist/tests/e2e/property-ic.test.js +55 -0
  180. package/dist/tests/e2e/property-ic.test.js.map +1 -0
  181. package/dist/tests/e2e/runtime-errors.test.d.ts +10 -0
  182. package/dist/tests/e2e/runtime-errors.test.js +52 -0
  183. package/dist/tests/e2e/runtime-errors.test.js.map +1 -0
  184. package/dist/tests/e2e/structured-clone.test.d.ts +6 -0
  185. package/dist/tests/e2e/structured-clone.test.js +49 -0
  186. package/dist/tests/e2e/structured-clone.test.js.map +1 -0
  187. package/dist/tests/e2e/text-codec.test.d.ts +6 -0
  188. package/dist/tests/e2e/text-codec.test.js +24 -0
  189. package/dist/tests/e2e/text-codec.test.js.map +1 -0
  190. package/dist/tests/e2e/typed-array-views.test.d.ts +6 -0
  191. package/dist/tests/e2e/typed-array-views.test.js +39 -0
  192. package/dist/tests/e2e/typed-array-views.test.js.map +1 -0
  193. package/dist/tests/e2e/url-search-params.test.d.ts +5 -0
  194. package/dist/tests/e2e/url-search-params.test.js +30 -0
  195. package/dist/tests/e2e/url-search-params.test.js.map +1 -0
  196. package/dist/tests/e2e/weak-collections.test.d.ts +1 -0
  197. package/dist/tests/e2e/weak-collections.test.js +88 -0
  198. package/dist/tests/e2e/weak-collections.test.js.map +1 -0
  199. package/dist/tests/parser/declarations.test.js +12 -0
  200. package/dist/tests/parser/declarations.test.js.map +1 -1
  201. package/dist/tests/parser/module-syntax.test.js +9 -0
  202. package/dist/tests/parser/module-syntax.test.js.map +1 -1
  203. package/dist/tests/parser/parser.test.js +7 -0
  204. package/dist/tests/parser/parser.test.js.map +1 -1
  205. package/dist/tests/version.test.js +5 -1
  206. package/dist/tests/version.test.js.map +1 -1
  207. package/doc/ai/README.md +4 -3
  208. package/doc/ai/cli.md +41 -0
  209. package/doc/ai/contributing.md +18 -15
  210. package/doc/ai/extensions.md +9 -7
  211. package/doc/ai/language-support.md +17 -13
  212. package/doc/ai/troubleshooting.md +11 -9
  213. package/doc/ai/zh-CN/README.md +3 -2
  214. package/doc/ai/zh-CN/cli.md +35 -0
  215. package/doc/ai/zh-CN/contributing.md +15 -14
  216. package/doc/ai/zh-CN/extensions.md +8 -6
  217. package/doc/ai/zh-CN/language-support.md +17 -14
  218. package/doc/ai/zh-CN/troubleshooting.md +9 -8
  219. package/doc/gui/build.md +13 -4
  220. package/doc/gui/known-issues.md +9 -5
  221. package/doc/gui/rendering.md +3 -1
  222. package/doc/gui.md +4 -3
  223. package/doc/icon.md +5 -4
  224. package/doc/implemented/async.md +38 -0
  225. package/doc/implemented/binder.md +13 -0
  226. package/doc/implemented/cli.md +47 -0
  227. package/doc/implemented/codegen.md +33 -0
  228. package/doc/implemented/collections.md +26 -0
  229. package/doc/implemented/driver.md +19 -0
  230. package/doc/implemented/extensions.md +19 -0
  231. package/doc/implemented/fetch.md +12 -0
  232. package/doc/implemented/lexer.md +23 -0
  233. package/doc/implemented/modules.md +28 -0
  234. package/doc/implemented/node/assert.md +17 -0
  235. package/doc/implemented/node/buffer.md +29 -0
  236. package/doc/implemented/node/child-process.md +29 -0
  237. package/doc/implemented/node/crypto.md +9 -0
  238. package/doc/implemented/node/dgram.md +15 -0
  239. package/doc/implemented/node/events.md +37 -0
  240. package/doc/implemented/node/fs-promises.md +38 -0
  241. package/doc/implemented/node/fs.md +112 -0
  242. package/doc/implemented/node/http.md +21 -0
  243. package/doc/implemented/node/net.md +17 -0
  244. package/doc/implemented/node/os.md +22 -0
  245. package/doc/implemented/node/path.md +33 -0
  246. package/doc/implemented/node/process.md +23 -0
  247. package/doc/implemented/node/querystring.md +20 -0
  248. package/doc/implemented/node/stream-promises.md +8 -0
  249. package/doc/implemented/node/stream.md +19 -0
  250. package/doc/implemented/node/test.md +10 -0
  251. package/doc/implemented/node/url.md +8 -0
  252. package/doc/implemented/node/util.md +25 -0
  253. package/doc/implemented/node/worker-threads.md +10 -0
  254. package/doc/implemented/node/zlib.md +8 -0
  255. package/doc/implemented/node.md +48 -0
  256. package/doc/implemented/operators.md +38 -0
  257. package/doc/implemented/parser.md +58 -0
  258. package/doc/implemented/pipeline.md +28 -0
  259. package/doc/implemented/runtime-core.md +32 -0
  260. package/doc/implemented/stdlib.md +78 -0
  261. package/doc/implemented/strings.md +27 -0
  262. package/doc/implemented/tests.md +10 -0
  263. package/doc/implemented/typed-arrays.md +26 -0
  264. package/doc/implemented/value-model.md +18 -0
  265. package/doc/implemented.md +54 -355
  266. package/doc/node-implemented.md +3 -585
  267. package/doc/node-unimplemented.md +3 -164
  268. package/doc/requirements.md +23 -8
  269. package/doc/unimplemented/classes.md +22 -0
  270. package/doc/unimplemented/deviations.md +27 -0
  271. package/doc/unimplemented/expressions.md +26 -0
  272. package/doc/unimplemented/functions.md +21 -0
  273. package/doc/unimplemented/modules.md +22 -0
  274. package/doc/unimplemented/node/async.md +17 -0
  275. package/doc/unimplemented/node/bun.md +9 -0
  276. package/doc/unimplemented/node/fs-promises.md +16 -0
  277. package/doc/unimplemented/node/fs.md +31 -0
  278. package/doc/unimplemented/node/globals.md +23 -0
  279. package/doc/unimplemented/node/modules.md +21 -0
  280. package/doc/unimplemented/node.md +21 -0
  281. package/doc/unimplemented/statements.md +18 -0
  282. package/doc/unimplemented/stdlib.md +54 -0
  283. package/doc/unimplemented/toolchain.md +14 -0
  284. package/doc/unimplemented/types.md +12 -0
  285. package/doc/unimplemented.md +18 -275
  286. package/doc/xbintsc.config.schema.json +12 -0
  287. package/doc/zh-CN/gui/build.md +11 -3
  288. package/doc/zh-CN/gui/known-issues.md +9 -4
  289. package/doc/zh-CN/gui/rendering.md +2 -1
  290. package/doc/zh-CN/gui.md +3 -2
  291. package/doc/zh-CN/icon.md +5 -4
  292. package/doc/zh-CN/implemented/async.md +38 -0
  293. package/doc/zh-CN/implemented/binder.md +13 -0
  294. package/doc/zh-CN/implemented/cli.md +46 -0
  295. package/doc/zh-CN/implemented/codegen.md +33 -0
  296. package/doc/zh-CN/implemented/collections.md +26 -0
  297. package/doc/zh-CN/implemented/driver.md +19 -0
  298. package/doc/zh-CN/implemented/extensions.md +19 -0
  299. package/doc/zh-CN/implemented/fetch.md +12 -0
  300. package/doc/zh-CN/implemented/lexer.md +23 -0
  301. package/doc/zh-CN/implemented/modules.md +28 -0
  302. package/doc/zh-CN/implemented/node/assert.md +17 -0
  303. package/doc/zh-CN/implemented/node/buffer.md +25 -0
  304. package/doc/zh-CN/implemented/node/child-process.md +27 -0
  305. package/doc/zh-CN/implemented/node/crypto.md +9 -0
  306. package/doc/zh-CN/implemented/node/dgram.md +15 -0
  307. package/doc/zh-CN/implemented/node/events.md +36 -0
  308. package/doc/zh-CN/implemented/node/fs-promises.md +27 -0
  309. package/doc/zh-CN/implemented/node/fs.md +105 -0
  310. package/doc/zh-CN/implemented/node/http.md +17 -0
  311. package/doc/zh-CN/implemented/node/net.md +17 -0
  312. package/doc/zh-CN/implemented/node/os.md +21 -0
  313. package/doc/zh-CN/implemented/node/path.md +26 -0
  314. package/doc/zh-CN/implemented/node/process.md +23 -0
  315. package/doc/zh-CN/implemented/node/querystring.md +20 -0
  316. package/doc/zh-CN/implemented/node/stream-promises.md +8 -0
  317. package/doc/zh-CN/implemented/node/stream.md +15 -0
  318. package/doc/zh-CN/implemented/node/test.md +10 -0
  319. package/doc/zh-CN/implemented/node/url.md +8 -0
  320. package/doc/zh-CN/implemented/node/util.md +25 -0
  321. package/doc/zh-CN/implemented/node/worker-threads.md +9 -0
  322. package/doc/zh-CN/implemented/node/zlib.md +8 -0
  323. package/doc/zh-CN/implemented/node.md +45 -0
  324. package/doc/zh-CN/implemented/operators.md +38 -0
  325. package/doc/zh-CN/implemented/parser.md +58 -0
  326. package/doc/zh-CN/implemented/pipeline.md +25 -0
  327. package/doc/zh-CN/implemented/runtime-core.md +31 -0
  328. package/doc/zh-CN/implemented/stdlib.md +76 -0
  329. package/doc/zh-CN/implemented/strings.md +27 -0
  330. package/doc/zh-CN/implemented/tests.md +10 -0
  331. package/doc/zh-CN/implemented/typed-arrays.md +26 -0
  332. package/doc/zh-CN/implemented/value-model.md +18 -0
  333. package/doc/zh-CN/implemented.md +50 -350
  334. package/doc/zh-CN/node-implemented.md +4 -531
  335. package/doc/zh-CN/node-unimplemented.md +4 -139
  336. package/doc/zh-CN/plan-require-node-modules.md +4 -4
  337. package/doc/zh-CN/requirements.md +20 -6
  338. package/doc/zh-CN/unimplemented/classes.md +22 -0
  339. package/doc/zh-CN/unimplemented/deviations.md +24 -0
  340. package/doc/zh-CN/unimplemented/expressions.md +24 -0
  341. package/doc/zh-CN/unimplemented/functions.md +21 -0
  342. package/doc/zh-CN/unimplemented/modules.md +19 -0
  343. package/doc/zh-CN/unimplemented/node/async.md +17 -0
  344. package/doc/zh-CN/unimplemented/node/bun.md +8 -0
  345. package/doc/zh-CN/unimplemented/node/fs-promises.md +12 -0
  346. package/doc/zh-CN/unimplemented/node/fs.md +24 -0
  347. package/doc/zh-CN/unimplemented/node/globals.md +14 -0
  348. package/doc/zh-CN/unimplemented/node/modules.md +15 -0
  349. package/doc/zh-CN/unimplemented/node.md +18 -0
  350. package/doc/zh-CN/unimplemented/statements.md +15 -0
  351. package/doc/zh-CN/unimplemented/stdlib.md +54 -0
  352. package/doc/zh-CN/unimplemented/toolchain.md +14 -0
  353. package/doc/zh-CN/unimplemented/types.md +11 -0
  354. package/doc/zh-CN/unimplemented.md +14 -237
  355. package/llms.txt +32 -4
  356. package/package.json +1 -1
  357. package/runtime/ext_gui/renderer_shaders.h +2 -2
  358. package/runtime/ext_gui/stb_image.h +1 -17
  359. package/runtime/ext_node/child_process/child_process.c +173 -73
  360. package/runtime/rt.h +15 -0
  361. package/runtime/rt_internal.h +106 -0
  362. package/runtime/xt_alloc.c +43 -7
  363. package/runtime/xt_array_buffer.c +284 -0
  364. package/runtime/xt_async.c +46 -21
  365. package/runtime/xt_bigint/helpers.inc +3 -3
  366. package/runtime/xt_builtins.c +21 -17
  367. package/runtime/xt_constructors.c +12 -2
  368. package/runtime/xt_containers/access.inc +148 -3
  369. package/runtime/xt_containers/objects.inc +26 -2
  370. package/runtime/xt_containers/shapes.inc +71 -0
  371. package/runtime/xt_containers.c +1 -0
  372. package/runtime/xt_coroutine.c +17 -0
  373. package/runtime/xt_generator.c +299 -10
  374. package/runtime/xt_io/inspect.inc +112 -0
  375. package/runtime/xt_loop.c +35 -4
  376. package/runtime/xt_performance.c +37 -0
  377. package/runtime/xt_promise.c +63 -1
  378. package/runtime/xt_stdlib/arrays.inc +1 -1
  379. package/runtime/xt_stdlib/dispatch.inc +46 -11
  380. package/runtime/xt_stdlib/strings.inc +1 -1
  381. package/runtime/xt_stdlib2/array-statics.inc +25 -0
  382. package/runtime/xt_stdlib2/arrays.inc +5 -3
  383. package/runtime/xt_stdlib2/container.inc +5 -0
  384. package/runtime/xt_stdlib2/date.inc +111 -3
  385. package/runtime/xt_stdlib2/error.inc +24 -0
  386. package/runtime/xt_stdlib2/json.inc +310 -19
  387. package/runtime/xt_stdlib2/number-string-statics.inc +1 -1
  388. package/runtime/xt_stdlib2/objects.inc +122 -0
  389. package/runtime/xt_stdlib2/set.inc +1 -1
  390. package/runtime/xt_structured_clone.c +159 -0
  391. package/runtime/xt_symbol.c +2 -2
  392. package/runtime/xt_text_codec.c +69 -0
  393. package/runtime/xt_typed_array/construction.inc +35 -5
  394. package/runtime/xt_typed_array/elements.inc +159 -0
  395. package/runtime/xt_typed_array/methods.inc +21 -5
  396. package/runtime/xt_typed_array.c +7 -10
  397. package/runtime/xt_url.c +375 -0
  398. package/runtime/xt_values/arithmetic.inc +2 -2
  399. package/runtime/xt_values/conversions.inc +1 -1
  400. package/runtime/xt_weak.c +281 -0
  401. package/scripts/build-gui.ts +133 -60
  402. package/scripts/check-version.ts +3 -3
  403. package/src/binder/declarations.ts +14 -3
  404. package/src/cli/hints.ts +8 -1
  405. package/src/cli/main.ts +119 -18
  406. package/src/cli/watch.ts +101 -0
  407. package/src/codegen/generator/calls/access.ts +10 -2
  408. package/src/codegen/generator/calls/closures.ts +12 -4
  409. package/src/codegen/generator/context.ts +23 -3
  410. package/src/codegen/generator/expressions/operators.ts +27 -13
  411. package/src/codegen/generator/expressions/primary.ts +4 -0
  412. package/src/codegen/generator/module.ts +0 -7
  413. package/src/codegen/generator/numeric.ts +85 -11
  414. package/src/codegen/generator/state.ts +23 -0
  415. package/src/codegen/generator/statements/control-flow.ts +1 -4
  416. package/src/codegen/generator/statements/loops.ts +50 -16
  417. package/src/codegen/generator/tables.ts +26 -1
  418. package/src/diagnostics/diagnostic.ts +23 -3
  419. package/src/driver/app-artifacts.ts +77 -0
  420. package/src/driver/build-key.ts +55 -0
  421. package/src/driver/bundler/graph.ts +63 -13
  422. package/src/driver/bundler/merge.ts +4 -1
  423. package/src/driver/compiler.ts +93 -327
  424. package/src/driver/config.ts +11 -0
  425. package/src/driver/frontend.ts +120 -0
  426. package/src/driver/index.ts +0 -1
  427. package/src/driver/options.ts +70 -0
  428. package/src/driver/runtime-objects.ts +133 -0
  429. package/src/driver/toolchain-provider.ts +4 -0
  430. package/src/driver/toolchain.ts +154 -10
  431. package/src/driver/version.ts +12 -0
  432. package/src/driver/win-icon.ts +36 -36
  433. package/src/parser/declarations/classes.ts +4 -0
  434. package/src/parser/declarations/functions.ts +12 -1
  435. package/src/parser/modules.ts +8 -4
  436. package/src/parser/parser.ts +28 -0
@@ -0,0 +1,101 @@
1
+ /**
2
+ * `xbintsc watch` support: fingerprint a source tree and rebuild when it
3
+ * changes.
4
+ *
5
+ * The scan is deliberately polling-based. A self-hosted xbintsc binary has no
6
+ * `fs.watch` backend in the Node extension, and polling works identically on
7
+ * every platform. The tree is the entry file's directory, with build outputs
8
+ * and dependency directories excluded; package sources inside `node_modules`
9
+ * are not watched (run the build once after installing a dependency).
10
+ */
11
+
12
+ import { readFileSync, readdirSync, statSync, type Dirent } from "node:fs";
13
+ import { extname, join, resolve } from "node:path";
14
+
15
+ const WATCHED_EXTENSIONS = new Set([
16
+ ".ts",
17
+ ".tsx",
18
+ ".js",
19
+ ".mjs",
20
+ ".cjs",
21
+ ".json",
22
+ ".html",
23
+ ".css",
24
+ ]);
25
+
26
+ const IGNORED_DIRECTORIES = new Set([
27
+ "node_modules",
28
+ ".git",
29
+ ".github",
30
+ ".xbintsc",
31
+ ".xbintsc-cache",
32
+ "build",
33
+ "dist",
34
+ "coverage",
35
+ "scratch",
36
+ "target",
37
+ "vendor",
38
+ ]);
39
+
40
+ /** One string that changes whenever a watched file changes. */
41
+ export function fingerprintTree(root: string): string {
42
+ const entries: string[] = [];
43
+ collect(resolve(root), entries);
44
+ entries.sort();
45
+ return entries.join("|");
46
+ }
47
+
48
+ function collect(directory: string, out: string[]): void {
49
+ let entries: Dirent[];
50
+ try {
51
+ entries = readdirSync(directory, { withFileTypes: true });
52
+ } catch {
53
+ return; // the directory disappeared between scans
54
+ }
55
+ for (const entry of entries) {
56
+ const path = join(directory, entry.name);
57
+ if (entry.isDirectory()) {
58
+ if (!IGNORED_DIRECTORIES.has(entry.name)) collect(path, out);
59
+ continue;
60
+ }
61
+ if (!entry.isFile()) continue;
62
+ if (!WATCHED_EXTENSIONS.has(extname(entry.name).toLowerCase())) continue;
63
+ try {
64
+ const stat = statSync(path);
65
+ /* mtime resolution is coarse on some filesystems (and on Windows two
66
+ * same-size writes can share a timestamp), so hash the bytes as well. */
67
+ let hash = 2166136261;
68
+ const contents = readFileSync(path);
69
+ for (let i = 0; i < contents.length; i++) {
70
+ hash = Math.imul(hash ^ (contents[i] ?? 0), 16777619);
71
+ }
72
+ out.push(`${path}:${stat.mtimeMs}:${stat.size}:${hash >>> 0}`);
73
+ } catch {
74
+ // A file removed during the scan is picked up by the next iteration.
75
+ }
76
+ }
77
+ }
78
+
79
+ export interface WatchOptions {
80
+ /** Current fingerprint of everything that should trigger a rebuild. */
81
+ readonly scan: () => string;
82
+ /** Called after the fingerprint changes. Must be synchronous. */
83
+ readonly onRebuild: () => void;
84
+ /** Poll interval; defaults to 300 ms. */
85
+ readonly intervalMs?: number;
86
+ }
87
+
88
+ /**
89
+ * Start polling. Returns a stop function. The caller performs the initial
90
+ * build, so this never fires `onRebuild` for the state it starts in.
91
+ */
92
+ export function startWatching(options: WatchOptions): () => void {
93
+ let previous = options.scan();
94
+ const timer = setInterval(() => {
95
+ const next = options.scan();
96
+ if (next === previous) return;
97
+ previous = next;
98
+ options.onRebuild();
99
+ }, options.intervalMs ?? 300);
100
+ return () => clearInterval(timer);
101
+ }
@@ -143,7 +143,14 @@ export const accessCallMethods: AccessCallMethods = {
143
143
  const access = (): string => {
144
144
  const key = this.emitExpression(node.argumentExpression);
145
145
  const result = this.reg();
146
- this.emit(` ${result} = call i64 @xt_get(i64 ${object}, i64 ${key})`);
146
+ /* Array-index reads are not object property layouts, so skip the IC for
147
+ * a numeric literal; every other key may benefit from it. */
148
+ if (node.argumentExpression.kind === SyntaxKind.NumericLiteral) {
149
+ this.emit(` ${result} = call i64 @xt_get(i64 ${object}, i64 ${key})`);
150
+ } else {
151
+ const cache = this.icCachePointer();
152
+ this.emit(` ${result} = call i64 @xt_get_ic(i64 ${object}, i64 ${key}, i64* ${cache})`);
153
+ }
147
154
  return result;
148
155
  };
149
156
  return node.optional ? this.emitOptional(object, access) : access();
@@ -158,8 +165,9 @@ export const accessCallMethods: AccessCallMethods = {
158
165
  return result;
159
166
  }
160
167
  const key = this.stringValue(name);
168
+ const cache = this.icCachePointer();
161
169
  const result = this.reg();
162
- this.emit(` ${result} = call i64 @xt_get(i64 ${object}, i64 ${key})`);
170
+ this.emit(` ${result} = call i64 @xt_get_ic(i64 ${object}, i64 ${key}, i64* ${cache})`);
163
171
  return result;
164
172
  },
165
173
 
@@ -79,9 +79,17 @@ export const closureCallMethods: ClosureCallMethods = {
79
79
  if (fn.isConstructor && fn.classInfo) name = fn.classInfo.name;
80
80
  const nameValue = this.stringValue(name);
81
81
  this.emit(` call i64 @xt_function_set_metadata(i64 ${closure}, i64 ${nameValue}, i32 ${arity})`);
82
- if (fn.isGenerator) this.emit(` call i64 @xt_function_set_generator(i64 ${closure})`);
83
- /* `async` functions run on a coroutine: the runtime must know at call time
84
- * so it can return a promise and suspend at `await`. */
85
- if (fn.isAsync) this.emit(` call i64 @xt_function_set_async(i64 ${closure})`);
82
+ if (fn.isAsync && fn.isGenerator) {
83
+ /* `async function*`: a generator whose `.next()` returns promises. The
84
+ * runtime needs both flags, so use the combined marker instead of the
85
+ * two separate setters. */
86
+ this.emit(` call i64 @xt_function_set_async_generator(i64 ${closure})`);
87
+ } else if (fn.isGenerator) {
88
+ this.emit(` call i64 @xt_function_set_generator(i64 ${closure})`);
89
+ } else if (fn.isAsync) {
90
+ /* `async` functions run on a coroutine: the runtime must know at call
91
+ * time so it can return a promise and suspend at `await`. */
92
+ this.emit(` call i64 @xt_function_set_async(i64 ${closure})`);
93
+ }
86
94
  },
87
95
  };
@@ -64,6 +64,8 @@ export class GeneratorContext {
64
64
  readonly lineStartsByFile = new Map<string, number[]>();
65
65
  stringCounter = 0;
66
66
  staticCounter = 0;
67
+ /** Monotonic id for per-property-access inline-cache globals. */
68
+ icCounter = 0;
67
69
  /**
68
70
  * How many `UnsupportedFeature` diagnostics the function currently being
69
71
  * emitted produced. Unsupported constructs can leave the generator with a
@@ -187,8 +189,8 @@ export class GeneratorContext {
187
189
  if (!symbols.some((symbol) => this.usedAsValue(symbol))) return;
188
190
  this.diagnostics.error(
189
191
  DiagnosticCode.ModuleNotFound,
190
- `module '${specifier}' is not supported: xbintsc can import built-in platform modules, ` +
191
- "relative '.ts' files and ESM packages under node_modules; CommonJS packages are not supported",
192
+ `module '${specifier}' is not supported: expected a Node built-in ` +
193
+ "(with --ext node), a relative .ts/.js file, or a package in node_modules",
192
194
  declaration.moduleSpecifier,
193
195
  this.fileNameOf(declaration.moduleSpecifier),
194
196
  );
@@ -309,6 +311,19 @@ export class GeneratorContext {
309
311
  return ptr;
310
312
  }
311
313
 
314
+ /**
315
+ * Allocate a two-word inline cache for one property-access site and return
316
+ * the `i64*` the runtime fills with (shape, property index). The global is
317
+ * zero-initialised, which the runtime treats as an empty cache.
318
+ */
319
+ icCachePointer(): string {
320
+ const name = `@ic.${this.icCounter++}`;
321
+ this.globals.push(`${name} = internal global [2 x i64] zeroinitializer`);
322
+ const ptr = this.reg();
323
+ this.emit(` ${ptr} = getelementptr [2 x i64], [2 x i64]* ${name}, i64 0, i64 0`);
324
+ return ptr;
325
+ }
326
+
312
327
  /** Lay already-computed values out as a contiguous `i64*` argument buffer. */
313
328
  emitValueArguments(values: readonly string[]): { argc: string; ptr: string } {
314
329
  if (values.length === 0) return { argc: "0", ptr: "null" };
@@ -517,10 +532,15 @@ export class GeneratorContext {
517
532
 
518
533
  unsupported(node: Node, what: string): void {
519
534
  const label = kindName(node.kind);
535
+ const hasName = label !== String(node.kind);
536
+ /* `unsupported(statement, "statement")` is the generic fallback; when the
537
+ * syntax kind has a human name, use it directly instead of appending a
538
+ * redundant "(statement)". */
539
+ const subject = what === "statement" && hasName ? `this ${label}` : `this ${what} (${label})`;
520
540
  this.unsupportedCount++;
521
541
  this.diagnostics.error(
522
542
  DiagnosticCode.UnsupportedFeature,
523
- `xbintsc does not yet support this ${what} (${label})`,
543
+ `xbintsc does not yet support ${subject}`,
524
544
  node,
525
545
  this.fileNameOf(node),
526
546
  );
@@ -24,6 +24,15 @@ function isStringLike(node: Expression): boolean {
24
24
  return node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
25
25
  }
26
26
 
27
+ /** True for a numeric literal (optionally signed), whose tag check can be skipped. */
28
+ function isNumericLiteral(node: Expression): boolean {
29
+ if (node.kind === SyntaxKind.NumericLiteral) return true;
30
+ if (node.kind !== SyntaxKind.PrefixUnaryExpression) return false;
31
+ const prefix = node as PrefixUnaryExpression;
32
+ if (prefix.operator !== PrefixUnaryOperator.Minus && prefix.operator !== PrefixUnaryOperator.Plus) return false;
33
+ return prefix.operand.kind === SyntaxKind.NumericLiteral;
34
+ }
35
+
27
36
  /**
28
37
  * The built-in constructor a right-hand `instanceof` operand names, if any.
29
38
  * A user binding with the same name shadows it.
@@ -84,7 +93,15 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
84
93
  // `+` concatenates when either side is known to be a string; skip the
85
94
  // numeric tag checks for that shape and call the runtime directly.
86
95
  const knownStringConcat = operator === "+" && (isStringLike(node.left) || isStringLike(node.right));
87
- return this.emitBinaryOperation(left, right, operator, runtime, !knownStringConcat);
96
+ return this.emitBinaryOperation(
97
+ left,
98
+ right,
99
+ operator,
100
+ runtime,
101
+ !knownStringConcat,
102
+ isNumericLiteral(node.left),
103
+ isNumericLiteral(node.right),
104
+ );
88
105
  },
89
106
 
90
107
  emitShortCircuit(node: BinaryExpression, kind: "and" | "or" | "nullish"): string {
@@ -95,15 +112,9 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
95
112
  const endLabel = this.label("sc.end");
96
113
  let condition: string;
97
114
  if (kind === "and") {
98
- const truthy = this.reg();
99
- this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${left})`);
100
- condition = this.reg();
101
- this.emit(` ${condition} = icmp ne i32 ${truthy}, 0`);
115
+ condition = this.emitTruthiness(left, node.left);
102
116
  } else if (kind === "or") {
103
- const truthy = this.reg();
104
- this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${left})`);
105
- const isTruthy = this.reg();
106
- this.emit(` ${isTruthy} = icmp ne i32 ${truthy}, 0`);
117
+ const isTruthy = this.emitTruthiness(left, node.left);
107
118
  condition = this.reg();
108
119
  this.emit(` ${condition} = xor i1 ${isTruthy}, true`);
109
120
  } else {
@@ -128,10 +139,7 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
128
139
  emitConditional(node: ConditionalExpression): string {
129
140
  const result = this.alloca();
130
141
  const condition = this.emitExpression(node.condition);
131
- const truthy = this.reg();
132
- this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${condition})`);
133
- const nonzero = this.reg();
134
- this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
142
+ const nonzero = this.emitTruthiness(condition, node.condition);
135
143
  const trueLabel = this.label("cond.true");
136
144
  const falseLabel = this.label("cond.false");
137
145
  const endLabel = this.label("cond.end");
@@ -195,6 +203,9 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
195
203
  one,
196
204
  node.operator === PrefixUnaryOperator.PlusPlus ? "+" : "-",
197
205
  fn,
206
+ true,
207
+ false,
208
+ true,
198
209
  );
199
210
  this.emitAssignmentTarget(node.operand, next);
200
211
  return next;
@@ -214,6 +225,9 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
214
225
  one,
215
226
  node.operator === PostfixUnaryOperator.PlusPlus ? "+" : "-",
216
227
  fn,
228
+ true,
229
+ false,
230
+ true,
217
231
  );
218
232
  this.emitAssignmentTarget(node.operand, next);
219
233
  return current;
@@ -245,6 +245,10 @@ export const primaryExpressionMethods: PrimaryExpressionMethods = {
245
245
  this.reportRequireUse(identifier);
246
246
  return i64(XT_UNDEFINED);
247
247
  }
248
+ /* The parser's recovery node for a missing expression. The syntax
249
+ * error has already been reported; "Cannot find name '<error>'" is
250
+ * pure noise on top of it. */
251
+ if (identifier.text === "<error>") return i64(XT_UNDEFINED);
248
252
  this.diagnostics.error(
249
253
  DiagnosticCode.CannotFindName,
250
254
  `Cannot find name '${identifier.text}'`,
@@ -100,13 +100,6 @@ export const moduleMethods: ModuleMethods = {
100
100
 
101
101
  emitFunction(fn: FunctionInfo): void {
102
102
  this.unsupportedCount = 0;
103
- // `async function*` would need an async iterator and a promise-returning
104
- // `.next()`; the generator/async lowering below would silently produce a
105
- // synchronous generator instead, so reject it rather than miscompile.
106
- if (fn.isAsync && fn.isGenerator) {
107
- this.unsupported(fn.node, "async generator function");
108
- return;
109
- }
110
103
  const name = this.functionName(fn);
111
104
  const debugSubprogram = this.debugSubprogramFor(fn);
112
105
  const state: FunctionState = {
@@ -12,9 +12,41 @@
12
12
  * mask and the operation is `bitcast` → `fadd`/`fcmp` → `bitcast`.
13
13
  */
14
14
 
15
+ import {
16
+ BinaryOperator,
17
+ PrefixUnaryOperator,
18
+ SyntaxKind,
19
+ type BinaryExpression,
20
+ type Expression,
21
+ type PrefixUnaryExpression,
22
+ } from "../../ast/nodes.js";
15
23
  import { i64, XT_FALSE, XT_NUMBER_MASK, XT_TRUE } from "../values.js";
16
24
  import type { Generator } from "./generator.js";
17
25
 
26
+ /** Operators whose runtime result is always `XT_TRUE` / `XT_FALSE`. */
27
+ const BOOLEAN_BINARY: ReadonlySet<string> = new Set([
28
+ BinaryOperator.LessThan,
29
+ BinaryOperator.LessThanEquals,
30
+ BinaryOperator.GreaterThan,
31
+ BinaryOperator.GreaterThanEquals,
32
+ BinaryOperator.EqualsEquals,
33
+ BinaryOperator.ExclamationEquals,
34
+ BinaryOperator.EqualsEqualsEquals,
35
+ BinaryOperator.ExclamationEqualsEquals,
36
+ BinaryOperator.In,
37
+ BinaryOperator.InstanceOf,
38
+ ]);
39
+
40
+ /** True when the expression's value is a boolean tag, not an arbitrary value. */
41
+ function isBooleanValue(node: Expression): boolean {
42
+ if (node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword) return true;
43
+ if (node.kind === SyntaxKind.BinaryExpression) {
44
+ return BOOLEAN_BINARY.has((node as BinaryExpression).operator as string);
45
+ }
46
+ return node.kind === SyntaxKind.PrefixUnaryExpression &&
47
+ (node as PrefixUnaryExpression).operator === PrefixUnaryOperator.Exclamation;
48
+ }
49
+
18
50
  export interface NumericMethods {
19
51
  /**
20
52
  * Emit `left <operator> right`, using an inline double fast path when both
@@ -27,11 +59,31 @@ export interface NumericMethods {
27
59
  operator: string,
28
60
  runtime: string,
29
61
  allowFastPath?: boolean,
62
+ leftKnownNumber?: boolean,
63
+ rightKnownNumber?: boolean,
64
+ ): string;
65
+ emitNumericBinary(
66
+ this: Generator,
67
+ left: string,
68
+ right: string,
69
+ instruction: string,
70
+ runtime: string,
71
+ leftKnownNumber?: boolean,
72
+ rightKnownNumber?: boolean,
73
+ ): string;
74
+ emitNumericComparison(
75
+ this: Generator,
76
+ left: string,
77
+ right: string,
78
+ predicate: string,
79
+ runtime: string,
80
+ leftKnownNumber?: boolean,
81
+ rightKnownNumber?: boolean,
30
82
  ): string;
31
- emitNumericBinary(this: Generator, left: string, right: string, instruction: string, runtime: string): string;
32
- emitNumericComparison(this: Generator, left: string, right: string, predicate: string, runtime: string): string;
33
83
  /** Emit an i1 SSA value that is true when `value` is an unboxed double. */
34
84
  isNumberValue(this: Generator, value: string): string;
85
+ /** Emit an i1 branch condition, folding boolean producers to a tag compare. */
86
+ emitTruthiness(this: Generator, value: string, expression?: Expression): string;
35
87
  }
36
88
 
37
89
  /** Canonical quiet NaN; the runtime uses the same pattern in `xt_from_double`. */
@@ -57,12 +109,16 @@ const NUMERIC_COMPARISON: Record<string, string | undefined> = {
57
109
  };
58
110
 
59
111
  export const numericMethods: NumericMethods = {
60
- emitBinaryOperation(left, right, operator, runtime, allowFastPath = true) {
112
+ emitBinaryOperation(left, right, operator, runtime, allowFastPath = true, leftKnownNumber = false, rightKnownNumber = false) {
61
113
  if (allowFastPath) {
62
114
  const instruction = NUMERIC_ARITHMETIC[operator];
63
- if (instruction) return this.emitNumericBinary(left, right, instruction, runtime);
115
+ if (instruction) {
116
+ return this.emitNumericBinary(left, right, instruction, runtime, leftKnownNumber, rightKnownNumber);
117
+ }
64
118
  const predicate = NUMERIC_COMPARISON[operator];
65
- if (predicate) return this.emitNumericComparison(left, right, predicate, runtime);
119
+ if (predicate) {
120
+ return this.emitNumericComparison(left, right, predicate, runtime, leftKnownNumber, rightKnownNumber);
121
+ }
66
122
  }
67
123
  const result = this.reg();
68
124
  this.emit(` ${result} = call i64 @${runtime}(i64 ${left}, i64 ${right})`);
@@ -78,10 +134,10 @@ export const numericMethods: NumericMethods = {
78
134
  return result;
79
135
  },
80
136
 
81
- emitNumericBinary(left, right, instruction, runtime) {
137
+ emitNumericBinary(left, right, instruction, runtime, leftKnownNumber = false, rightKnownNumber = false) {
82
138
  const result = this.alloca();
83
- const leftIsNumber = this.isNumberValue(left);
84
- const rightIsNumber = this.isNumberValue(right);
139
+ const leftIsNumber = leftKnownNumber ? "true" : this.isNumberValue(left);
140
+ const rightIsNumber = rightKnownNumber ? "true" : this.isNumberValue(right);
85
141
  const bothNumbers = this.reg();
86
142
  this.emit(` ${bothNumbers} = and i1 ${leftIsNumber}, ${rightIsNumber}`);
87
143
  const fast = this.label("num.fast");
@@ -119,10 +175,10 @@ export const numericMethods: NumericMethods = {
119
175
  return value;
120
176
  },
121
177
 
122
- emitNumericComparison(left, right, predicate, runtime) {
178
+ emitNumericComparison(left, right, predicate, runtime, leftKnownNumber = false, rightKnownNumber = false) {
123
179
  const result = this.alloca();
124
- const leftIsNumber = this.isNumberValue(left);
125
- const rightIsNumber = this.isNumberValue(right);
180
+ const leftIsNumber = leftKnownNumber ? "true" : this.isNumberValue(left);
181
+ const rightIsNumber = rightKnownNumber ? "true" : this.isNumberValue(right);
126
182
  const bothNumbers = this.reg();
127
183
  this.emit(` ${bothNumbers} = and i1 ${leftIsNumber}, ${rightIsNumber}`);
128
184
  const fast = this.label("cmp.fast");
@@ -155,4 +211,22 @@ export const numericMethods: NumericMethods = {
155
211
  this.emit(` ${merged} = load i64, i64* ${result}`);
156
212
  return merged;
157
213
  },
214
+
215
+ /**
216
+ * A comparison, `in`/`instanceof` or `!` already evaluates to a boolean tag,
217
+ * so its truthiness is a tag compare instead of an `xt_truthy` call. This is
218
+ * the hot condition in `for (let i = 0; i < n; i++)` loops.
219
+ */
220
+ emitTruthiness(value, expression) {
221
+ if (expression && isBooleanValue(expression)) {
222
+ const result = this.reg();
223
+ this.emit(` ${result} = icmp eq i64 ${value}, ${i64(XT_TRUE)}`);
224
+ return result;
225
+ }
226
+ const truthy = this.reg();
227
+ this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${value})`);
228
+ const result = this.reg();
229
+ this.emit(` ${result} = icmp ne i32 ${truthy}, 0`);
230
+ return result;
231
+ },
158
232
  };
@@ -105,6 +105,9 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
105
105
  "declare i64 @xt_function_set_metadata(i64, i64, i32)",
106
106
  "declare i64 @xt_function_set_generator(i64)",
107
107
  "declare i64 @xt_function_set_async(i64)",
108
+ "declare i64 @xt_function_set_async_generator(i64)",
109
+ "declare i64 @xt_async_iter_open(i64)",
110
+ "declare i64 @xt_async_iter_next(i64)",
108
111
  "declare i64 @xt_closure_call(i64, i32, i64*)",
109
112
  "declare i64 @xt_closure_env(i64, i32)",
110
113
  "declare i64 @xt_call_with_this(i64, i64, i32, i64*)",
@@ -180,8 +183,17 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
180
183
  "declare i64 @xt_process_get(i64)",
181
184
  "declare i64 @xt_map_ctor(i32, i64*)",
182
185
  "declare i64 @xt_set_ctor(i32, i64*)",
186
+ "declare i64 @xt_weak_map_ctor(i32, i64*)",
187
+ "declare i64 @xt_weak_set_ctor(i32, i64*)",
188
+ "declare i64 @xt_weak_ref_ctor(i32, i64*)",
189
+ "declare i64 @xt_text_encoder_ctor(i32, i64*)",
190
+ "declare i64 @xt_text_decoder_ctor(i32, i64*)",
183
191
  "declare i64 @xt_date_ctor(i32, i64*)",
184
192
  "declare i64 @xt_regexp_ctor(i32, i64*)",
193
+ "declare i64 @xt_url_search_params_ctor(i32, i64*)",
194
+ "declare i64 @xt_array_buffer_ctor(i32, i64*)",
195
+ "declare i64 @xt_array_buffer_static(i64, i32, i64*)",
196
+ "declare i64 @xt_data_view_ctor(i32, i64*)",
185
197
  "declare i64 @xt_error_ctor(i32, i64*)",
186
198
  "declare i64 @xt_type_error_ctor(i32, i64*)",
187
199
  "declare i64 @xt_range_error_ctor(i32, i64*)",
@@ -264,6 +276,12 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
264
276
  "declare i64 @xt_clear_timeout(i32, i64*)",
265
277
  "declare i64 @xt_set_interval(i32, i64*)",
266
278
  "declare i64 @xt_clear_interval(i32, i64*)",
279
+ "declare i64 @xt_set_immediate(i32, i64*)",
280
+ "declare i64 @xt_clear_immediate(i32, i64*)",
281
+ "declare i64 @xt_queue_microtask(i32, i64*)",
282
+ "declare i64 @xt_performance_get(i64)",
283
+ "declare i64 @xt_performance_call(i64, i32, i64*)",
284
+ "declare i64 @xt_structured_clone(i32, i64*)",
267
285
  "declare i64 @xt_fetch(i32, i64*)",
268
286
  "declare i64 @xt_number_ctor(i32, i64*)",
269
287
  "declare i64 @xt_bigint_ctor(i32, i64*)",
@@ -300,6 +318,10 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
300
318
  "declare i64 @xt_builtin_value_clearTimeout(i64, i64, i32, i64*)",
301
319
  "declare i64 @xt_builtin_value_setInterval(i64, i64, i32, i64*)",
302
320
  "declare i64 @xt_builtin_value_clearInterval(i64, i64, i32, i64*)",
321
+ "declare i64 @xt_builtin_value_setImmediate(i64, i64, i32, i64*)",
322
+ "declare i64 @xt_builtin_value_clearImmediate(i64, i64, i32, i64*)",
323
+ "declare i64 @xt_builtin_value_queueMicrotask(i64, i64, i32, i64*)",
324
+ "declare i64 @xt_builtin_value_structuredClone(i64, i64, i32, i64*)",
303
325
  "declare i64 @xt_builtin_value_fetch(i64, i64, i32, i64*)",
304
326
  "declare i64 @xt_builtin_value_number(i64, i64, i32, i64*)",
305
327
  "declare i64 @xt_builtin_value_string(i64, i64, i32, i64*)",
@@ -310,6 +332,7 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
310
332
  "declare i64 @xt_symbol_static(i64, i32, i64*)",
311
333
  "declare i64 @xt_symbol_get(i64)",
312
334
  "declare i64 @xt_get(i64, i64)",
335
+ "declare i64 @xt_get_ic(i64, i64, i64*)",
313
336
  "declare i64 @xt_set(i64, i64, i64)",
314
337
  "declare i64 @xt_box_new(i64)",
315
338
  "declare i64 @xt_box_get(i64)",
@@ -71,10 +71,7 @@ export const controlFlowStatementMethods: ControlFlowStatementMethods = {
71
71
  const elseLabel = statement.elseStatement ? this.label("if.else") : undefined;
72
72
  const endLabel = this.label("if.end");
73
73
  const condition = this.emitExpression(statement.condition);
74
- const truthy = this.reg();
75
- this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${condition})`);
76
- const nonzero = this.reg();
77
- this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
74
+ const nonzero = this.emitTruthiness(condition, statement.condition);
78
75
  this.terminate(`br i1 ${nonzero}, label %${thenLabel}, label %${elseLabel ?? endLabel}`);
79
76
 
80
77
  this.startBlock(thenLabel);
@@ -12,7 +12,7 @@ import {
12
12
  type VariableDeclarationList,
13
13
  type WhileStatement,
14
14
  } from "../../../ast/nodes.js";
15
- import { numberLiteral } from "../../values.js";
15
+ import { i64, numberLiteral, XT_TRUE } from "../../values.js";
16
16
  import type { Generator } from "../generator.js";
17
17
  import type { LoopLabels } from "../state.js";
18
18
 
@@ -48,10 +48,7 @@ export const loopStatementMethods: LoopStatementMethods = {
48
48
  this.terminate(`br label %${condLabel}`);
49
49
  this.startBlock(condLabel);
50
50
  const condition = this.emitExpression(statement.condition);
51
- const truthy = this.reg();
52
- this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${condition})`);
53
- const nonzero = this.reg();
54
- this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
51
+ const nonzero = this.emitTruthiness(condition, statement.condition);
55
52
  this.terminate(`br i1 ${nonzero}, label %${bodyLabel}, label %${endLabel}`);
56
53
  this.startBlock(bodyLabel);
57
54
  this.current.loops.push({ breakLabel: endLabel, continueLabel: condLabel, tryDepth: this.current.tryFrames.length, labels: this.takePendingLabels() });
@@ -74,10 +71,7 @@ export const loopStatementMethods: LoopStatementMethods = {
74
71
 
75
72
  this.startBlock(condLabel);
76
73
  const condition = this.emitExpression(statement.condition);
77
- const truthy = this.reg();
78
- this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${condition})`);
79
- const nonzero = this.reg();
80
- this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
74
+ const nonzero = this.emitTruthiness(condition, statement.condition);
81
75
  this.terminate(`br i1 ${nonzero}, label %${bodyLabel}, label %${endLabel}`);
82
76
  this.startBlock(endLabel);
83
77
  },
@@ -103,10 +97,7 @@ export const loopStatementMethods: LoopStatementMethods = {
103
97
  this.startBlock(condLabel);
104
98
  if (statement.condition) {
105
99
  const condition = this.emitExpression(statement.condition);
106
- const truthy = this.reg();
107
- this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${condition})`);
108
- const nonzero = this.reg();
109
- this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
100
+ const nonzero = this.emitTruthiness(condition, statement.condition);
110
101
  this.terminate(`br i1 ${nonzero}, label %${bodyLabel}, label %${endLabel}`);
111
102
  } else {
112
103
  this.terminate(`br label %${bodyLabel}`);
@@ -128,6 +119,50 @@ export const loopStatementMethods: LoopStatementMethods = {
128
119
  emitForOf(statement: ForOfStatement | ForInStatement): void {
129
120
  const source = this.emitExpression(statement.expression);
130
121
  const isForIn = statement.kind === SyntaxKind.ForInStatement;
122
+ /* `for await (const x of xs)`: resolve the async iteration protocol once,
123
+ * await one step per iteration, then bind its `value`. Running the await
124
+ * inside the surrounding async coroutine is what makes the loop suspend
125
+ * between elements instead of blocking the event loop. */
126
+ if (!isForIn && (statement as ForOfStatement).awaitModifier) {
127
+ const iterable = this.runtimeCall("xt_async_iter_open", [source]);
128
+ const condLabel = this.label("forawait.cond");
129
+ const bodyLabel = this.label("forawait.body");
130
+ const updateLabel = this.label("forawait.update");
131
+ const endLabel = this.label("forawait.end");
132
+ this.terminate(`br label %${condLabel}`);
133
+
134
+ this.startBlock(condLabel);
135
+ const next = this.runtimeCall("xt_async_iter_next", [iterable]);
136
+ const step = this.runtimeCall("xt_await", [next]);
137
+ const doneKey = this.stringValue("done");
138
+ const done = this.runtimeCall("xt_get", [step, doneKey]);
139
+ /* `xt_truthy` returns i32, so it cannot go through `runtimeCall`
140
+ * (which types every result as i64). */
141
+ const truthy = this.reg();
142
+ this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${done})`);
143
+ const nonzero = this.reg();
144
+ this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
145
+ this.terminate(`br i1 ${nonzero}, label %${endLabel}, label %${bodyLabel}`);
146
+
147
+ this.startBlock(bodyLabel);
148
+ const valueKey = this.stringValue("value");
149
+ const element = this.runtimeCall("xt_get", [step, valueKey]);
150
+ this.bindLoopVariable(statement.initializer, element);
151
+ this.current.loops.push({
152
+ breakLabel: endLabel,
153
+ continueLabel: updateLabel,
154
+ tryDepth: this.current.tryFrames.length,
155
+ labels: this.takePendingLabels(),
156
+ });
157
+ this.emitStatement(statement.statement);
158
+ this.current.loops.pop();
159
+ if (!this.current.terminated) this.terminate(`br label %${updateLabel}`);
160
+
161
+ this.startBlock(updateLabel);
162
+ this.terminate(`br label %${condLabel}`);
163
+ this.startBlock(endLabel);
164
+ return;
165
+ }
131
166
  // `for...in` iterates the enumerable keys (indices become strings);
132
167
  // `for...of` resolves the iteration protocol once, then walks it.
133
168
  const iterable = isForIn
@@ -148,10 +183,9 @@ export const loopStatementMethods: LoopStatementMethods = {
148
183
  /* `xt_iter_has` covers generators too, which cannot be sized up front. */
149
184
  const hasValue = this.reg();
150
185
  this.emit(` ${hasValue} = call i64 @xt_iter_has(i64 ${iterable}, i64 ${index})`);
151
- const truthy = this.reg();
152
- this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${hasValue})`);
186
+ /* `xt_iter_has` always returns a boolean tag, so skip `xt_truthy`. */
153
187
  const nonzero = this.reg();
154
- this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
188
+ this.emit(` ${nonzero} = icmp eq i64 ${hasValue}, ${i64(XT_TRUE)}`);
155
189
  this.terminate(`br i1 ${nonzero}, label %${bodyLabel}, label %${endLabel}`);
156
190
 
157
191
  this.startBlock(bodyLabel);