xbintsc 0.5.23 → 0.5.32

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 (481) hide show
  1. package/AGENTS.md +11 -2
  2. package/README.md +47 -16
  3. package/README.zh-CN.md +21 -2
  4. package/dist/scripts/support-matrix.d.ts +18 -0
  5. package/dist/scripts/support-matrix.js +141 -0
  6. package/dist/scripts/support-matrix.js.map +1 -0
  7. package/dist/src/ast/common.d.ts +2 -2
  8. package/dist/src/ast/declarations.d.ts +7 -1
  9. package/dist/src/ast/expressions.d.ts +5 -0
  10. package/dist/src/ast/kinds.d.ts +2 -0
  11. package/dist/src/ast/kinds.js +2 -0
  12. package/dist/src/ast/kinds.js.map +1 -1
  13. package/dist/src/binder/binder.d.ts +2 -1
  14. package/dist/src/binder/binder.js +2 -0
  15. package/dist/src/binder/binder.js.map +1 -1
  16. package/dist/src/binder/declarations.d.ts +9 -0
  17. package/dist/src/binder/declarations.js +64 -0
  18. package/dist/src/binder/declarations.js.map +1 -1
  19. package/dist/src/binder/references.js +99 -4
  20. package/dist/src/binder/references.js.map +1 -1
  21. package/dist/src/binder/types.d.ts +32 -0
  22. package/dist/src/binder/types.js.map +1 -1
  23. package/dist/src/canonical.d.ts +29 -0
  24. package/dist/src/canonical.js +35 -0
  25. package/dist/src/canonical.js.map +1 -0
  26. package/dist/src/checker/assignability.d.ts +13 -0
  27. package/dist/src/checker/assignability.js +146 -0
  28. package/dist/src/checker/assignability.js.map +1 -0
  29. package/dist/src/checker/calls.d.ts +13 -0
  30. package/dist/src/checker/calls.js +127 -0
  31. package/dist/src/checker/calls.js.map +1 -0
  32. package/dist/src/checker/checker.d.ts +26 -0
  33. package/dist/src/checker/checker.js +31 -0
  34. package/dist/src/checker/checker.js.map +1 -0
  35. package/dist/src/checker/declarations.d.ts +9 -0
  36. package/dist/src/checker/declarations.js +15 -0
  37. package/dist/src/checker/declarations.js.map +1 -0
  38. package/dist/src/checker/flow.d.ts +21 -0
  39. package/dist/src/checker/flow.js +241 -0
  40. package/dist/src/checker/flow.js.map +1 -0
  41. package/dist/src/checker/globals.d.ts +9 -0
  42. package/dist/src/checker/globals.js +29 -0
  43. package/dist/src/checker/globals.js.map +1 -0
  44. package/dist/src/checker/source.d.ts +38 -0
  45. package/dist/src/checker/source.js +48 -0
  46. package/dist/src/checker/source.js.map +1 -0
  47. package/dist/src/checker/type-infer.d.ts +18 -0
  48. package/dist/src/checker/type-infer.js +173 -0
  49. package/dist/src/checker/type-infer.js.map +1 -0
  50. package/dist/src/checker/type-model.d.ts +73 -0
  51. package/dist/src/checker/type-model.js +151 -0
  52. package/dist/src/checker/type-model.js.map +1 -0
  53. package/dist/src/checker/type-system.d.ts +58 -0
  54. package/dist/src/checker/type-system.js +569 -0
  55. package/dist/src/checker/type-system.js.map +1 -0
  56. package/dist/src/checker/typecheck-types.d.ts +22 -0
  57. package/dist/src/checker/typecheck-types.js +109 -0
  58. package/dist/src/checker/typecheck-types.js.map +1 -0
  59. package/dist/src/checker/typecheck.d.ts +62 -0
  60. package/dist/src/checker/typecheck.js +574 -0
  61. package/dist/src/checker/typecheck.js.map +1 -0
  62. package/dist/src/checker/undefined.d.ts +14 -0
  63. package/dist/src/checker/undefined.js +32 -0
  64. package/dist/src/checker/undefined.js.map +1 -0
  65. package/dist/src/checker/walk.d.ts +10 -0
  66. package/dist/src/checker/walk.js +15 -0
  67. package/dist/src/checker/walk.js.map +1 -0
  68. package/dist/src/cli/help.d.ts +7 -0
  69. package/dist/src/cli/help.js +64 -0
  70. package/dist/src/cli/help.js.map +1 -0
  71. package/dist/src/cli/hints.js +2 -1
  72. package/dist/src/cli/hints.js.map +1 -1
  73. package/dist/src/cli/main.js +12 -48
  74. package/dist/src/cli/main.js.map +1 -1
  75. package/dist/src/codegen/generator/calls/access.js +8 -8
  76. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  77. package/dist/src/codegen/generator/calls/invocation.js +9 -4
  78. package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
  79. package/dist/src/codegen/generator/calls/super.d.ts +9 -1
  80. package/dist/src/codegen/generator/calls/super.js +56 -5
  81. package/dist/src/codegen/generator/calls/super.js.map +1 -1
  82. package/dist/src/codegen/generator/context.d.ts +13 -2
  83. package/dist/src/codegen/generator/context.js +25 -19
  84. package/dist/src/codegen/generator/context.js.map +1 -1
  85. package/dist/src/codegen/generator/debug.js +2 -1
  86. package/dist/src/codegen/generator/debug.js.map +1 -1
  87. package/dist/src/codegen/generator/expressions/primary.d.ts +4 -1
  88. package/dist/src/codegen/generator/expressions/primary.js +68 -8
  89. package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
  90. package/dist/src/codegen/generator/generator.js +11 -1
  91. package/dist/src/codegen/generator/generator.js.map +1 -1
  92. package/dist/src/codegen/generator/module.d.ts +3 -0
  93. package/dist/src/codegen/generator/module.js +116 -26
  94. package/dist/src/codegen/generator/module.js.map +1 -1
  95. package/dist/src/codegen/generator/state.d.ts +11 -1
  96. package/dist/src/codegen/generator/state.js.map +1 -1
  97. package/dist/src/codegen/generator/statements/variables.js +26 -7
  98. package/dist/src/codegen/generator/statements/variables.js.map +1 -1
  99. package/dist/src/codegen/generator/tables.d.ts +2 -0
  100. package/dist/src/codegen/generator/tables.js +4 -0
  101. package/dist/src/codegen/generator/tables.js.map +1 -1
  102. package/dist/src/driver/build-key.d.ts +2 -0
  103. package/dist/src/driver/build-key.js +1 -0
  104. package/dist/src/driver/build-key.js.map +1 -1
  105. package/dist/src/driver/bundler/graph.js +5 -1
  106. package/dist/src/driver/bundler/graph.js.map +1 -1
  107. package/dist/src/driver/bundler/merge.js +16 -1
  108. package/dist/src/driver/bundler/merge.js.map +1 -1
  109. package/dist/src/driver/bundler/types.d.ts +12 -0
  110. package/dist/src/driver/compiler.d.ts +1 -1
  111. package/dist/src/driver/compiler.js +3 -0
  112. package/dist/src/driver/compiler.js.map +1 -1
  113. package/dist/src/driver/fingerprint.js +2 -1
  114. package/dist/src/driver/fingerprint.js.map +1 -1
  115. package/dist/src/driver/frontend.d.ts +8 -6
  116. package/dist/src/driver/frontend.js +4 -0
  117. package/dist/src/driver/frontend.js.map +1 -1
  118. package/dist/src/driver/options.d.ts +6 -0
  119. package/dist/src/driver/version.d.ts +1 -1
  120. package/dist/src/driver/version.js +1 -1
  121. package/dist/src/extensions/gui/css.d.ts +26 -0
  122. package/dist/src/extensions/gui/css.js +100 -0
  123. package/dist/src/extensions/gui/css.js.map +1 -0
  124. package/dist/src/extensions/gui/html.js +28 -7
  125. package/dist/src/extensions/gui/html.js.map +1 -1
  126. package/dist/src/extensions/gui/index.js +79 -2
  127. package/dist/src/extensions/gui/index.js.map +1 -1
  128. package/dist/src/extensions/gui/three.d.ts +16 -0
  129. package/dist/src/extensions/gui/three.js +22 -0
  130. package/dist/src/extensions/gui/three.js.map +1 -0
  131. package/dist/src/extensions/media/index.d.ts +6 -5
  132. package/dist/src/extensions/media/index.js +12 -14
  133. package/dist/src/extensions/media/index.js.map +1 -1
  134. package/dist/src/extensions/registry.d.ts +38 -0
  135. package/dist/src/extensions/registry.js +10 -0
  136. package/dist/src/extensions/registry.js.map +1 -1
  137. package/dist/src/index.d.ts +1 -0
  138. package/dist/src/index.js +1 -0
  139. package/dist/src/index.js.map +1 -1
  140. package/dist/src/parser/declarations/classes.js +7 -0
  141. package/dist/src/parser/declarations/classes.js.map +1 -1
  142. package/dist/src/parser/expressions.js +14 -1
  143. package/dist/src/parser/expressions.js.map +1 -1
  144. package/dist/src/parser/literals.js +6 -2
  145. package/dist/src/parser/literals.js.map +1 -1
  146. package/dist/tests/binder/binder.test.js +29 -0
  147. package/dist/tests/binder/binder.test.js.map +1 -1
  148. package/dist/tests/canonical.test.d.ts +1 -0
  149. package/dist/tests/canonical.test.js +19 -0
  150. package/dist/tests/canonical.test.js.map +1 -0
  151. package/dist/tests/checker/checker.test.d.ts +1 -0
  152. package/dist/tests/checker/checker.test.js +245 -0
  153. package/dist/tests/checker/checker.test.js.map +1 -0
  154. package/dist/tests/cli/check.test.js +20 -0
  155. package/dist/tests/cli/check.test.js.map +1 -1
  156. package/dist/tests/conformance/matrix.test.d.ts +6 -0
  157. package/dist/tests/conformance/matrix.test.js +23 -0
  158. package/dist/tests/conformance/matrix.test.js.map +1 -0
  159. package/dist/tests/conformance/test262/manifest.d.ts +115 -0
  160. package/dist/tests/conformance/test262/manifest.js +257 -0
  161. package/dist/tests/conformance/test262/manifest.js.map +1 -0
  162. package/dist/tests/conformance/test262.test.d.ts +11 -0
  163. package/dist/tests/conformance/test262.test.js +74 -0
  164. package/dist/tests/conformance/test262.test.js.map +1 -0
  165. package/dist/tests/docs/structure.test.js +9 -11
  166. package/dist/tests/docs/structure.test.js.map +1 -1
  167. package/dist/tests/e2e/child-process.test.js +3 -2
  168. package/dist/tests/e2e/child-process.test.js.map +1 -1
  169. package/dist/tests/e2e/compile-builtins.test.js +45 -0
  170. package/dist/tests/e2e/compile-builtins.test.js.map +1 -1
  171. package/dist/tests/e2e/compile-objects-classes.test.js +77 -0
  172. package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
  173. package/dist/tests/e2e/differential-syntax.test.d.ts +5 -0
  174. package/dist/tests/e2e/differential-syntax.test.js +95 -0
  175. package/dist/tests/e2e/differential-syntax.test.js.map +1 -0
  176. package/dist/tests/e2e/differential-values.test.js +15 -0
  177. package/dist/tests/e2e/differential-values.test.js.map +1 -1
  178. package/dist/tests/e2e/gui-browser.test.d.ts +13 -0
  179. package/dist/tests/e2e/gui-browser.test.js +163 -0
  180. package/dist/tests/e2e/gui-browser.test.js.map +1 -0
  181. package/dist/tests/e2e/gui-effects.test.d.ts +6 -0
  182. package/dist/tests/e2e/gui-effects.test.js +262 -0
  183. package/dist/tests/e2e/gui-effects.test.js.map +1 -0
  184. package/dist/tests/e2e/gui-example-browser.test.js +2 -2
  185. package/dist/tests/e2e/gui-example-browser.test.js.map +1 -1
  186. package/dist/tests/e2e/gui-example-canvas.test.js +5 -4
  187. package/dist/tests/e2e/gui-example-canvas.test.js.map +1 -1
  188. package/dist/tests/e2e/gui-example-svg.test.js +4 -3
  189. package/dist/tests/e2e/gui-example-svg.test.js.map +1 -1
  190. package/dist/tests/e2e/gui-example-webgl.test.d.ts +10 -0
  191. package/dist/tests/e2e/gui-example-webgl.test.js +75 -0
  192. package/dist/tests/e2e/gui-example-webgl.test.js.map +1 -0
  193. package/dist/tests/e2e/gui-example-webgl2.test.d.ts +8 -0
  194. package/dist/tests/e2e/gui-example-webgl2.test.js +72 -0
  195. package/dist/tests/e2e/gui-example-webgl2.test.js.map +1 -0
  196. package/dist/tests/e2e/gui-example.test.js +4 -3
  197. package/dist/tests/e2e/gui-example.test.js.map +1 -1
  198. package/dist/tests/e2e/gui-helpers.js +4 -3
  199. package/dist/tests/e2e/gui-helpers.js.map +1 -1
  200. package/dist/tests/e2e/gui-layout.test.js +48 -0
  201. package/dist/tests/e2e/gui-layout.test.js.map +1 -1
  202. package/dist/tests/e2e/gui-media.test.js +10 -8
  203. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  204. package/dist/tests/e2e/gui-webgl.test.d.ts +11 -0
  205. package/dist/tests/e2e/gui-webgl.test.js +179 -0
  206. package/dist/tests/e2e/gui-webgl.test.js.map +1 -0
  207. package/dist/tests/e2e/gui-webgl2.test.d.ts +10 -0
  208. package/dist/tests/e2e/gui-webgl2.test.js +238 -0
  209. package/dist/tests/e2e/gui-webgl2.test.js.map +1 -0
  210. package/dist/tests/e2e/harness.d.ts +9 -0
  211. package/dist/tests/e2e/harness.js +14 -2
  212. package/dist/tests/e2e/harness.js.map +1 -1
  213. package/dist/tests/e2e/native-extensions.test.js +2 -1
  214. package/dist/tests/e2e/native-extensions.test.js.map +1 -1
  215. package/dist/tests/e2e/property-descriptors.test.js +20 -0
  216. package/dist/tests/e2e/property-descriptors.test.js.map +1 -1
  217. package/dist/tests/e2e/unicode-output.test.js +5 -3
  218. package/dist/tests/e2e/unicode-output.test.js.map +1 -1
  219. package/dist/tests/e2e/weak-collections.test.js +16 -2
  220. package/dist/tests/e2e/weak-collections.test.js.map +1 -1
  221. package/dist/tests/extensions/gui.test.js +41 -0
  222. package/dist/tests/extensions/gui.test.js.map +1 -1
  223. package/dist/tests/extensions/media.test.js +7 -3
  224. package/dist/tests/extensions/media.test.js.map +1 -1
  225. package/dist/tests/helpers.d.ts +1 -0
  226. package/dist/tests/helpers.js +1 -0
  227. package/dist/tests/helpers.js.map +1 -1
  228. package/dist/tests/parser/declarations.test.js +20 -0
  229. package/dist/tests/parser/declarations.test.js.map +1 -1
  230. package/dist/tests/parser/expressions.test.js +36 -0
  231. package/dist/tests/parser/expressions.test.js.map +1 -1
  232. package/dist/tests/platform.d.ts +32 -0
  233. package/dist/tests/platform.js +40 -0
  234. package/dist/tests/platform.js.map +1 -0
  235. package/dist/tests/platform.test.d.ts +12 -0
  236. package/dist/tests/platform.test.js +51 -0
  237. package/dist/tests/platform.test.js.map +1 -0
  238. package/dist/tests/version.test.js +4 -4
  239. package/dist/tests/version.test.js.map +1 -1
  240. package/doc/ai/README.md +10 -4
  241. package/doc/ai/build-recipe.md +1 -0
  242. package/doc/ai/cli.md +17 -5
  243. package/doc/ai/contributing.md +59 -2
  244. package/doc/ai/extensions.md +38 -7
  245. package/doc/ai/language-support.md +25 -16
  246. package/doc/ai/troubleshooting.md +12 -8
  247. package/doc/ai/zh-CN/README.md +9 -4
  248. package/doc/ai/zh-CN/build-recipe.md +1 -0
  249. package/doc/ai/zh-CN/cli.md +13 -3
  250. package/doc/ai/zh-CN/contributing.md +49 -3
  251. package/doc/ai/zh-CN/extensions.md +33 -6
  252. package/doc/ai/zh-CN/language-support.md +23 -14
  253. package/doc/ai/zh-CN/troubleshooting.md +10 -6
  254. package/doc/gui/api.md +47 -1
  255. package/doc/gui/build.md +72 -16
  256. package/doc/gui/canvas.md +11 -3
  257. package/doc/gui/dom.md +33 -18
  258. package/doc/gui/known-issues.md +58 -15
  259. package/doc/gui/layout.md +18 -0
  260. package/doc/gui/media.md +17 -13
  261. package/doc/gui/rendering.md +50 -3
  262. package/doc/gui/runtime.md +18 -0
  263. package/doc/gui/webgl.md +256 -0
  264. package/doc/gui-scripts.md +7 -0
  265. package/doc/gui.md +108 -17
  266. package/doc/implemented/binder.md +2 -0
  267. package/doc/implemented/checker.md +117 -0
  268. package/doc/implemented/cli.md +13 -1
  269. package/doc/implemented/codegen.md +3 -2
  270. package/doc/implemented/driver.md +2 -2
  271. package/doc/implemented/operators.md +2 -1
  272. package/doc/implemented/parser.md +3 -2
  273. package/doc/implemented/pipeline.md +8 -1
  274. package/doc/implemented/stdlib.md +2 -1
  275. package/doc/implemented/tests.md +3 -1
  276. package/doc/implemented.md +2 -0
  277. package/doc/npm-package.md +419 -0
  278. package/doc/requirements.md +22 -10
  279. package/doc/support-matrix.md +83 -0
  280. package/doc/unimplemented/classes.md +3 -0
  281. package/doc/unimplemented/deviations.md +3 -2
  282. package/doc/unimplemented/toolchain.md +1 -1
  283. package/doc/unimplemented/types.md +24 -8
  284. package/doc/unimplemented.md +1 -1
  285. package/doc/zh-CN/gui/api.md +43 -1
  286. package/doc/zh-CN/gui/build.md +64 -15
  287. package/doc/zh-CN/gui/canvas.md +9 -2
  288. package/doc/zh-CN/gui/dom.md +20 -7
  289. package/doc/zh-CN/gui/known-issues.md +46 -13
  290. package/doc/zh-CN/gui/layout.md +14 -0
  291. package/doc/zh-CN/gui/media.md +15 -11
  292. package/doc/zh-CN/gui/rendering.md +41 -4
  293. package/doc/zh-CN/gui/runtime.md +16 -0
  294. package/doc/zh-CN/gui/webgl.md +115 -0
  295. package/doc/zh-CN/gui-scripts.md +5 -0
  296. package/doc/zh-CN/gui.md +89 -14
  297. package/doc/zh-CN/implemented/binder.md +2 -0
  298. package/doc/zh-CN/implemented/checker.md +99 -0
  299. package/doc/zh-CN/implemented/cli.md +12 -1
  300. package/doc/zh-CN/implemented/codegen.md +3 -2
  301. package/doc/zh-CN/implemented/driver.md +2 -2
  302. package/doc/zh-CN/implemented/operators.md +1 -1
  303. package/doc/zh-CN/implemented/parser.md +3 -2
  304. package/doc/zh-CN/implemented/pipeline.md +3 -1
  305. package/doc/zh-CN/implemented/stdlib.md +2 -1
  306. package/doc/zh-CN/implemented/tests.md +3 -1
  307. package/doc/zh-CN/implemented.md +2 -0
  308. package/doc/zh-CN/npm-package.md +394 -0
  309. package/doc/zh-CN/post/announce.md +47 -47
  310. package/doc/zh-CN/requirements.md +16 -7
  311. package/doc/zh-CN/support-matrix.md +82 -0
  312. package/doc/zh-CN/unimplemented/classes.md +3 -0
  313. package/doc/zh-CN/unimplemented/deviations.md +3 -2
  314. package/doc/zh-CN/unimplemented/toolchain.md +1 -1
  315. package/doc/zh-CN/unimplemented/types.md +16 -6
  316. package/doc/zh-CN/unimplemented.md +1 -1
  317. package/llms.txt +6 -1
  318. package/package.json +2 -1
  319. package/runtime/ext_gui/audio.cpp +316 -0
  320. package/runtime/ext_gui/browser.cpp +573 -0
  321. package/runtime/ext_gui/browser_escape.cpp +85 -0
  322. package/runtime/ext_gui/browser_loop.cpp +83 -0
  323. package/runtime/ext_gui/canvas.cpp +12 -21
  324. package/runtime/ext_gui/canvas_internal.h +10 -0
  325. package/runtime/ext_gui/canvas_raster.cpp +79 -1
  326. package/runtime/ext_gui/clip_values.cpp +246 -0
  327. package/runtime/ext_gui/css.cpp +94 -0
  328. package/runtime/ext_gui/css.h +22 -1
  329. package/runtime/ext_gui/css_match.cpp +3 -0
  330. package/runtime/ext_gui/css_selector.cpp +9 -0
  331. package/runtime/ext_gui/css_sheet.cpp +89 -45
  332. package/runtime/ext_gui/document.cpp +4 -1
  333. package/runtime/ext_gui/document.h +2 -0
  334. package/runtime/ext_gui/dom.h +16 -0
  335. package/runtime/ext_gui/dom_api.cpp +37 -0
  336. package/runtime/ext_gui/dom_api_canvas.cpp +17 -80
  337. package/runtime/ext_gui/dom_api_canvas_extra.cpp +130 -1
  338. package/runtime/ext_gui/dom_api_canvas_pending.cpp +41 -0
  339. package/runtime/ext_gui/dom_api_document.cpp +96 -5
  340. package/runtime/ext_gui/dom_api_events.cpp +20 -0
  341. package/runtime/ext_gui/dom_api_internal.h +278 -0
  342. package/runtime/ext_gui/dom_api_proto.cpp +6 -0
  343. package/runtime/ext_gui/dom_api_webgl.cpp +376 -0
  344. package/runtime/ext_gui/dom_api_webgl2.cpp +434 -0
  345. package/runtime/ext_gui/dom_api_webgl2_draw.cpp +269 -0
  346. package/runtime/ext_gui/dom_api_webgl_buffer.cpp +212 -0
  347. package/runtime/ext_gui/dom_api_webgl_rt.h +30 -0
  348. package/runtime/ext_gui/dom_api_webgl_shader.cpp +443 -0
  349. package/runtime/ext_gui/dom_api_webgl_state.cpp +444 -0
  350. package/runtime/ext_gui/dom_api_webgl_texture.cpp +445 -0
  351. package/runtime/ext_gui/effect_values.cpp +312 -0
  352. package/runtime/ext_gui/gradient_values.cpp +476 -0
  353. package/runtime/ext_gui/grid_values.cpp +230 -0
  354. package/runtime/ext_gui/gui.cpp +90 -23
  355. package/runtime/ext_gui/gui_canvas.cpp +50 -2
  356. package/runtime/ext_gui/gui_engine.h +71 -0
  357. package/runtime/ext_gui/gui_events.cpp +4 -1
  358. package/runtime/ext_gui/gui_media.cpp +1 -1
  359. package/runtime/ext_gui/gui_webgl.cpp +83 -0
  360. package/runtime/ext_gui/layout.cpp +21 -0
  361. package/runtime/ext_gui/layout_flow.cpp +81 -4
  362. package/runtime/ext_gui/layout_flow_internal.h +31 -0
  363. package/runtime/ext_gui/layout_grid.cpp +374 -0
  364. package/runtime/ext_gui/media.h +1 -1
  365. package/runtime/ext_gui/media_api.h +2 -2
  366. package/runtime/ext_gui/media_query.cpp +211 -0
  367. package/runtime/ext_gui/paint.cpp +111 -77
  368. package/runtime/ext_gui/paint.h +33 -3
  369. package/runtime/ext_gui/paint_background.cpp +229 -0
  370. package/runtime/ext_gui/paint_clip.cpp +268 -0
  371. package/runtime/ext_gui/paint_effects.cpp +324 -0
  372. package/runtime/ext_gui/paint_internal.h +85 -0
  373. package/runtime/ext_gui/renderer.cpp +8 -31
  374. package/runtime/ext_gui/renderer_clip.cpp +196 -0
  375. package/runtime/ext_gui/renderer_image.cpp +13 -8
  376. package/runtime/ext_gui/renderer_internal.h +15 -8
  377. package/runtime/ext_gui/renderer_text.cpp +6 -31
  378. package/runtime/ext_gui/style.cpp +343 -20
  379. package/runtime/ext_gui/style.h +144 -3
  380. package/runtime/ext_gui/style_print.cpp +134 -1
  381. package/runtime/ext_gui/style_values.cpp +152 -126
  382. package/runtime/ext_gui/style_values_internal.h +35 -0
  383. package/runtime/ext_gui/webgl.h +466 -0
  384. package/runtime/ext_gui/webgl2_constants.h +274 -0
  385. package/runtime/ext_gui/webgl_buffer.cpp +565 -0
  386. package/runtime/ext_gui/webgl_constants.h +317 -0
  387. package/runtime/ext_gui/webgl_context.cpp +466 -0
  388. package/runtime/ext_gui/webgl_draw.cpp +495 -0
  389. package/runtime/ext_gui/webgl_glsl.h +125 -0
  390. package/runtime/ext_gui/webgl_glsl_compile.cpp +431 -0
  391. package/runtime/ext_gui/webgl_glsl_rewrite.cpp +349 -0
  392. package/runtime/ext_gui/webgl_glsl_scan.cpp +581 -0
  393. package/runtime/ext_gui/webgl_msl.cpp +62 -0
  394. package/runtime/ext_gui/webgl_msl.h +33 -0
  395. package/runtime/ext_gui/webgl_pipeline.cpp +274 -0
  396. package/runtime/ext_gui/webgl_program_internal.h +18 -0
  397. package/runtime/ext_gui/webgl_shader.cpp +582 -0
  398. package/runtime/ext_gui/webgl_texture.cpp +293 -0
  399. package/runtime/ext_gui/webgl_uniform.cpp +167 -0
  400. package/runtime/ext_gui/webgl_webgl2.cpp +224 -0
  401. package/runtime/ext_gui/window.cpp +9 -0
  402. package/runtime/ext_media/media.cpp +1 -1
  403. package/runtime/ext_media/media_bridge.c +9 -3
  404. package/runtime/ext_node/path/path.c +7 -7
  405. package/runtime/ext_node/url/url.c +4 -2
  406. package/runtime/rt.h +15 -0
  407. package/runtime/rt_internal.h +1 -0
  408. package/runtime/xt_constructors.c +2 -1
  409. package/runtime/xt_containers/access.inc +8 -0
  410. package/runtime/xt_containers/objects.inc +22 -2
  411. package/runtime/xt_io/exception.inc +4 -2
  412. package/runtime/xt_regex/api.inc +2 -0
  413. package/runtime/xt_regex/matcher.inc +16 -3
  414. package/runtime/xt_regex/parser.inc +8 -2
  415. package/runtime/xt_regex/types.inc +3 -0
  416. package/runtime/xt_stdlib/math.inc +62 -0
  417. package/runtime/xt_stdlib2/date.inc +7 -1
  418. package/runtime/xt_stdlib2/objects.inc +14 -0
  419. package/runtime/xt_stdlib2/regexp-match.inc +60 -21
  420. package/runtime/xt_stdlib2/regexp.inc +1 -0
  421. package/runtime/xt_typed_array.c +1 -1
  422. package/scripts/build-gui.ts +90 -3
  423. package/scripts/build-media.ts +323 -58
  424. package/scripts/setup-vs-toolchain.ps1 +152 -0
  425. package/scripts/support-matrix.ts +167 -0
  426. package/src/ast/common.ts +2 -0
  427. package/src/ast/declarations.ts +12 -1
  428. package/src/ast/expressions.ts +6 -0
  429. package/src/ast/kinds.ts +2 -0
  430. package/src/binder/binder.ts +3 -0
  431. package/src/binder/declarations.ts +70 -0
  432. package/src/binder/references.ts +97 -4
  433. package/src/binder/types.ts +30 -0
  434. package/src/canonical.ts +37 -0
  435. package/src/checker/assignability.ts +134 -0
  436. package/src/checker/calls.ts +135 -0
  437. package/src/checker/checker.ts +47 -0
  438. package/src/checker/declarations.ts +26 -0
  439. package/src/checker/flow.ts +236 -0
  440. package/src/checker/globals.ts +40 -0
  441. package/src/checker/source.ts +53 -0
  442. package/src/checker/type-infer.ts +185 -0
  443. package/src/checker/type-model.ts +212 -0
  444. package/src/checker/type-system.ts +578 -0
  445. package/src/checker/typecheck-types.ts +112 -0
  446. package/src/checker/typecheck.ts +586 -0
  447. package/src/checker/undefined.ts +43 -0
  448. package/src/checker/walk.ts +16 -0
  449. package/src/cli/help.ts +65 -0
  450. package/src/cli/hints.ts +2 -1
  451. package/src/cli/main.ts +12 -49
  452. package/src/codegen/generator/calls/access.ts +8 -8
  453. package/src/codegen/generator/calls/invocation.ts +8 -5
  454. package/src/codegen/generator/calls/super.ts +67 -5
  455. package/src/codegen/generator/context.ts +31 -19
  456. package/src/codegen/generator/debug.ts +2 -1
  457. package/src/codegen/generator/expressions/primary.ts +84 -13
  458. package/src/codegen/generator/generator.ts +11 -1
  459. package/src/codegen/generator/module.ts +115 -24
  460. package/src/codegen/generator/state.ts +11 -1
  461. package/src/codegen/generator/statements/variables.ts +26 -6
  462. package/src/codegen/generator/tables.ts +5 -0
  463. package/src/driver/build-key.ts +3 -0
  464. package/src/driver/bundler/graph.ts +6 -2
  465. package/src/driver/bundler/merge.ts +14 -1
  466. package/src/driver/bundler/types.ts +13 -0
  467. package/src/driver/compiler.ts +4 -1
  468. package/src/driver/fingerprint.ts +2 -1
  469. package/src/driver/frontend.ts +13 -2
  470. package/src/driver/options.ts +6 -0
  471. package/src/driver/version.ts +1 -1
  472. package/src/extensions/gui/css.ts +113 -0
  473. package/src/extensions/gui/html.ts +31 -11
  474. package/src/extensions/gui/index.ts +81 -2
  475. package/src/extensions/gui/three.ts +25 -0
  476. package/src/extensions/media/index.ts +13 -16
  477. package/src/extensions/registry.ts +48 -0
  478. package/src/index.ts +1 -0
  479. package/src/parser/declarations/classes.ts +7 -0
  480. package/src/parser/expressions.ts +13 -1
  481. package/src/parser/literals.ts +6 -2
@@ -43,6 +43,24 @@ export interface SymbolInfo {
43
43
  boxed: boolean;
44
44
  }
45
45
 
46
+ /**
47
+ * A same-scope declaration that cannot legally merge with the symbol already
48
+ * bound to that name (`let x` twice, `function f` then `const f`, ...).
49
+ *
50
+ * The binder records the conflict instead of reporting it: whether it is an
51
+ * error is checker policy (`--no-check` keeps the old, permissive behaviour),
52
+ * while the fact itself is cheap to capture during the one declaration pass.
53
+ */
54
+ export interface DeclarationConflict {
55
+ readonly name: string;
56
+ /** The symbol the name was already bound to. */
57
+ readonly existing: SymbolInfo;
58
+ /** The kind of the offending declaration. */
59
+ readonly kind: SymbolKind;
60
+ /** The offending declaration node (the second one to use the name). */
61
+ readonly node: Node;
62
+ }
63
+
46
64
  export type FunctionNode = SourceFileNode | FunctionDeclaration | FunctionExpression | ArrowFunction;
47
65
 
48
66
  export interface FunctionInfo {
@@ -88,10 +106,20 @@ export interface ClassInfo {
88
106
  readonly fields: ClassFieldInfo[];
89
107
  readonly methods: FunctionInfo[];
90
108
  readonly statics: FunctionInfo[];
109
+ /** `static { ... }` blocks, in declaration order. */
110
+ readonly staticBlocks: FunctionInfo[];
111
+ /** Static fields and static blocks, interleaved in declaration order: they
112
+ * run in source order, while static methods are installed before both. */
113
+ readonly staticInit: ClassStaticInit[];
91
114
  ctor?: FunctionInfo;
92
115
  /** The symbol the class name binds to, when there is one. */
93
116
  }
94
117
 
118
+ /** One static element evaluated at class-definition time, in source order. */
119
+ export type ClassStaticInit =
120
+ | { readonly kind: "field"; readonly field: ClassFieldInfo }
121
+ | { readonly kind: "block"; readonly fn: FunctionInfo };
122
+
95
123
  export interface ClassFieldInfo {
96
124
  readonly name: string;
97
125
  readonly initializer: Expression | undefined;
@@ -129,6 +157,8 @@ export interface BindResult {
129
157
  readonly scopes: Map<Node, Scope>;
130
158
  /** Identifier references that could not be resolved in user code. */
131
159
  readonly unresolved: Identifier[];
160
+ /** Same-scope declarations that cannot merge (see {@link DeclarationConflict}). */
161
+ readonly conflicts: readonly DeclarationConflict[];
132
162
  }
133
163
 
134
164
  export interface MutableFunction extends FunctionInfo {
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Canonical bytes for compiler-emitted artifacts.
3
+ *
4
+ * The compiler runs on Windows, macOS and Linux, and can be compiled by
5
+ * itself. Anything it writes into a byte-compared artifact — LLVM IR, debug
6
+ * metadata, the compiler fingerprint, the bundled module text and the `path`
7
+ * module's results — has to use the same representation on every host. These
8
+ * constants are that representation: do not spell `"/"` or `"\n"` in code that
9
+ * emits an artifact.
10
+ *
11
+ * Native paths are deliberately different. Diagnostics, `import.meta.filename`
12
+ * and `process.cwd()` keep the host separator, exactly like Node. Convert a
13
+ * native path with {@link artifactPath} only when it enters an artifact.
14
+ */
15
+
16
+ /** Separator between path segments in a compiler artifact. Deliberately not
17
+ * selected by `process.platform`: every host writes `/`, so the same source
18
+ * produces the same bytes (and Windows accepts `/` in every API). */
19
+ export const ARTIFACT_PATH_SEPARATOR = "/";
20
+
21
+ /** Line ending between records in a compiler artifact. Deliberately not
22
+ * `os.EOL`/`"\r\n"` on Windows: the runtime opens stdout/stderr in binary
23
+ * mode, and CRLF would make IR, fingerprints and documentation differ per
24
+ * host. */
25
+ export const ARTIFACT_LINE_ENDING = "\n";
26
+
27
+ /**
28
+ * Rewrite a native path for an artifact: `C:\dir\file.ts` becomes
29
+ * `C:/dir/file.ts`. A backslash is always a separator here, matching how the
30
+ * runtime and Node treat Windows paths.
31
+ */
32
+ export function artifactPath(path: string): string {
33
+ // `split`/`join` is measurably faster than a regex or `replaceAll` for the
34
+ // short paths this sees (it runs once per emitted stack frame), and it is the
35
+ // exact transform the compiler used before it was centralised.
36
+ return path.split("\\").join(ARTIFACT_PATH_SEPARATOR);
37
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Structural assignability for the small type model.
3
+ *
4
+ * This is intentionally lenient: every case the model cannot decide returns
5
+ * `true`. A `false` is reserved for a definite mismatch (a string where a
6
+ * number is required, a required property that is absent from a closed shape),
7
+ * because a false negative only hides a bug while a false positive rejects
8
+ * working code.
9
+ */
10
+
11
+ import { isAny, unionMembers, type Type } from "./type-model.js";
12
+
13
+ const MAX_DEPTH = 8;
14
+
15
+ export function isAssignable(source: Type, target: Type, depth = 0): boolean {
16
+ if (depth > MAX_DEPTH) return true;
17
+ if (isAny(source) || isAny(target)) return true;
18
+
19
+ // Every member of a source union must fit; a target union accepts if any
20
+ // member fits. Source first, so `("a" | "b")` fits `("a" | "b")`.
21
+ if (source.kind === "union") {
22
+ return source.members.every((member) => isAssignable(member, target, depth + 1));
23
+ }
24
+ if (target.kind === "union") {
25
+ return target.members.some((member) => isAssignable(source, member, depth + 1));
26
+ }
27
+
28
+ if (target.kind === "literal") {
29
+ if (source.kind === "literal") return source.value === target.value;
30
+ if (source.kind === "primitive") return source.name === target.primitive;
31
+ return false;
32
+ }
33
+
34
+ if (target.kind === "primitive") {
35
+ return assignableToPrimitive(source, target.name);
36
+ }
37
+
38
+ if (source.kind === "literal") {
39
+ if (target.kind === "object") return false;
40
+ if (target.kind === "array" || target.kind === "tuple" || target.kind === "function") return false;
41
+ return true;
42
+ }
43
+
44
+ if (source.kind === "primitive") {
45
+ // `null` / `undefined` are accepted everywhere: the compiler does not
46
+ // enable strict-null checking, so rejecting them would break working code.
47
+ if (source.name === "null" || source.name === "undefined" || source.name === "void") return true;
48
+ if (target.kind === "object") return false;
49
+ if (target.kind === "array" || target.kind === "tuple" || target.kind === "function") return false;
50
+ return true;
51
+ }
52
+
53
+ if (target.kind === "array") {
54
+ if (source.kind === "array") return isAssignable(source.element, target.element, depth + 1);
55
+ if (source.kind === "tuple") return source.elements.every((element) => isAssignable(element, target.element, depth + 1));
56
+ return false;
57
+ }
58
+
59
+ if (target.kind === "tuple") {
60
+ if (source.kind === "tuple") {
61
+ if (source.elements.length !== target.elements.length) return false;
62
+ return source.elements.every((element, index) => isAssignable(element, target.elements[index]!, depth + 1));
63
+ }
64
+ // Array-to-tuple is not generally safe, but the model cannot prove it is
65
+ // wrong, so stay silent.
66
+ return source.kind === "array";
67
+ }
68
+
69
+ if (target.kind === "object") {
70
+ if (source.kind === "array" || source.kind === "tuple") {
71
+ // Arrays have prototype members this model does not enumerate; only a
72
+ // target with no required properties can be judged.
73
+ return [...target.properties.values()].every((property) => property.optional);
74
+ }
75
+ if (source.kind !== "object") return false;
76
+ for (const [name, targetProperty] of target.properties) {
77
+ const sourceProperty = source.properties.get(name);
78
+ if (!sourceProperty) {
79
+ if (targetProperty.optional) continue;
80
+ if (source.index && isAssignable(source.index, targetProperty.type, depth + 1)) continue;
81
+ if (!target.closed) continue;
82
+ return false;
83
+ }
84
+ if (!isAssignable(sourceProperty.type, targetProperty.type, depth + 1)) return false;
85
+ }
86
+ if (target.index) {
87
+ if (source.index && !isAssignable(source.index, target.index, depth + 1)) return false;
88
+ for (const property of source.properties.values()) {
89
+ if (!isAssignable(property.type, target.index, depth + 1)) return false;
90
+ }
91
+ }
92
+ return true;
93
+ }
94
+
95
+ if (target.kind === "function") {
96
+ if (source.kind !== "function") {
97
+ // A function-typed value can also wear object members; do not guess.
98
+ return source.kind === "object";
99
+ }
100
+ const required = target.parameters.filter((parameter) => !parameter.optional && !parameter.rest).length;
101
+ if (source.parameters.length < required) return false;
102
+ for (let index = 0; index < target.parameters.length; index++) {
103
+ const sourceParameter = source.parameters[index];
104
+ const targetParameter = target.parameters[index];
105
+ if (!sourceParameter || !targetParameter) break;
106
+ if (!isAssignable(targetParameter.type, sourceParameter.type, depth + 1)) return false;
107
+ }
108
+ return isAssignable(source.returnType, target.returnType, depth + 1);
109
+ }
110
+
111
+ return true;
112
+ }
113
+
114
+ function assignableToPrimitive(source: Type, name: string): boolean {
115
+ if (name === "null" || name === "undefined" || name === "void") return true;
116
+ if (source.kind === "literal") return source.primitive === name;
117
+ if (source.kind === "primitive") {
118
+ if (source.name === "null" || source.name === "undefined" || source.name === "void") return true;
119
+ return source.name === name;
120
+ }
121
+ if (name === "object") return source.kind === "object" || source.kind === "array" || source.kind === "tuple" || source.kind === "function";
122
+ return false;
123
+ }
124
+
125
+ /** True only when the value is definitely not callable (not merely unknown). */
126
+ export function isDefinitelyNotCallable(type: Type): boolean {
127
+ const members = unionMembers(type);
128
+ return members.every((member) => {
129
+ if (member.kind === "primitive") {
130
+ return member.name === "number" || member.name === "string" || member.name === "boolean" || member.name === "bigint" || member.name === "symbol" || member.name === "null" || member.name === "undefined";
131
+ }
132
+ return member.kind === "literal";
133
+ });
134
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Call arity: `f(1)` where `f` declares two required parameters.
3
+ *
4
+ * Only calls whose callee the checker can resolve without inference are
5
+ * checked: a direct identifier bound to a function declaration, or to a
6
+ * `const` initialised with a function expression / arrow. Methods, imports,
7
+ * first-class re-exports and reassigned bindings are left alone — guessing
8
+ * there is how a checker produces false positives.
9
+ */
10
+
11
+ import {
12
+ SyntaxKind,
13
+ type BinaryExpression,
14
+ type CallExpression,
15
+ type Expression,
16
+ type Identifier,
17
+ type Parameter,
18
+ type SourceFileNode,
19
+ } from "../ast/nodes.js";
20
+ import { SymbolKind, type BindResult, type FunctionInfo } from "../binder/binder.js";
21
+ import { DiagnosticCode, type DiagnosticBag } from "../diagnostics/diagnostic.js";
22
+ import { ASSIGNMENT_OPERATORS } from "../codegen/generator/tables.js";
23
+ import { fileNameOf, isUntypedNode } from "./source.js";
24
+ import { walk } from "./walk.js";
25
+
26
+ interface Arity {
27
+ /** Leading parameters that must be supplied. */
28
+ readonly required: number;
29
+ /** Total parameters, or `Infinity` for a rest parameter. */
30
+ readonly max: number;
31
+ }
32
+
33
+ function arityOf(fn: FunctionInfo): Arity | undefined {
34
+ const parameters = (fn.node as unknown as { parameters?: readonly Parameter[] }).parameters;
35
+ if (!parameters) return undefined;
36
+ let required = 0;
37
+ let max = 0;
38
+ for (const parameter of parameters) {
39
+ if (parameter.dotDotDotToken) return { required, max: Number.POSITIVE_INFINITY };
40
+ max++;
41
+ // A `this:` parameter is a type-only declaration: it is erased and never
42
+ // occupies an argument slot.
43
+ if (parameter.name.kind === SyntaxKind.Identifier && (parameter.name as Identifier).text === "this") {
44
+ max--;
45
+ continue;
46
+ }
47
+ if (!parameter.questionToken && !parameter.initializer) required = max;
48
+ }
49
+ return { required, max };
50
+ }
51
+
52
+ /** Symbols written after their declaration (so their signature can change). */
53
+ function collectAssignedSymbols(sourceFile: SourceFileNode, binding: BindResult): Set<number> {
54
+ const assigned = new Set<number>();
55
+ walk(sourceFile, (node) => {
56
+ if (node.kind !== SyntaxKind.BinaryExpression) return;
57
+ const binary = node as BinaryExpression;
58
+ if (!ASSIGNMENT_OPERATORS.has(binary.operator)) return;
59
+ if (binary.left.kind !== SyntaxKind.Identifier) return;
60
+ const symbol = binding.symbolOfIdentifier.get(binary.left as Identifier);
61
+ if (symbol) assigned.add(symbol.id);
62
+ });
63
+ return assigned;
64
+ }
65
+
66
+ function resolveCallee(binding: BindResult, assigned: ReadonlySet<number>, callee: Expression): FunctionInfo | undefined {
67
+ if (callee.kind !== SyntaxKind.Identifier) return undefined;
68
+ const symbol = binding.symbolOfIdentifier.get(callee as Identifier);
69
+ if (!symbol || symbol.declarations.length !== 1 || assigned.has(symbol.id)) return undefined;
70
+ if (symbol.kind === SymbolKind.Function) {
71
+ return binding.functionOfNode.get(symbol.declarations[0]!);
72
+ }
73
+ if (symbol.kind === SymbolKind.Const) {
74
+ const declaration = symbol.declarations[0]!;
75
+ if (declaration.kind !== SyntaxKind.VariableDeclaration) return undefined;
76
+ const initializer = (declaration as unknown as { initializer?: Expression }).initializer;
77
+ if (!initializer) return undefined;
78
+ if (initializer.kind !== SyntaxKind.ArrowFunction && initializer.kind !== SyntaxKind.FunctionExpression) {
79
+ return undefined;
80
+ }
81
+ return binding.functionOfNode.get(initializer);
82
+ }
83
+ return undefined;
84
+ }
85
+
86
+ function plural(count: number): string {
87
+ return count === 1 ? "argument" : "arguments";
88
+ }
89
+
90
+ function expected(arity: Arity): string {
91
+ if (arity.max === Number.POSITIVE_INFINITY) return `at least ${arity.required} ${plural(arity.required)}`;
92
+ if (arity.required === arity.max) return `${arity.required} ${plural(arity.required)}`;
93
+ return `${arity.required}-${arity.max} ${plural(arity.max)}`;
94
+ }
95
+
96
+ export function checkCallArity(
97
+ sourceFile: SourceFileNode,
98
+ binding: BindResult,
99
+ diagnostics: DiagnosticBag,
100
+ ): void {
101
+ const assigned = collectAssignedSymbols(sourceFile, binding);
102
+ /* `function f() { return arguments.length; }` is a declared-zero-parameter
103
+ * function that legitimately accepts any number of arguments; its parameter
104
+ * list is not the whole signature. */
105
+ const argumentsUsers = new Map<number, boolean>();
106
+ const usesArguments = (fn: FunctionInfo): boolean => {
107
+ const cached = argumentsUsers.get(fn.id);
108
+ if (cached !== undefined) return cached;
109
+ let found = false;
110
+ walk(fn.node, (node) => {
111
+ if (node.kind === SyntaxKind.Identifier && (node as Identifier).text === "arguments") found = true;
112
+ });
113
+ argumentsUsers.set(fn.id, found);
114
+ return found;
115
+ };
116
+ walk(sourceFile, (node) => {
117
+ if (node.kind !== SyntaxKind.CallExpression) return;
118
+ if (isUntypedNode(sourceFile, node)) return;
119
+ const call = node as CallExpression;
120
+ if (call.optional) return;
121
+ if (call.arguments.some((argument) => argument.kind === SyntaxKind.SpreadElement)) return;
122
+ const fn = resolveCallee(binding, assigned, call.expression);
123
+ if (!fn || fn.isModule || usesArguments(fn)) return;
124
+ const arity = arityOf(fn);
125
+ if (!arity) return;
126
+ const argc = call.arguments.length;
127
+ if (argc >= arity.required && argc <= arity.max) return;
128
+ diagnostics.error(
129
+ DiagnosticCode.ArgumentCountMismatch,
130
+ `Expected ${expected(arity)}, but got ${argc}.`,
131
+ call,
132
+ fileNameOf(sourceFile, call),
133
+ );
134
+ });
135
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The opt-out semantic checker (`--check` / `--no-check`).
3
+ *
4
+ * It runs after binding and before code generation. The first three passes are
5
+ * inference-free:
6
+ *
7
+ * 1. identifier references with no declaration and no runtime global,
8
+ * 2. same-scope declarations that cannot merge (`let x` twice, ...),
9
+ * 3. calls whose argument count cannot match a locally-visible signature.
10
+ *
11
+ * The fourth pass uses a deliberately small structural type model to check
12
+ * assignability, property existence and simple flow narrowing. It understands
13
+ * annotations, interfaces, classes, arrays, functions, unions and simple
14
+ * generics; anything else is `any`, so unsupported syntax can hide a bug but
15
+ * never reject working code.
16
+ */
17
+
18
+ import type { SourceFileNode } from "../ast/nodes.js";
19
+ import type { BindResult } from "../binder/binder.js";
20
+ import type { DiagnosticBag } from "../diagnostics/diagnostic.js";
21
+ import { checkCallArity } from "./calls.js";
22
+ import { reportDeclarationConflicts } from "./declarations.js";
23
+ import { checkTypes } from "./typecheck.js";
24
+ import { checkUnresolvedNames } from "./undefined.js";
25
+
26
+ export interface CheckOptions {
27
+ /** Globals supplied by the registered extensions (`print`, `__registerScript`, ...). */
28
+ readonly builtins?: Readonly<Record<string, unknown>>;
29
+ /** Global values supplied by the registered extensions (`window`, `document`). */
30
+ readonly globalValues?: Readonly<Record<string, unknown>>;
31
+ }
32
+
33
+ export function checkProgram(
34
+ sourceFile: SourceFileNode,
35
+ binding: BindResult,
36
+ diagnostics: DiagnosticBag,
37
+ options: CheckOptions = {},
38
+ ): void {
39
+ const builtinNames = new Set<string>([
40
+ ...Object.keys(options.builtins ?? {}),
41
+ ...Object.keys(options.globalValues ?? {}),
42
+ ]);
43
+ checkUnresolvedNames(sourceFile, binding, diagnostics, builtinNames);
44
+ reportDeclarationConflicts(sourceFile, binding, diagnostics);
45
+ checkCallArity(sourceFile, binding, diagnostics);
46
+ checkTypes(sourceFile, binding, diagnostics);
47
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Redeclarations: the binder records same-scope declarations that cannot merge
3
+ * (`let x` twice, `function f` followed by `const f`, ...). This pass turns
4
+ * those facts into diagnostics.
5
+ */
6
+
7
+ import type { SourceFileNode } from "../ast/nodes.js";
8
+ import type { BindResult } from "../binder/binder.js";
9
+ import { DiagnosticCode, type DiagnosticBag } from "../diagnostics/diagnostic.js";
10
+ import { fileNameOf, isDependencyNode } from "./source.js";
11
+
12
+ export function reportDeclarationConflicts(
13
+ sourceFile: SourceFileNode,
14
+ binding: BindResult,
15
+ diagnostics: DiagnosticBag,
16
+ ): void {
17
+ for (const conflict of binding.conflicts) {
18
+ if (isDependencyNode(sourceFile, conflict.node)) continue;
19
+ diagnostics.error(
20
+ DiagnosticCode.DuplicateIdentifier,
21
+ `Duplicate identifier '${conflict.name}'.`,
22
+ conflict.node,
23
+ fileNameOf(sourceFile, conflict.node),
24
+ );
25
+ }
26
+ }
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Lightweight control-flow narrowing.
3
+ *
4
+ * Only the predicates whose refinement is unambiguous are handled:
5
+ * `typeof x === "..."`, comparisons with `null`/`undefined`, `instanceof`,
6
+ * truthiness and the `&&` / `||` / `??` forms that combine them. Everything
7
+ * else leaves the flow untouched, so a missed narrowing can only hide an
8
+ * error, never invent one.
9
+ */
10
+
11
+ import {
12
+ SyntaxKind,
13
+ type BinaryExpression,
14
+ type Expression,
15
+ type Identifier,
16
+ type PrefixUnaryExpression,
17
+ type TypeOfExpression,
18
+ } from "../ast/nodes.js";
19
+ import { primitive, unionMembers, unwrap, type Type } from "./type-model.js";
20
+ import type { TypeResolver } from "./type-system.js";
21
+
22
+ export class Flow {
23
+ constructor(
24
+ readonly parent?: Flow,
25
+ readonly overrides: ReadonlyMap<number, Type> = new Map(),
26
+ ) {}
27
+
28
+ typeOf(symbolId: number): Type | undefined {
29
+ return this.overrides.get(symbolId) ?? this.parent?.typeOf(symbolId);
30
+ }
31
+
32
+ with(overrides: ReadonlyMap<number, Type>): Flow {
33
+ return new Flow(this, overrides);
34
+ }
35
+ }
36
+
37
+ function merge(...maps: ReadonlyMap<number, Type>[]): Map<number, Type> {
38
+ const result = new Map<number, Type>();
39
+ for (const map of maps) for (const [key, value] of map) result.set(key, value);
40
+ return result;
41
+ }
42
+
43
+ function symbolIdOf(expression: Expression, resolver: TypeResolver): number | undefined {
44
+ const unwrapped = unwrap(expression);
45
+ if (unwrapped.kind !== SyntaxKind.Identifier) return undefined;
46
+ return resolver.binding.symbolOfIdentifier.get(unwrapped as Identifier)?.id;
47
+ }
48
+
49
+ function nullishKind(expression: Expression): "null" | "undefined" | "nullish" | undefined {
50
+ const unwrapped = unwrap(expression);
51
+ if (unwrapped.kind === SyntaxKind.NullKeyword) return "null";
52
+ if (unwrapped.kind === SyntaxKind.UndefinedKeyword) return "undefined";
53
+ if (unwrapped.kind === SyntaxKind.Identifier && (unwrapped as Identifier).text === "undefined") return "undefined";
54
+ return undefined;
55
+ }
56
+
57
+ function literalType(expression: Expression): Type | undefined {
58
+ const unwrapped = unwrap(expression);
59
+ switch (unwrapped.kind) {
60
+ case SyntaxKind.StringLiteral:
61
+ case SyntaxKind.NoSubstitutionTemplateLiteral:
62
+ return { kind: "literal", value: (unwrapped as { value: string }).value, primitive: "string" };
63
+ case SyntaxKind.NumericLiteral:
64
+ return { kind: "literal", value: (unwrapped as { value: number }).value, primitive: "number" };
65
+ case SyntaxKind.TrueKeyword:
66
+ return { kind: "literal", value: true, primitive: "boolean" };
67
+ case SyntaxKind.FalseKeyword:
68
+ return { kind: "literal", value: false, primitive: "boolean" };
69
+ default:
70
+ return undefined;
71
+ }
72
+ }
73
+
74
+ const TYPEOF_NAMES: Readonly<Record<string, "string" | "number" | "boolean" | "bigint" | "symbol" | "undefined">> = {
75
+ string: "string",
76
+ number: "number",
77
+ boolean: "boolean",
78
+ bigint: "bigint",
79
+ symbol: "symbol",
80
+ undefined: "undefined",
81
+ };
82
+
83
+ function filterType(type: Type, predicate: (member: Type) => boolean): Type | undefined {
84
+ const kept = unionMembers(type).filter(predicate);
85
+ if (kept.length === 0) return undefined;
86
+ if (kept.length === 1) return kept[0]!;
87
+ return { kind: "union", members: kept };
88
+ }
89
+
90
+ export function withoutNullish(type: Type): Type {
91
+ return filterType(type, (member) => !(member.kind === "primitive" && (member.name === "null" || member.name === "undefined"))) ?? type;
92
+ }
93
+
94
+ function refine(type: Type, predicate: (member: Type) => boolean): Type | undefined {
95
+ return filterType(type, predicate);
96
+ }
97
+
98
+ function positiveRefinement(expression: Expression, flow: Flow, resolver: TypeResolver): Map<number, Type> {
99
+ const result = new Map<number, Type>();
100
+ const unwrapped = unwrap(expression);
101
+
102
+ if (unwrapped.kind === SyntaxKind.Identifier) {
103
+ const id = symbolIdOf(unwrapped, resolver);
104
+ if (id !== undefined) {
105
+ const type = flow.typeOf(id) ?? resolver.typeOfSymbolId(id);
106
+ if (type) result.set(id, withoutNullish(type));
107
+ }
108
+ return result;
109
+ }
110
+
111
+ if (unwrapped.kind === SyntaxKind.PrefixUnaryExpression) {
112
+ const unary = unwrapped as PrefixUnaryExpression;
113
+ if (unary.operator === "!") return negativeRefinement(unary.operand, flow, resolver);
114
+ return result;
115
+ }
116
+
117
+ if (unwrapped.kind !== SyntaxKind.BinaryExpression) return result;
118
+ const binary = unwrapped as BinaryExpression;
119
+ const operator = binary.operator;
120
+
121
+ if (operator === "&&") return merge(positiveRefinement(binary.left, flow, resolver), positiveRefinement(binary.right, flow, resolver));
122
+ if (operator === "||") {
123
+ // `a || b` is truthy when either side is; no single refinement to apply.
124
+ return result;
125
+ }
126
+ if (operator === "??") return positiveRefinement(binary.left, flow, resolver);
127
+
128
+ const equality = operator === "===" || operator === "==";
129
+ const inequality = operator === "!==" || operator === "!=";
130
+ if (equality || inequality) {
131
+ const leftNullish = nullishKind(binary.left);
132
+ const rightNullish = nullishKind(binary.right);
133
+ const nullish = leftNullish ?? rightNullish;
134
+ const other = leftNullish ? binary.right : binary.left;
135
+ const id = symbolIdOf(other, resolver);
136
+ if (id !== undefined && nullish) {
137
+ if (equality) {
138
+ const target = nullish === "nullish" ? [primitive("null"), primitive("undefined")] : [primitive(nullish)];
139
+ for (const type of target) result.set(id, type);
140
+ } else {
141
+ const base = flow.typeOf(id) ?? resolver.typeOfSymbolId(id);
142
+ if (base) {
143
+ const narrowed = refine(base, (member) => !(member.kind === "primitive" && (member.name === "null" || member.name === "undefined")));
144
+ if (narrowed) result.set(id, narrowed);
145
+ }
146
+ }
147
+ return result;
148
+ }
149
+ // `typeof x === "string"` and friends.
150
+ const typeofSide = unwrap(binary.left).kind === SyntaxKind.TypeOfExpression ? binary.left : unwrap(binary.right).kind === SyntaxKind.TypeOfExpression ? binary.right : undefined;
151
+ const literalSide = literalType(typeofSide === binary.left ? binary.right : binary.left);
152
+ if (typeofSide && literalSide?.kind === "literal" && typeof literalSide.value === "string") {
153
+ const name = TYPEOF_NAMES[literalSide.value];
154
+ const operand = (unwrap(typeofSide) as TypeOfExpression).expression;
155
+ const operandId = symbolIdOf(operand, resolver);
156
+ if (name && operandId !== undefined) {
157
+ const base = flow.typeOf(operandId) ?? resolver.typeOfSymbolId(operandId);
158
+ if (base) {
159
+ const narrowed = refine(base, (member) => matchesTypeof(member, name));
160
+ if (narrowed) result.set(operandId, narrowed);
161
+ }
162
+ }
163
+ return result;
164
+ }
165
+ // `x === "literal"` narrows to that literal.
166
+ const leftLiteral = literalType(binary.left);
167
+ const rightLiteral = literalType(binary.right);
168
+ if (leftLiteral && !rightLiteral) {
169
+ const id = symbolIdOf(binary.right, resolver);
170
+ if (id !== undefined) result.set(id, leftLiteral);
171
+ } else if (rightLiteral && !leftLiteral) {
172
+ const id = symbolIdOf(binary.left, resolver);
173
+ if (id !== undefined) result.set(id, rightLiteral);
174
+ }
175
+ return result;
176
+ }
177
+
178
+ if (operator === "instanceof") {
179
+ const id = symbolIdOf(binary.left, resolver);
180
+ if (id === undefined) return result;
181
+ const instance = resolver.classInstanceFromIdentifier(binary.right);
182
+ if (instance) result.set(id, instance);
183
+ }
184
+ return result;
185
+ }
186
+
187
+ function negativeRefinement(expression: Expression, flow: Flow, resolver: TypeResolver): Map<number, Type> {
188
+ const result = new Map<number, Type>();
189
+ const unwrapped = unwrap(expression);
190
+ if (unwrapped.kind === SyntaxKind.PrefixUnaryExpression) {
191
+ const unary = unwrapped as PrefixUnaryExpression;
192
+ if (unary.operator === "!") return positiveRefinement(unary.operand, flow, resolver);
193
+ return result;
194
+ }
195
+ if (unwrapped.kind !== SyntaxKind.BinaryExpression) return result;
196
+ const binary = unwrapped as BinaryExpression;
197
+ if (binary.operator === "&&") {
198
+ // `!(a && b)` does not refine either side on its own.
199
+ return result;
200
+ }
201
+ if (binary.operator === "||") {
202
+ return merge(negativeRefinement(binary.left, flow, resolver), negativeRefinement(binary.right, flow, resolver));
203
+ }
204
+ const equality = binary.operator === "===" || binary.operator === "==";
205
+ const inequality = binary.operator === "!==" || binary.operator === "!=";
206
+ if (!equality && !inequality) return result;
207
+ const leftNullish = nullishKind(binary.left);
208
+ const rightNullish = nullishKind(binary.right);
209
+ const nullish = leftNullish ?? rightNullish;
210
+ const other = leftNullish ? binary.right : binary.left;
211
+ const id = symbolIdOf(other, resolver);
212
+ if (id === undefined || !nullish) return result;
213
+ if (equality) {
214
+ // `!(x === null)` means x is non-null.
215
+ const base = flow.typeOf(id) ?? resolver.typeOfSymbolId(id);
216
+ if (!base) return result;
217
+ const narrowed = refine(base, (member) => !(member.kind === "primitive" && (member.name === "null" || member.name === "undefined")));
218
+ if (narrowed) result.set(id, narrowed);
219
+ } else {
220
+ // `!(x !== null)` means x is null (or nullish for `!= null`).
221
+ const target = nullish === "nullish" ? [primitive("null"), primitive("undefined")] : [primitive(nullish)];
222
+ for (const type of target) result.set(id, type);
223
+ }
224
+ return result;
225
+ }
226
+
227
+ function matchesTypeof(type: Type, name: string): boolean {
228
+ if (type.kind === "literal") return type.primitive === name;
229
+ if (type.kind !== "primitive") return false;
230
+ return type.name === name;
231
+ }
232
+
233
+ export function narrow(condition: Expression, truthy: boolean, flow: Flow, resolver: TypeResolver): Flow {
234
+ const overrides = truthy ? positiveRefinement(condition, flow, resolver) : negativeRefinement(condition, flow, resolver);
235
+ return overrides.size > 0 ? flow.with(overrides) : flow;
236
+ }