redscript-mc 2.6.2 → 3.0.0

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 (636) hide show
  1. package/.github/workflows/ci.yml +11 -0
  2. package/CHANGELOG.md +18 -9
  3. package/README-benchmarks.md +48 -0
  4. package/README-vscode-test.md +251 -0
  5. package/RELEASE_NOTES.md +74 -0
  6. package/ROADMAP.md +131 -167
  7. package/benchmarks/_shared.ts +468 -0
  8. package/benchmarks/baseline.json +2816 -0
  9. package/benchmarks/baseline.md +13 -0
  10. package/benchmarks/compiler-perf.report.json +207 -0
  11. package/benchmarks/compiler-perf.ts +76 -0
  12. package/benchmarks/results.md +13 -0
  13. package/benchmarks/stdlib-complexity.report.json +2606 -0
  14. package/benchmarks/stdlib-complexity.ts +54 -0
  15. package/benchmarks/stdlib-size.md +57 -0
  16. package/benchmarks/stdlib-size.ts +91 -0
  17. package/coverage-report.md +177 -0
  18. package/dist/src/__tests__/budget.test.js +4 -0
  19. package/dist/src/__tests__/cache/cache-behavior.test.d.ts +10 -0
  20. package/dist/src/__tests__/cache/cache-behavior.test.js +425 -0
  21. package/dist/src/__tests__/cache-extra.test.d.ts +5 -0
  22. package/dist/src/__tests__/cache-extra.test.js +211 -0
  23. package/dist/src/__tests__/cli-init.test.d.ts +1 -0
  24. package/dist/src/__tests__/cli-init.test.js +97 -0
  25. package/dist/src/__tests__/cli-publish.test.d.ts +9 -0
  26. package/dist/src/__tests__/cli-publish.test.js +189 -0
  27. package/dist/src/__tests__/cli.test.js +76 -0
  28. package/dist/src/__tests__/compile-preprocess.test.d.ts +11 -0
  29. package/dist/src/__tests__/compile-preprocess.test.js +328 -0
  30. package/dist/src/__tests__/compiler/break-stmt.test.d.ts +1 -0
  31. package/dist/src/__tests__/compiler/break-stmt.test.js +58 -0
  32. package/dist/src/__tests__/compiler/const-decl.test.d.ts +1 -0
  33. package/dist/src/__tests__/compiler/const-decl.test.js +123 -0
  34. package/dist/src/__tests__/compiler/continue-stmt.test.d.ts +1 -0
  35. package/dist/src/__tests__/compiler/continue-stmt.test.js +67 -0
  36. package/dist/src/__tests__/compiler/coroutine-extended.test.d.ts +17 -0
  37. package/dist/src/__tests__/compiler/coroutine-extended.test.js +565 -0
  38. package/dist/src/__tests__/compiler/deprecated.test.d.ts +4 -0
  39. package/dist/src/__tests__/compiler/deprecated.test.js +285 -0
  40. package/dist/src/__tests__/compiler/do-while.test.d.ts +1 -0
  41. package/dist/src/__tests__/compiler/do-while.test.js +120 -0
  42. package/dist/src/__tests__/compiler/enum-payload.test.d.ts +9 -0
  43. package/dist/src/__tests__/compiler/enum-payload.test.js +272 -0
  44. package/dist/src/__tests__/compiler/interface.test.d.ts +10 -0
  45. package/dist/src/__tests__/compiler/interface.test.js +258 -0
  46. package/dist/src/__tests__/compiler/labeled-loops.test.d.ts +1 -0
  47. package/dist/src/__tests__/compiler/labeled-loops.test.js +263 -0
  48. package/dist/src/__tests__/compiler/match-string.test.d.ts +1 -0
  49. package/dist/src/__tests__/compiler/match-string.test.js +43 -0
  50. package/dist/src/__tests__/compiler/memoize.test.d.ts +1 -0
  51. package/dist/src/__tests__/compiler/memoize.test.js +113 -0
  52. package/dist/src/__tests__/compiler/method-chain.test.d.ts +5 -0
  53. package/dist/src/__tests__/compiler/method-chain.test.js +115 -0
  54. package/dist/src/__tests__/compiler/module-import.test.d.ts +12 -0
  55. package/dist/src/__tests__/compiler/module-import.test.js +261 -0
  56. package/dist/src/__tests__/compiler/option-extensions.test.d.ts +6 -0
  57. package/dist/src/__tests__/compiler/option-extensions.test.js +191 -0
  58. package/dist/src/__tests__/compiler/profile-decorator.test.d.ts +1 -0
  59. package/dist/src/__tests__/compiler/profile-decorator.test.js +69 -0
  60. package/dist/src/__tests__/compiler/string-advanced.test.d.ts +7 -0
  61. package/dist/src/__tests__/compiler/string-advanced.test.js +281 -0
  62. package/dist/src/__tests__/compiler/struct-extends.test.d.ts +1 -0
  63. package/dist/src/__tests__/compiler/struct-extends.test.js +95 -0
  64. package/dist/src/__tests__/compiler/throttle-retry.test.d.ts +1 -0
  65. package/dist/src/__tests__/compiler/throttle-retry.test.js +166 -0
  66. package/dist/src/__tests__/compiler/tuple-type.test.d.ts +10 -0
  67. package/dist/src/__tests__/compiler/tuple-type.test.js +229 -0
  68. package/dist/src/__tests__/compiler/watch-decorator.test.d.ts +1 -0
  69. package/dist/src/__tests__/compiler/watch-decorator.test.js +65 -0
  70. package/dist/src/__tests__/config/project-config.test.d.ts +1 -0
  71. package/dist/src/__tests__/config/project-config.test.js +199 -0
  72. package/dist/src/__tests__/config-decorator.test.d.ts +8 -0
  73. package/dist/src/__tests__/config-decorator.test.js +142 -0
  74. package/dist/src/__tests__/diagnostics-extra.test.d.ts +6 -0
  75. package/dist/src/__tests__/diagnostics-extra.test.js +132 -0
  76. package/dist/src/__tests__/emit/compile-branches.test.d.ts +1 -0
  77. package/dist/src/__tests__/emit/compile-branches.test.js +123 -0
  78. package/dist/src/__tests__/emit/compile-coverage.test.d.ts +25 -0
  79. package/dist/src/__tests__/emit/compile-coverage.test.js +617 -0
  80. package/dist/src/__tests__/emit/compile-extra-branches.test.d.ts +12 -0
  81. package/dist/src/__tests__/emit/compile-extra-branches.test.js +225 -0
  82. package/dist/src/__tests__/emit/compile-mocked-branches.test.d.ts +0 -0
  83. package/dist/src/__tests__/emit/compile-mocked-branches.test.js +238 -0
  84. package/dist/src/__tests__/emit/execute-chain.test.d.ts +10 -0
  85. package/dist/src/__tests__/emit/execute-chain.test.js +94 -0
  86. package/dist/src/__tests__/emit/index.test.js +2 -1
  87. package/dist/src/__tests__/emit/modules-branches.test.d.ts +1 -0
  88. package/dist/src/__tests__/emit/modules-branches.test.js +88 -0
  89. package/dist/src/__tests__/emit/modules-coverage.test.d.ts +15 -0
  90. package/dist/src/__tests__/emit/modules-coverage.test.js +221 -0
  91. package/dist/src/__tests__/emit/modules-errors.test.d.ts +12 -0
  92. package/dist/src/__tests__/emit/modules-errors.test.js +169 -0
  93. package/dist/src/__tests__/emit/modules-rewrite.test.d.ts +17 -0
  94. package/dist/src/__tests__/emit/modules-rewrite.test.js +204 -0
  95. package/dist/src/__tests__/emit/source-map.test.d.ts +1 -0
  96. package/dist/src/__tests__/emit/source-map.test.js +167 -0
  97. package/dist/src/__tests__/enum.test.js +9 -4
  98. package/dist/src/__tests__/error-recovery.test.d.ts +7 -0
  99. package/dist/src/__tests__/error-recovery.test.js +217 -0
  100. package/dist/src/__tests__/events-types-extra.test.d.ts +10 -0
  101. package/dist/src/__tests__/events-types-extra.test.js +91 -0
  102. package/dist/src/__tests__/events-types.test.d.ts +4 -0
  103. package/dist/src/__tests__/events-types.test.js +56 -0
  104. package/dist/src/__tests__/formatter.test.js +13 -5
  105. package/dist/src/__tests__/hir/lower-extra.test.d.ts +9 -0
  106. package/dist/src/__tests__/hir/lower-extra.test.js +140 -0
  107. package/dist/src/__tests__/hir/monomorphize-extra.test.d.ts +15 -0
  108. package/dist/src/__tests__/hir/monomorphize-extra.test.js +200 -0
  109. package/dist/src/__tests__/hir/monomorphize-extra2.test.d.ts +16 -0
  110. package/dist/src/__tests__/hir/monomorphize-extra2.test.js +316 -0
  111. package/dist/src/__tests__/incremental.test.js +10 -2
  112. package/dist/src/__tests__/index-extra.test.d.ts +10 -0
  113. package/dist/src/__tests__/index-extra.test.js +71 -0
  114. package/dist/src/__tests__/lexer.test.js +2 -2
  115. package/dist/src/__tests__/lint/rules.test.d.ts +5 -0
  116. package/dist/src/__tests__/lint/rules.test.js +208 -0
  117. package/dist/src/__tests__/lir/lower.test.js +29 -0
  118. package/dist/src/__tests__/lir/verify.test.js +30 -0
  119. package/dist/src/__tests__/lsp/completion.test.d.ts +7 -0
  120. package/dist/src/__tests__/lsp/completion.test.js +583 -0
  121. package/dist/src/__tests__/lsp/definition.test.d.ts +7 -0
  122. package/dist/src/__tests__/lsp/definition.test.js +454 -0
  123. package/dist/src/__tests__/lsp/diagnostics.test.d.ts +10 -0
  124. package/dist/src/__tests__/lsp/diagnostics.test.js +98 -0
  125. package/dist/src/__tests__/lsp/hover-docs.test.d.ts +10 -0
  126. package/dist/src/__tests__/lsp/hover-docs.test.js +210 -0
  127. package/dist/src/__tests__/lsp.test.js +4 -1
  128. package/dist/src/__tests__/mc-integration/item-entity-events.test.js +4 -0
  129. package/dist/src/__tests__/mc-integration/stdlib-coverage-2.test.js +4 -0
  130. package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.d.ts +13 -0
  131. package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.js +1227 -0
  132. package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.d.ts +13 -0
  133. package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.js +1509 -0
  134. package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.d.ts +14 -0
  135. package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.js +1374 -0
  136. package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.d.ts +10 -0
  137. package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.js +759 -0
  138. package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.d.ts +13 -0
  139. package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.js +855 -0
  140. package/dist/src/__tests__/mc-integration/stdlib-coverage.test.js +4 -0
  141. package/dist/src/__tests__/mc-integration/syntax-coverage.test.js +4 -0
  142. package/dist/src/__tests__/mc-validator-coverage.test.d.ts +13 -0
  143. package/dist/src/__tests__/mc-validator-coverage.test.js +296 -0
  144. package/dist/src/__tests__/mc-validator-extra.test.d.ts +13 -0
  145. package/dist/src/__tests__/mc-validator-extra.test.js +245 -0
  146. package/dist/src/__tests__/mir/lower-extra.test.d.ts +20 -0
  147. package/dist/src/__tests__/mir/lower-extra.test.js +361 -0
  148. package/dist/src/__tests__/mir/lower-extra2.test.d.ts +17 -0
  149. package/dist/src/__tests__/mir/lower-extra2.test.js +317 -0
  150. package/dist/src/__tests__/mir/lower-extra3.test.d.ts +19 -0
  151. package/dist/src/__tests__/mir/lower-extra3.test.js +249 -0
  152. package/dist/src/__tests__/mir/lower-extra4.test.d.ts +23 -0
  153. package/dist/src/__tests__/mir/lower-extra4.test.js +606 -0
  154. package/dist/src/__tests__/mir/lower-extra5.test.d.ts +25 -0
  155. package/dist/src/__tests__/mir/lower-extra5.test.js +543 -0
  156. package/dist/src/__tests__/mir/lower-extra6.test.d.ts +16 -0
  157. package/dist/src/__tests__/mir/lower-extra6.test.js +471 -0
  158. package/dist/src/__tests__/mir/lower-extra7.test.d.ts +35 -0
  159. package/dist/src/__tests__/mir/lower-extra7.test.js +921 -0
  160. package/dist/src/__tests__/mir/lower-extra8.test.d.ts +19 -0
  161. package/dist/src/__tests__/mir/lower-extra8.test.js +626 -0
  162. package/dist/src/__tests__/mir/lower-extra9.test.d.ts +14 -0
  163. package/dist/src/__tests__/mir/lower-extra9.test.js +717 -0
  164. package/dist/src/__tests__/optimizer/auto-inline.test.d.ts +1 -0
  165. package/dist/src/__tests__/optimizer/auto-inline.test.js +176 -0
  166. package/dist/src/__tests__/optimizer/cse.test.d.ts +4 -0
  167. package/dist/src/__tests__/optimizer/cse.test.js +178 -0
  168. package/dist/src/__tests__/optimizer/inline_fn.test.d.ts +1 -0
  169. package/dist/src/__tests__/optimizer/inline_fn.test.js +221 -0
  170. package/dist/src/__tests__/optimizer/licm.test.d.ts +1 -0
  171. package/dist/src/__tests__/optimizer/licm.test.js +244 -0
  172. package/dist/src/__tests__/optimizer/optimizer-extended.test.d.ts +12 -0
  173. package/dist/src/__tests__/optimizer/optimizer-extended.test.js +993 -0
  174. package/dist/src/__tests__/optimizer/strength-reduction.test.d.ts +1 -0
  175. package/dist/src/__tests__/optimizer/strength-reduction.test.js +86 -0
  176. package/dist/src/__tests__/optimizer/tco.test.d.ts +14 -0
  177. package/dist/src/__tests__/optimizer/tco.test.js +203 -0
  178. package/dist/src/__tests__/parser-coverage.test.d.ts +25 -0
  179. package/dist/src/__tests__/parser-coverage.test.js +491 -0
  180. package/dist/src/__tests__/parser-extra.test.d.ts +6 -0
  181. package/dist/src/__tests__/parser-extra.test.js +451 -0
  182. package/dist/src/__tests__/parser.test.js +12 -0
  183. package/dist/src/__tests__/repl-extra.test.d.ts +13 -0
  184. package/dist/src/__tests__/repl-extra.test.js +174 -0
  185. package/dist/src/__tests__/repl-server-extra.test.d.ts +10 -0
  186. package/dist/src/__tests__/repl-server-extra.test.js +161 -0
  187. package/dist/src/__tests__/repl-server.test.d.ts +6 -0
  188. package/dist/src/__tests__/repl-server.test.js +146 -0
  189. package/dist/src/__tests__/runtime-extra.test.d.ts +15 -0
  190. package/dist/src/__tests__/runtime-extra.test.js +732 -0
  191. package/dist/src/__tests__/singleton-decorator.test.d.ts +11 -0
  192. package/dist/src/__tests__/singleton-decorator.test.js +260 -0
  193. package/dist/src/__tests__/sourcemap.test.js +1 -1
  194. package/dist/src/__tests__/stdlib/advanced.test.d.ts +5 -0
  195. package/dist/src/__tests__/stdlib/advanced.test.js +301 -0
  196. package/dist/src/__tests__/stdlib/bigint.test.d.ts +4 -0
  197. package/dist/src/__tests__/stdlib/bigint.test.js +83 -0
  198. package/dist/src/__tests__/stdlib/bits.test.d.ts +4 -0
  199. package/dist/src/__tests__/stdlib/bits.test.js +96 -0
  200. package/dist/src/__tests__/stdlib/bossbar.test.d.ts +4 -0
  201. package/dist/src/__tests__/stdlib/bossbar.test.js +72 -0
  202. package/dist/src/__tests__/stdlib/color.test.d.ts +4 -0
  203. package/dist/src/__tests__/stdlib/color.test.js +84 -0
  204. package/dist/src/__tests__/stdlib/combat.test.d.ts +4 -0
  205. package/dist/src/__tests__/stdlib/combat.test.js +64 -0
  206. package/dist/src/__tests__/stdlib/cooldown.test.d.ts +4 -0
  207. package/dist/src/__tests__/stdlib/cooldown.test.js +64 -0
  208. package/dist/src/__tests__/stdlib/dialog.test.js +15 -7
  209. package/dist/src/__tests__/stdlib/ecs.test.d.ts +4 -0
  210. package/dist/src/__tests__/stdlib/ecs.test.js +81 -0
  211. package/dist/src/__tests__/stdlib/effects.test.d.ts +4 -0
  212. package/dist/src/__tests__/stdlib/effects.test.js +72 -0
  213. package/dist/src/__tests__/stdlib/events.test.d.ts +4 -0
  214. package/dist/src/__tests__/stdlib/events.test.js +55 -0
  215. package/dist/src/__tests__/stdlib/expr.test.d.ts +4 -0
  216. package/dist/src/__tests__/stdlib/expr.test.js +77 -0
  217. package/dist/src/__tests__/stdlib/fft.test.d.ts +4 -0
  218. package/dist/src/__tests__/stdlib/fft.test.js +82 -0
  219. package/dist/src/__tests__/stdlib/graph.test.d.ts +4 -0
  220. package/dist/src/__tests__/stdlib/graph.test.js +102 -0
  221. package/dist/src/__tests__/stdlib/interactions.test.d.ts +4 -0
  222. package/dist/src/__tests__/stdlib/interactions.test.js +60 -0
  223. package/dist/src/__tests__/stdlib/inventory.test.d.ts +4 -0
  224. package/dist/src/__tests__/stdlib/inventory.test.js +68 -0
  225. package/dist/src/__tests__/stdlib/linalg.test.d.ts +5 -0
  226. package/dist/src/__tests__/stdlib/linalg.test.js +78 -0
  227. package/dist/src/__tests__/stdlib/map.test.d.ts +1 -0
  228. package/dist/src/__tests__/stdlib/map.test.js +84 -0
  229. package/dist/src/__tests__/stdlib/math.test.js +19 -6
  230. package/dist/src/__tests__/stdlib/math_hp.test.d.ts +4 -0
  231. package/dist/src/__tests__/stdlib/math_hp.test.js +80 -0
  232. package/dist/src/__tests__/stdlib/mobs.test.d.ts +4 -0
  233. package/dist/src/__tests__/stdlib/mobs.test.js +61 -0
  234. package/dist/src/__tests__/stdlib/noise.test.d.ts +4 -0
  235. package/dist/src/__tests__/stdlib/noise.test.js +73 -0
  236. package/dist/src/__tests__/stdlib/ode.test.d.ts +4 -0
  237. package/dist/src/__tests__/stdlib/ode.test.js +68 -0
  238. package/dist/src/__tests__/stdlib/parabola.test.d.ts +4 -0
  239. package/dist/src/__tests__/stdlib/parabola.test.js +77 -0
  240. package/dist/src/__tests__/stdlib/particles.test.d.ts +4 -0
  241. package/dist/src/__tests__/stdlib/particles.test.js +68 -0
  242. package/dist/src/__tests__/stdlib/physics.test.d.ts +4 -0
  243. package/dist/src/__tests__/stdlib/physics.test.js +76 -0
  244. package/dist/src/__tests__/stdlib/player.test.d.ts +4 -0
  245. package/dist/src/__tests__/stdlib/player.test.js +64 -0
  246. package/dist/src/__tests__/stdlib/quaternion.test.d.ts +4 -0
  247. package/dist/src/__tests__/stdlib/quaternion.test.js +73 -0
  248. package/dist/src/__tests__/stdlib/queue.test.d.ts +1 -0
  249. package/dist/src/__tests__/stdlib/queue.test.js +97 -0
  250. package/dist/src/__tests__/stdlib/random.test.d.ts +4 -0
  251. package/dist/src/__tests__/stdlib/random.test.js +76 -0
  252. package/dist/src/__tests__/stdlib/result.test.d.ts +12 -0
  253. package/dist/src/__tests__/stdlib/result.test.js +329 -0
  254. package/dist/src/__tests__/stdlib/scheduler.test.js +19 -8
  255. package/dist/src/__tests__/stdlib/set_int.test.d.ts +1 -0
  256. package/dist/src/__tests__/stdlib/set_int.test.js +88 -0
  257. package/dist/src/__tests__/stdlib/sets.test.d.ts +6 -0
  258. package/dist/src/__tests__/stdlib/sets.test.js +60 -0
  259. package/dist/src/__tests__/stdlib/signal.test.d.ts +4 -0
  260. package/dist/src/__tests__/stdlib/signal.test.js +84 -0
  261. package/dist/src/__tests__/stdlib/spawn.test.d.ts +4 -0
  262. package/dist/src/__tests__/stdlib/spawn.test.js +68 -0
  263. package/dist/src/__tests__/stdlib/string.test.d.ts +12 -0
  264. package/dist/src/__tests__/stdlib/string.test.js +231 -0
  265. package/dist/src/__tests__/stdlib/strings.test.d.ts +4 -0
  266. package/dist/src/__tests__/stdlib/strings.test.js +83 -0
  267. package/dist/src/__tests__/stdlib/tags.test.d.ts +4 -0
  268. package/dist/src/__tests__/stdlib/tags.test.js +57 -0
  269. package/dist/src/__tests__/stdlib/teams.test.d.ts +4 -0
  270. package/dist/src/__tests__/stdlib/teams.test.js +72 -0
  271. package/dist/src/__tests__/stdlib/timer.test.d.ts +4 -0
  272. package/dist/src/__tests__/stdlib/timer.test.js +79 -0
  273. package/dist/src/__tests__/stdlib/vec.test.d.ts +5 -0
  274. package/dist/src/__tests__/stdlib/vec.test.js +94 -0
  275. package/dist/src/__tests__/stdlib/world.test.d.ts +4 -0
  276. package/dist/src/__tests__/stdlib/world.test.js +72 -0
  277. package/dist/src/__tests__/struct-display.test.d.ts +1 -0
  278. package/dist/src/__tests__/struct-display.test.js +64 -0
  279. package/dist/src/__tests__/test-framework/runner.test.d.ts +10 -0
  280. package/dist/src/__tests__/test-framework/runner.test.js +193 -0
  281. package/dist/src/__tests__/tuner/adapters.test.d.ts +14 -0
  282. package/dist/src/__tests__/tuner/adapters.test.js +194 -0
  283. package/dist/src/__tests__/tuner/simulator-extra.test.d.ts +4 -0
  284. package/dist/src/__tests__/tuner/simulator-extra.test.js +193 -0
  285. package/dist/src/__tests__/typechecker-coverage.test.d.ts +30 -0
  286. package/dist/src/__tests__/typechecker-coverage.test.js +627 -0
  287. package/dist/src/__tests__/typechecker.test.js +3 -3
  288. package/dist/src/__tests__/watch-decorator.test.d.ts +1 -0
  289. package/dist/src/__tests__/watch-decorator.test.js +54 -0
  290. package/dist/src/ast/types.d.ts +102 -3
  291. package/dist/src/cache/incremental.d.ts +13 -14
  292. package/dist/src/cache/incremental.js +106 -89
  293. package/dist/src/cache/index.d.ts +8 -2
  294. package/dist/src/cache/index.js +18 -6
  295. package/dist/src/cli.d.ts +1 -0
  296. package/dist/src/cli.js +466 -17
  297. package/dist/src/config/project-config.d.ts +29 -0
  298. package/dist/src/config/project-config.js +180 -0
  299. package/dist/src/diagnostics/index.d.ts +9 -0
  300. package/dist/src/diagnostics/index.js +18 -1
  301. package/dist/src/emit/compile.d.ts +10 -0
  302. package/dist/src/emit/compile.js +395 -50
  303. package/dist/src/emit/index.d.ts +40 -0
  304. package/dist/src/emit/index.js +307 -14
  305. package/dist/src/emit/modules.js +21 -3
  306. package/dist/src/emit/sourcemap.d.ts +23 -27
  307. package/dist/src/emit/sourcemap.js +52 -30
  308. package/dist/src/formatter/index.js +33 -8
  309. package/dist/src/hir/deprecated.d.ts +13 -0
  310. package/dist/src/hir/deprecated.js +218 -0
  311. package/dist/src/hir/lower.js +114 -8
  312. package/dist/src/hir/monomorphize.js +22 -2
  313. package/dist/src/hir/types.d.ts +65 -1
  314. package/dist/src/index.d.ts +6 -0
  315. package/dist/src/index.js +18 -3
  316. package/dist/src/lexer/index.d.ts +2 -1
  317. package/dist/src/lexer/index.js +39 -3
  318. package/dist/src/lint/index.d.ts +45 -0
  319. package/dist/src/lint/index.js +930 -0
  320. package/dist/src/lir/lower.js +29 -2
  321. package/dist/src/lir/types.d.ts +2 -0
  322. package/dist/src/lsp/server.js +92 -5
  323. package/dist/src/mir/lower.js +775 -34
  324. package/dist/src/mir/macro.js +36 -2
  325. package/dist/src/mir/types.d.ts +12 -0
  326. package/dist/src/mir/verify.js +9 -0
  327. package/dist/src/optimizer/auto-inline.d.ts +2 -0
  328. package/dist/src/optimizer/auto-inline.js +67 -0
  329. package/dist/src/optimizer/cse.d.ts +20 -0
  330. package/dist/src/optimizer/cse.js +234 -0
  331. package/dist/src/optimizer/inline.d.ts +26 -0
  332. package/dist/src/optimizer/inline.js +286 -0
  333. package/dist/src/optimizer/interprocedural.js +4 -0
  334. package/dist/src/optimizer/licm.d.ts +32 -0
  335. package/dist/src/optimizer/licm.js +371 -0
  336. package/dist/src/optimizer/pipeline.js +12 -2
  337. package/dist/src/optimizer/strength_reduction.d.ts +15 -0
  338. package/dist/src/optimizer/strength_reduction.js +90 -0
  339. package/dist/src/optimizer/tco.d.ts +53 -0
  340. package/dist/src/optimizer/tco.js +238 -0
  341. package/dist/src/parser/index.d.ts +32 -0
  342. package/dist/src/parser/index.js +421 -59
  343. package/dist/src/repl-server.d.ts +13 -0
  344. package/dist/src/repl-server.js +127 -0
  345. package/dist/src/structs/expand.d.ts +15 -0
  346. package/dist/src/structs/expand.js +46 -0
  347. package/dist/src/testing/runner.d.ts +40 -0
  348. package/dist/src/testing/runner.js +237 -0
  349. package/dist/src/typechecker/index.d.ts +3 -0
  350. package/dist/src/typechecker/index.js +254 -9
  351. package/dist/tsconfig.tsbuildinfo +1 -1
  352. package/doc-drafts/redscript-docs/docs/en/stdlib/graph.md +104 -0
  353. package/doc-drafts/redscript-docs/docs/en/stdlib/parabola.md +113 -0
  354. package/doc-drafts/redscript-docs/docs/en/stdlib/pathfind.md +104 -0
  355. package/doc-drafts/redscript-docs/docs/en/stdlib/physics.md +134 -0
  356. package/doc-drafts/redscript-docs/docs/en/stdlib/quaternion.md +135 -0
  357. package/doc-drafts/redscript-docs/docs/zh/stdlib/graph.md +104 -0
  358. package/doc-drafts/redscript-docs/docs/zh/stdlib/parabola.md +113 -0
  359. package/doc-drafts/redscript-docs/docs/zh/stdlib/pathfind.md +104 -0
  360. package/doc-drafts/redscript-docs/docs/zh/stdlib/physics.md +134 -0
  361. package/doc-drafts/redscript-docs/docs/zh/stdlib/quaternion.md +135 -0
  362. package/docs/stdlib/result.md +156 -0
  363. package/docs/stdlib/result.zh.md +156 -0
  364. package/editors/vscode/fixtures/test.mcrs +7 -0
  365. package/editors/vscode/out/extension.js +2095 -225
  366. package/editors/vscode/out/lsp-server.js +519 -51
  367. package/editors/vscode/package-lock.json +9 -4
  368. package/editors/vscode/package.json +1 -1
  369. package/examples/display-demo.mcrs +64 -0
  370. package/examples/game/racing.mcrs +301 -0
  371. package/examples/game/tower_defense.mcrs +311 -0
  372. package/examples/math/physics_sim.mcrs +322 -0
  373. package/examples/rpg/boss_fight.mcrs +313 -0
  374. package/examples/rpg/health_system.mcrs +237 -0
  375. package/examples/rpg/inventory.mcrs +265 -0
  376. package/examples/util/debug_hud.mcrs +279 -0
  377. package/jest.config.js +10 -0
  378. package/package.json +12 -3
  379. package/playground/index.html +823 -0
  380. package/scripts/gen-docs.ts +533 -0
  381. package/scripts/update-redscript-docs-stdlib.sh +770 -0
  382. package/src/__tests__/budget.test.ts +5 -0
  383. package/src/__tests__/cache/cache-behavior.test.ts +480 -0
  384. package/src/__tests__/cache-extra.test.ts +199 -0
  385. package/src/__tests__/cli-docs.test.ts +77 -0
  386. package/src/__tests__/cli-init.test.ts +91 -0
  387. package/src/__tests__/cli-publish.test.ts +190 -0
  388. package/src/__tests__/cli.test.ts +117 -1
  389. package/src/__tests__/compile-preprocess.test.ts +366 -0
  390. package/src/__tests__/compiler/break-stmt.test.ts +66 -0
  391. package/src/__tests__/compiler/const-decl.test.ts +141 -0
  392. package/src/__tests__/compiler/continue-stmt.test.ts +81 -0
  393. package/src/__tests__/compiler/coroutine-extended.test.ts +723 -0
  394. package/src/__tests__/compiler/deprecated.test.ts +305 -0
  395. package/src/__tests__/compiler/do-while.test.ts +130 -0
  396. package/src/__tests__/compiler/enum-payload.test.ts +299 -0
  397. package/src/__tests__/compiler/interface.test.ts +287 -0
  398. package/src/__tests__/compiler/labeled-loops.test.ts +279 -0
  399. package/src/__tests__/compiler/match-string.test.ts +45 -0
  400. package/src/__tests__/compiler/memoize.test.ts +126 -0
  401. package/src/__tests__/compiler/method-chain.test.ts +121 -0
  402. package/src/__tests__/compiler/module-import.test.ts +240 -0
  403. package/src/__tests__/compiler/option-extensions.test.ts +207 -0
  404. package/src/__tests__/compiler/profile-decorator.test.ts +79 -0
  405. package/src/__tests__/compiler/string-advanced.test.ts +310 -0
  406. package/src/__tests__/compiler/struct-extends.test.ts +109 -0
  407. package/src/__tests__/compiler/throttle-retry.test.ts +191 -0
  408. package/src/__tests__/compiler/tuple-type.test.ts +263 -0
  409. package/src/__tests__/compiler/watch-decorator.test.ts +72 -0
  410. package/src/__tests__/config/project-config.test.ts +181 -0
  411. package/src/__tests__/config-decorator.test.ts +157 -0
  412. package/src/__tests__/diagnostics-extra.test.ts +155 -0
  413. package/src/__tests__/emit/compile-branches.test.ts +135 -0
  414. package/src/__tests__/emit/compile-coverage.test.ts +696 -0
  415. package/src/__tests__/emit/compile-extra-branches.test.ts +228 -0
  416. package/src/__tests__/emit/compile-mocked-branches.test.ts +249 -0
  417. package/src/__tests__/emit/compile.test.ts +6 -1
  418. package/src/__tests__/emit/execute-chain.test.ts +114 -0
  419. package/src/__tests__/emit/index.test.ts +2 -1
  420. package/src/__tests__/emit/modules-branches.test.ts +90 -0
  421. package/src/__tests__/emit/modules-coverage.test.ts +241 -0
  422. package/src/__tests__/emit/modules-errors.test.ts +192 -0
  423. package/src/__tests__/emit/modules-rewrite.test.ts +232 -0
  424. package/src/__tests__/emit/source-map.test.ts +152 -0
  425. package/src/__tests__/enum.test.ts +9 -4
  426. package/src/__tests__/error-recovery.test.ts +226 -0
  427. package/src/__tests__/events-types-extra.test.ts +110 -0
  428. package/src/__tests__/events-types.test.ts +66 -0
  429. package/src/__tests__/formatter.test.ts +15 -5
  430. package/src/__tests__/generics.test.ts +16 -9
  431. package/src/__tests__/hir/lower-extra.test.ts +151 -0
  432. package/src/__tests__/hir/monomorphize-coverage.test.ts +432 -0
  433. package/src/__tests__/hir/monomorphize-extra.test.ts +220 -0
  434. package/src/__tests__/hir/monomorphize-extra2.test.ts +350 -0
  435. package/src/__tests__/impl.test.ts +12 -8
  436. package/src/__tests__/incremental.test.ts +10 -2
  437. package/src/__tests__/index-extra.test.ts +79 -0
  438. package/src/__tests__/lexer.test.ts +2 -2
  439. package/src/__tests__/lint/hir-coverage.test.ts +1716 -0
  440. package/src/__tests__/lint/rules-coverage.test.ts +598 -0
  441. package/src/__tests__/lint/rules.test.ts +230 -0
  442. package/src/__tests__/lir/lower.test.ts +33 -0
  443. package/src/__tests__/lir/verify.test.ts +33 -0
  444. package/src/__tests__/lsp/completion.test.ts +687 -0
  445. package/src/__tests__/lsp/definition.test.ts +499 -0
  446. package/src/__tests__/lsp/diagnostics.test.ts +108 -0
  447. package/src/__tests__/lsp/hover-docs.test.ts +222 -0
  448. package/src/__tests__/lsp.test.ts +4 -1
  449. package/src/__tests__/mc-integration/item-entity-events.test.ts +5 -0
  450. package/src/__tests__/mc-integration/stdlib-coverage-2.test.ts +5 -0
  451. package/src/__tests__/mc-integration/stdlib-coverage-3.test.ts +1105 -0
  452. package/src/__tests__/mc-integration/stdlib-coverage-4.test.ts +1366 -0
  453. package/src/__tests__/mc-integration/stdlib-coverage-5.test.ts +1245 -0
  454. package/src/__tests__/mc-integration/stdlib-coverage-6.test.ts +755 -0
  455. package/src/__tests__/mc-integration/stdlib-coverage-7.test.ts +771 -0
  456. package/src/__tests__/mc-integration/stdlib-coverage.test.ts +5 -0
  457. package/src/__tests__/mc-integration/syntax-coverage.test.ts +5 -0
  458. package/src/__tests__/mc-validator-coverage.test.ts +325 -0
  459. package/src/__tests__/mc-validator-extra.test.ts +252 -0
  460. package/src/__tests__/mir/lower-extra.test.ts +402 -0
  461. package/src/__tests__/mir/lower-extra2.test.ts +348 -0
  462. package/src/__tests__/mir/lower-extra3.test.ts +277 -0
  463. package/src/__tests__/mir/lower-extra4.test.ts +636 -0
  464. package/src/__tests__/mir/lower-extra5.test.ts +612 -0
  465. package/src/__tests__/mir/lower-extra6.test.ts +520 -0
  466. package/src/__tests__/mir/lower-extra7.test.ts +1045 -0
  467. package/src/__tests__/mir/lower-extra8.test.ts +704 -0
  468. package/src/__tests__/mir/lower-extra9.test.ts +821 -0
  469. package/src/__tests__/optimizer/auto-inline.test.ts +206 -0
  470. package/src/__tests__/optimizer/cse.test.ts +195 -0
  471. package/src/__tests__/optimizer/inline_fn.test.ts +263 -0
  472. package/src/__tests__/optimizer/licm.test.ts +358 -0
  473. package/src/__tests__/optimizer/nbt-coalesce.test.ts +147 -0
  474. package/src/__tests__/optimizer/optimizer-extended.test.ts +1081 -0
  475. package/src/__tests__/optimizer/scoreboard-batch.test.ts +141 -0
  476. package/src/__tests__/optimizer/strength-reduction.test.ts +111 -0
  477. package/src/__tests__/optimizer/tco-coverage.test.ts +309 -0
  478. package/src/__tests__/optimizer/tco.test.ts +238 -0
  479. package/src/__tests__/option.test.ts +14 -7
  480. package/src/__tests__/parser-coverage.test.ts +576 -0
  481. package/src/__tests__/parser-extra.test.ts +531 -0
  482. package/src/__tests__/parser.test.ts +14 -0
  483. package/src/__tests__/repl-extra.test.ts +195 -0
  484. package/src/__tests__/repl-server-extra.test.ts +150 -0
  485. package/src/__tests__/repl-server.test.ts +122 -0
  486. package/src/__tests__/runtime-extra.test.ts +862 -0
  487. package/src/__tests__/singleton-decorator.test.ts +285 -0
  488. package/src/__tests__/sourcemap.test.ts +1 -1
  489. package/src/__tests__/stdlib/advanced.test.ts +312 -0
  490. package/src/__tests__/stdlib/bigint.test.ts +57 -0
  491. package/src/__tests__/stdlib/bits.test.ts +75 -0
  492. package/src/__tests__/stdlib/bossbar.test.ts +45 -0
  493. package/src/__tests__/stdlib/color.test.ts +60 -0
  494. package/src/__tests__/stdlib/combat.test.ts +35 -0
  495. package/src/__tests__/stdlib/cooldown.test.ts +35 -0
  496. package/src/__tests__/stdlib/dialog.test.ts +14 -6
  497. package/src/__tests__/stdlib/ecs.test.ts +54 -0
  498. package/src/__tests__/stdlib/effects.test.ts +45 -0
  499. package/src/__tests__/stdlib/events.test.ts +23 -0
  500. package/src/__tests__/stdlib/expr.test.ts +48 -0
  501. package/src/__tests__/stdlib/fft.test.ts +54 -0
  502. package/src/__tests__/stdlib/graph.test.ts +77 -0
  503. package/src/__tests__/stdlib/interactions.test.ts +30 -0
  504. package/src/__tests__/stdlib/inventory.test.ts +40 -0
  505. package/src/__tests__/stdlib/linalg.test.ts +52 -0
  506. package/src/__tests__/stdlib/map.test.ts +55 -0
  507. package/src/__tests__/stdlib/math.test.ts +19 -5
  508. package/src/__tests__/stdlib/math_hp.test.ts +55 -0
  509. package/src/__tests__/stdlib/mobs.test.ts +40 -0
  510. package/src/__tests__/stdlib/noise.test.ts +46 -0
  511. package/src/__tests__/stdlib/ode.test.ts +40 -0
  512. package/src/__tests__/stdlib/parabola.test.ts +51 -0
  513. package/src/__tests__/stdlib/particles.test.ts +40 -0
  514. package/src/__tests__/stdlib/physics.test.ts +50 -0
  515. package/src/__tests__/stdlib/player.test.ts +35 -0
  516. package/src/__tests__/stdlib/quaternion.test.ts +46 -0
  517. package/src/__tests__/stdlib/queue.test.ts +73 -0
  518. package/src/__tests__/stdlib/random.test.ts +50 -0
  519. package/src/__tests__/stdlib/result.test.ts +326 -0
  520. package/src/__tests__/stdlib/scheduler.test.ts +18 -7
  521. package/src/__tests__/stdlib/set_int.test.ts +62 -0
  522. package/src/__tests__/stdlib/sets.test.ts +28 -0
  523. package/src/__tests__/stdlib/signal.test.ts +60 -0
  524. package/src/__tests__/stdlib/spawn.test.ts +40 -0
  525. package/src/__tests__/stdlib/string.test.ts +224 -0
  526. package/src/__tests__/stdlib/strings.test.ts +55 -0
  527. package/src/__tests__/stdlib/tags.test.ts +32 -0
  528. package/src/__tests__/stdlib/teams.test.ts +45 -0
  529. package/src/__tests__/stdlib/timer.test.ts +53 -0
  530. package/src/__tests__/stdlib/vec.test.ts +72 -0
  531. package/src/__tests__/stdlib/world.test.ts +45 -0
  532. package/src/__tests__/struct-display.test.ts +69 -0
  533. package/src/__tests__/test-framework/runner.test.ts +208 -0
  534. package/src/__tests__/tuner/adapters.test.ts +232 -0
  535. package/src/__tests__/tuner/simulator-extra.test.ts +222 -0
  536. package/src/__tests__/tuple.test.ts +11 -4
  537. package/src/__tests__/typechecker-coverage.test.ts +671 -0
  538. package/src/__tests__/typechecker.test.ts +4 -3
  539. package/src/__tests__/watch-decorator.test.ts +59 -0
  540. package/src/ast/types.ts +65 -3
  541. package/src/cache/incremental.ts +128 -99
  542. package/src/cache/index.ts +35 -8
  543. package/src/cli.ts +538 -29
  544. package/src/config/project-config.ts +176 -0
  545. package/src/diagnostics/index.ts +22 -0
  546. package/src/docs.ts +98 -0
  547. package/src/emit/compile.ts +408 -51
  548. package/src/emit/index.ts +366 -18
  549. package/src/emit/modules.ts +19 -3
  550. package/src/emit/sourcemap.ts +64 -43
  551. package/src/formatter/index.ts +35 -8
  552. package/src/hir/deprecated.ts +212 -0
  553. package/src/hir/lower.ts +128 -8
  554. package/src/hir/monomorphize.ts +24 -2
  555. package/src/hir/types.ts +26 -1
  556. package/src/index.ts +23 -3
  557. package/src/lexer/index.ts +45 -6
  558. package/src/lint/index.ts +922 -0
  559. package/src/lir/lower.ts +30 -2
  560. package/src/lir/types.ts +4 -0
  561. package/src/lsp/server.ts +100 -1
  562. package/src/mir/lower.ts +785 -40
  563. package/src/mir/macro.ts +30 -2
  564. package/src/mir/types.ts +13 -0
  565. package/src/mir/verify.ts +10 -2
  566. package/src/optimizer/auto-inline.ts +86 -0
  567. package/src/optimizer/copy_prop.ts +2 -2
  568. package/src/optimizer/coroutine.ts +3 -3
  569. package/src/optimizer/cse.ts +205 -0
  570. package/src/optimizer/dce.ts +2 -2
  571. package/src/optimizer/inline.ts +335 -0
  572. package/src/optimizer/interprocedural.ts +5 -1
  573. package/src/optimizer/licm.ts +454 -0
  574. package/src/optimizer/nbt-coalesce.ts +109 -0
  575. package/src/optimizer/pipeline.ts +16 -2
  576. package/src/optimizer/scoreboard-batch.ts +52 -0
  577. package/src/optimizer/strength_reduction.ts +95 -0
  578. package/src/optimizer/tco.ts +267 -0
  579. package/src/optimizer/unroll.ts +2 -2
  580. package/src/parser/index.ts +426 -53
  581. package/src/repl-server.ts +102 -0
  582. package/src/stdlib/advanced.mcrs +271 -101
  583. package/src/stdlib/bigint.mcrs +97 -11
  584. package/src/stdlib/bits.mcrs +75 -12
  585. package/src/stdlib/bossbar.mcrs +37 -8
  586. package/src/stdlib/calculus.mcrs +82 -26
  587. package/src/stdlib/color.mcrs +98 -16
  588. package/src/stdlib/combat.mcrs +23 -5
  589. package/src/stdlib/cooldown.mcrs +19 -0
  590. package/src/stdlib/dialog.mcrs +45 -7
  591. package/src/stdlib/easing.mcrs +132 -12
  592. package/src/stdlib/ecs.mcrs +142 -25
  593. package/src/stdlib/effects.mcrs +88 -12
  594. package/src/stdlib/events.mcrs +21 -2
  595. package/src/stdlib/expr.mcrs +18 -3
  596. package/src/stdlib/fft.mcrs +66 -56
  597. package/src/stdlib/geometry.mcrs +137 -39
  598. package/src/stdlib/graph.mcrs +73 -0
  599. package/src/stdlib/heap.mcrs +49 -8
  600. package/src/stdlib/i18n/zh.yaml +2891 -0
  601. package/src/stdlib/interactions.mcrs +43 -20
  602. package/src/stdlib/inventory.mcrs +14 -3
  603. package/src/stdlib/linalg.mcrs +185 -30
  604. package/src/stdlib/list.mcrs +168 -18
  605. package/src/stdlib/map.mcrs +112 -0
  606. package/src/stdlib/math.mcrs +68 -18
  607. package/src/stdlib/math_hp.mcrs +124 -33
  608. package/src/stdlib/matrix.mcrs +133 -20
  609. package/src/stdlib/mobs.mcrs +87 -0
  610. package/src/stdlib/noise.mcrs +65 -21
  611. package/src/stdlib/ode.mcrs +96 -0
  612. package/src/stdlib/parabola.mcrs +104 -29
  613. package/src/stdlib/particles.mcrs +78 -21
  614. package/src/stdlib/pathfind.mcrs +89 -35
  615. package/src/stdlib/physics.mcrs +134 -26
  616. package/src/stdlib/player.mcrs +18 -0
  617. package/src/stdlib/quaternion.mcrs +213 -9
  618. package/src/stdlib/queue.mcrs +123 -0
  619. package/src/stdlib/random.mcrs +63 -18
  620. package/src/stdlib/result.mcrs +111 -0
  621. package/src/stdlib/scheduler.mcrs +59 -10
  622. package/src/stdlib/set_int.mcrs +240 -0
  623. package/src/stdlib/sets.mcrs +49 -19
  624. package/src/stdlib/signal.mcrs +151 -79
  625. package/src/stdlib/sort.mcrs +44 -24
  626. package/src/stdlib/spawn.mcrs +30 -7
  627. package/src/stdlib/state.mcrs +40 -5
  628. package/src/stdlib/strings.mcrs +131 -3
  629. package/src/stdlib/tags.mcrs +2 -2
  630. package/src/stdlib/teams.mcrs +22 -10
  631. package/src/stdlib/timer.mcrs +36 -6
  632. package/src/stdlib/vec.mcrs +44 -9
  633. package/src/stdlib/world.mcrs +57 -25
  634. package/src/structs/expand.ts +64 -0
  635. package/src/testing/runner.ts +271 -0
  636. package/src/typechecker/index.ts +273 -9
@@ -71,6 +71,8 @@ class Parser {
71
71
  this.inLibraryMode = false;
72
72
  /** Warnings accumulated during parsing (e.g. deprecated keyword usage). */
73
73
  this.warnings = [];
74
+ /** Parse errors collected during error-recovery mode. */
75
+ this.parseErrors = [];
74
76
  this.tokens = tokens;
75
77
  this.sourceLines = source?.split('\n') ?? [];
76
78
  this.filePath = filePath;
@@ -132,6 +134,51 @@ class Parser {
132
134
  return { kind: 'eof', value: '', line: span.line, col: span.col };
133
135
  }
134
136
  // -------------------------------------------------------------------------
137
+ // Error Recovery
138
+ // -------------------------------------------------------------------------
139
+ /**
140
+ * Synchronize to the next top-level declaration boundary after a parse error.
141
+ * Skips tokens until we find a keyword that starts a top-level declaration,
142
+ * or a `}` (end of a block), or EOF.
143
+ */
144
+ syncToNextDecl() {
145
+ const TOP_LEVEL_KEYWORDS = new Set([
146
+ 'fn', 'struct', 'impl', 'enum', 'const', 'let', 'export', 'declare', 'import', 'namespace', 'module'
147
+ ]);
148
+ while (!this.check('eof')) {
149
+ const kind = this.peek().kind;
150
+ if (kind === '}') {
151
+ this.advance(); // consume the stray `}`
152
+ return;
153
+ }
154
+ if (TOP_LEVEL_KEYWORDS.has(kind)) {
155
+ return;
156
+ }
157
+ // Also recover on a plain ident that could be 'import' keyword used as ident
158
+ if (kind === 'ident' && this.peek().value === 'import') {
159
+ return;
160
+ }
161
+ this.advance();
162
+ }
163
+ }
164
+ /**
165
+ * Synchronize to the next statement boundary inside a block after a parse error.
166
+ * Skips tokens until we reach `;`, `}`, or EOF.
167
+ */
168
+ syncToNextStmt() {
169
+ while (!this.check('eof')) {
170
+ const kind = this.peek().kind;
171
+ if (kind === ';') {
172
+ this.advance(); // consume the `;`
173
+ return;
174
+ }
175
+ if (kind === '}') {
176
+ return; // leave `}` for parseBlock to consume
177
+ }
178
+ this.advance();
179
+ }
180
+ }
181
+ // -------------------------------------------------------------------------
135
182
  // Program
136
183
  // -------------------------------------------------------------------------
137
184
  parse(defaultNamespace = 'redscript') {
@@ -143,6 +190,7 @@ class Parser {
143
190
  const enums = [];
144
191
  const consts = [];
145
192
  const imports = [];
193
+ const interfaces = [];
146
194
  let isLibrary = false;
147
195
  let moduleName;
148
196
  // Check for namespace declaration
@@ -171,51 +219,95 @@ class Parser {
171
219
  }
172
220
  // Parse struct, function, and import declarations
173
221
  while (!this.check('eof')) {
174
- if (this.check('let')) {
175
- globals.push(this.parseGlobalDecl(true));
176
- }
177
- else if (this.check('struct')) {
178
- structs.push(this.parseStructDecl());
179
- }
180
- else if (this.check('impl')) {
181
- implBlocks.push(this.parseImplBlock());
182
- }
183
- else if (this.check('enum')) {
184
- enums.push(this.parseEnumDecl());
185
- }
186
- else if (this.check('const')) {
187
- consts.push(this.parseConstDecl());
188
- }
189
- else if (this.check('declare')) {
190
- // Declaration-only stub (e.g. from builtins.d.mcrs) parse and discard
191
- this.advance(); // consume 'declare'
192
- this.parseDeclareStub();
193
- }
194
- else if (this.check('export')) {
195
- declarations.push(this.parseExportedFnDecl());
196
- }
197
- else if (this.check('ident') && this.peek().value === 'import') {
198
- // `import math::sin;` or `import math::*;`
199
- this.advance(); // consume 'import'
200
- const importToken = this.peek();
201
- const modName = this.expect('ident').value;
202
- this.expect('::');
203
- let symbol;
204
- if (this.check('*')) {
205
- this.advance();
206
- symbol = '*';
222
+ try {
223
+ if (this.check('decorator') && this.peek().value.startsWith('@config')) {
224
+ // @config decorator on a global let
225
+ const decorToken = this.advance();
226
+ const decorator = this.parseDecoratorValue(decorToken.value);
227
+ if (!this.check('let')) {
228
+ this.error('@config decorator must be followed by a let declaration');
229
+ }
230
+ const g = this.parseGlobalDecl(true);
231
+ g.configKey = decorator.args?.configKey;
232
+ g.configDefault = decorator.args?.configDefault;
233
+ globals.push(g);
234
+ }
235
+ else if (this.check('let')) {
236
+ globals.push(this.parseGlobalDecl(true));
237
+ }
238
+ else if (this.check('decorator') && this.peek().value === '@singleton') {
239
+ // @singleton decorator on a struct
240
+ this.advance(); // consume '@singleton'
241
+ if (!this.check('struct')) {
242
+ this.error('@singleton decorator must be followed by a struct declaration');
243
+ }
244
+ const s = this.parseStructDecl();
245
+ s.isSingleton = true;
246
+ structs.push(s);
247
+ }
248
+ else if (this.check('struct')) {
249
+ structs.push(this.parseStructDecl());
250
+ }
251
+ else if (this.check('impl')) {
252
+ implBlocks.push(this.parseImplBlock());
253
+ }
254
+ else if (this.check('interface')) {
255
+ interfaces.push(this.parseInterfaceDecl());
256
+ }
257
+ else if (this.check('enum')) {
258
+ enums.push(this.parseEnumDecl());
259
+ }
260
+ else if (this.check('const')) {
261
+ consts.push(this.parseConstDecl());
262
+ }
263
+ else if (this.check('declare')) {
264
+ // Declaration-only stub (e.g. from builtins.d.mcrs) — parse and discard
265
+ this.advance(); // consume 'declare'
266
+ this.parseDeclareStub();
267
+ }
268
+ else if (this.check('export')) {
269
+ declarations.push(this.parseExportedFnDecl());
270
+ }
271
+ else if (this.check('import') || (this.check('ident') && this.peek().value === 'import')) {
272
+ // `import math::sin;` or `import math::*;` or `import player_utils;` (whole-module file import)
273
+ this.advance(); // consume 'import' (keyword or ident)
274
+ const importToken = this.peek();
275
+ const modName = this.expect('ident').value;
276
+ // Check for `::` — if present, this is a symbol import; otherwise, whole-module import
277
+ if (this.check('::')) {
278
+ this.advance(); // consume '::'
279
+ let symbol;
280
+ if (this.check('*')) {
281
+ this.advance();
282
+ symbol = '*';
283
+ }
284
+ else {
285
+ symbol = this.expect('ident').value;
286
+ }
287
+ this.match(';');
288
+ imports.push(this.withLoc({ moduleName: modName, symbol }, importToken));
289
+ }
290
+ else {
291
+ // Whole-module import: `import player_utils;`
292
+ this.match(';');
293
+ imports.push(this.withLoc({ moduleName: modName, symbol: undefined }, importToken));
294
+ }
207
295
  }
208
296
  else {
209
- symbol = this.expect('ident').value;
297
+ declarations.push(this.parseFnDecl());
210
298
  }
211
- this.match(';');
212
- imports.push(this.withLoc({ moduleName: modName, symbol }, importToken));
213
299
  }
214
- else {
215
- declarations.push(this.parseFnDecl());
300
+ catch (err) {
301
+ if (err instanceof diagnostics_1.DiagnosticError) {
302
+ this.parseErrors.push(err);
303
+ this.syncToNextDecl();
304
+ }
305
+ else {
306
+ throw err;
307
+ }
216
308
  }
217
309
  }
218
- return { namespace, moduleName, globals, declarations, structs, implBlocks, enums, consts, imports, isLibrary };
310
+ return { namespace, moduleName, globals, declarations, structs, implBlocks, enums, consts, imports, interfaces, isLibrary };
219
311
  }
220
312
  // -------------------------------------------------------------------------
221
313
  // Struct Declaration
@@ -223,6 +315,7 @@ class Parser {
223
315
  parseStructDecl() {
224
316
  const structToken = this.expect('struct');
225
317
  const name = this.expect('ident').value;
318
+ const extendsName = this.match('extends') ? this.expect('ident').value : undefined;
226
319
  this.expect('{');
227
320
  const fields = [];
228
321
  while (!this.check('}') && !this.check('eof')) {
@@ -234,7 +327,7 @@ class Parser {
234
327
  this.match(',');
235
328
  }
236
329
  this.expect('}');
237
- return this.withLoc({ name, fields }, structToken);
330
+ return this.withLoc({ name, extends: extendsName, fields }, structToken);
238
331
  }
239
332
  parseEnumDecl() {
240
333
  const enumToken = this.expect('enum');
@@ -245,6 +338,21 @@ class Parser {
245
338
  while (!this.check('}') && !this.check('eof')) {
246
339
  const variantToken = this.expect('ident');
247
340
  const variant = { name: variantToken.value };
341
+ // Payload fields: Variant(field: Type, ...)
342
+ if (this.check('(')) {
343
+ this.advance(); // consume '('
344
+ const fields = [];
345
+ while (!this.check(')') && !this.check('eof')) {
346
+ const fieldName = this.expect('ident').value;
347
+ this.expect(':');
348
+ const fieldType = this.parseType();
349
+ fields.push({ name: fieldName, type: fieldType });
350
+ if (!this.match(','))
351
+ break;
352
+ }
353
+ this.expect(')');
354
+ variant.fields = fields;
355
+ }
248
356
  if (this.match('=')) {
249
357
  const valueToken = this.expect('int_lit');
250
358
  variant.value = parseInt(valueToken.value, 10);
@@ -263,14 +371,76 @@ class Parser {
263
371
  }
264
372
  parseImplBlock() {
265
373
  const implToken = this.expect('impl');
266
- const typeName = this.expect('ident').value;
374
+ let traitName;
375
+ let typeName;
376
+ const firstName = this.expect('ident').value;
377
+ if (this.match('for')) {
378
+ traitName = firstName;
379
+ typeName = this.expect('ident').value;
380
+ }
381
+ else {
382
+ typeName = firstName;
383
+ }
267
384
  this.expect('{');
268
385
  const methods = [];
269
386
  while (!this.check('}') && !this.check('eof')) {
270
387
  methods.push(this.parseFnDecl(typeName));
271
388
  }
272
389
  this.expect('}');
273
- return this.withLoc({ kind: 'impl_block', typeName, methods }, implToken);
390
+ return this.withLoc({ kind: 'impl_block', traitName, typeName, methods }, implToken);
391
+ }
392
+ /**
393
+ * Parse an interface declaration:
394
+ * interface <Name> {
395
+ * fn <method>(<params>): <retType>
396
+ * ...
397
+ * }
398
+ * Method signatures have no body — they are prototype-only.
399
+ */
400
+ parseInterfaceDecl() {
401
+ const ifaceToken = this.expect('interface');
402
+ const name = this.expect('ident').value;
403
+ this.expect('{');
404
+ const methods = [];
405
+ while (!this.check('}') && !this.check('eof')) {
406
+ const fnToken = this.expect('fn');
407
+ const methodName = this.expect('ident').value;
408
+ this.expect('(');
409
+ const params = this.parseInterfaceParams();
410
+ this.expect(')');
411
+ let returnType;
412
+ if (this.match(':')) {
413
+ returnType = this.parseType();
414
+ }
415
+ // No body — interface methods are signature-only
416
+ methods.push(this.withLoc({ name: methodName, params, returnType }, fnToken));
417
+ }
418
+ this.expect('}');
419
+ return this.withLoc({ name, methods }, ifaceToken);
420
+ }
421
+ /**
422
+ * Parse interface method params — like parseParams but allows bare `self`
423
+ * (no `:` required for the first param named 'self').
424
+ */
425
+ parseInterfaceParams() {
426
+ const params = [];
427
+ if (!this.check(')')) {
428
+ do {
429
+ const paramToken = this.expect('ident');
430
+ const paramName = paramToken.value;
431
+ let type;
432
+ if (params.length === 0 && paramName === 'self' && !this.check(':')) {
433
+ // self without type annotation — use a sentinel struct type
434
+ type = { kind: 'named', name: 'void' };
435
+ }
436
+ else {
437
+ this.expect(':');
438
+ type = this.parseType();
439
+ }
440
+ params.push(this.withLoc({ name: paramName, type }, paramToken));
441
+ } while (this.match(','));
442
+ }
443
+ return params;
274
444
  }
275
445
  parseConstDecl() {
276
446
  const constToken = this.expect('const');
@@ -294,8 +464,15 @@ class Parser {
294
464
  const name = this.expect('ident').value;
295
465
  this.expect(':');
296
466
  const type = this.parseType();
297
- this.expect('=');
298
- const init = this.parseExpr();
467
+ let init;
468
+ if (this.match('=')) {
469
+ init = this.parseExpr();
470
+ }
471
+ else {
472
+ // No init — valid only for @config-decorated globals (resolved later)
473
+ // Use a placeholder zero literal; will be replaced in compile step
474
+ init = { kind: 'int_lit', value: 0 };
475
+ }
299
476
  this.match(';');
300
477
  return this.withLoc({ kind: 'global', name, type, init, mutable }, token);
301
478
  }
@@ -311,6 +488,7 @@ class Parser {
311
488
  }
312
489
  parseFnDecl(implTypeName) {
313
490
  const decorators = this.parseDecorators();
491
+ const watchObjective = decorators.find(decorator => decorator.name === 'watch')?.args?.objective;
314
492
  // Map @keep decorator to isExported flag (backward compat)
315
493
  let isExported;
316
494
  const filteredDecorators = decorators.filter(d => {
@@ -343,7 +521,7 @@ class Parser {
343
521
  // Record the closing '}' line as endLine for accurate LSP scope detection
344
522
  const closingBraceLine = this.tokens[this.pos - 1]?.line;
345
523
  const fn = this.withLoc({ name, typeParams, params, returnType, decorators: filteredDecorators, body,
346
- isLibraryFn: this.inLibraryMode || undefined, isExported }, fnToken);
524
+ isLibraryFn: this.inLibraryMode || undefined, isExported, watchObjective }, fnToken);
347
525
  if (fn.span && closingBraceLine)
348
526
  fn.span.endLine = closingBraceLine;
349
527
  return fn;
@@ -378,8 +556,9 @@ class Parser {
378
556
  return decorators;
379
557
  }
380
558
  parseDecoratorValue(value) {
381
- // Parse @tick, @on(PlayerDeath), or @on_trigger("name")
382
- const match = value.match(/^@(\w+)(?:\(([^)]*)\))?$/);
559
+ // Parse @tick, @on(PlayerDeath), @on_trigger("name"), or @deprecated("msg with ) parens")
560
+ // Use a greedy match for args that allows any content inside the outermost parens.
561
+ const match = value.match(/^@([A-Za-z_][A-Za-z0-9_-]*)(?:\((.*)\))?$/s);
383
562
  if (!match) {
384
563
  this.error(`Invalid decorator: ${value}`);
385
564
  }
@@ -388,6 +567,9 @@ class Parser {
388
567
  if (!argsStr) {
389
568
  return { name };
390
569
  }
570
+ if (name === 'profile' || name === 'memoize') {
571
+ this.error(`@${name} decorator does not accept arguments`);
572
+ }
391
573
  const args = {};
392
574
  if (name === 'on') {
393
575
  const eventTypeMatch = argsStr.match(/^([A-Za-z_][A-Za-z0-9_]*)$/);
@@ -396,11 +578,14 @@ class Parser {
396
578
  return { name, args };
397
579
  }
398
580
  }
399
- // Handle @on_trigger("name"), @on_advancement("id"), @on_craft("item"), @on_join_team("team")
400
- if (name === 'on_trigger' || name === 'on_advancement' || name === 'on_craft' || name === 'on_join_team') {
581
+ // Handle @watch("objective"), @on_trigger("name"), @on_advancement("id"), @on_craft("item"), @on_join_team("team")
582
+ if (name === 'watch' || name === 'on_trigger' || name === 'on_advancement' || name === 'on_craft' || name === 'on_join_team') {
401
583
  const strMatch = argsStr.match(/^"([^"]*)"$/);
402
584
  if (strMatch) {
403
- if (name === 'on_trigger') {
585
+ if (name === 'watch') {
586
+ args.objective = strMatch[1];
587
+ }
588
+ else if (name === 'on_trigger') {
404
589
  args.trigger = strMatch[1];
405
590
  }
406
591
  else if (name === 'on_advancement') {
@@ -415,6 +600,38 @@ class Parser {
415
600
  return { name, args };
416
601
  }
417
602
  }
603
+ // Handle @config("key", default: value)
604
+ if (name === 'config') {
605
+ // Format: @config("key_name", default: 42)
606
+ const configMatch = argsStr.match(/^"([^"]+)"\s*,\s*default\s*:\s*(-?\d+(?:\.\d+)?)$/);
607
+ if (configMatch) {
608
+ return { name, args: { configKey: configMatch[1], configDefault: parseFloat(configMatch[2]) } };
609
+ }
610
+ // Format: @config("key_name") — no default
611
+ const keyOnlyMatch = argsStr.match(/^"([^"]+)"$/);
612
+ if (keyOnlyMatch) {
613
+ return { name, args: { configKey: keyOnlyMatch[1] } };
614
+ }
615
+ this.error(`Invalid @config syntax. Expected: @config("key", default: value) or @config("key")`);
616
+ }
617
+ // Handle @deprecated("message")
618
+ if (name === 'deprecated') {
619
+ const strMatch = argsStr.match(/^"([^"]*)"$/);
620
+ if (strMatch) {
621
+ return { name, args: { message: strMatch[1] } };
622
+ }
623
+ // @deprecated with no message string
624
+ return { name, args: {} };
625
+ }
626
+ // @test("label") — marks a test function with a human-readable label
627
+ if (name === 'test') {
628
+ const strMatch = argsStr.match(/^"([^"]*)"$/);
629
+ if (strMatch) {
630
+ return { name, args: { testLabel: strMatch[1] } };
631
+ }
632
+ // @test with no label — use empty string
633
+ return { name, args: { testLabel: '' } };
634
+ }
418
635
  // @require_on_load(fn_name) — when this fn is used, fn_name is called from __load.
419
636
  // Accepts bare identifiers (with optional leading _) or quoted strings.
420
637
  if (name === 'require_on_load') {
@@ -463,6 +680,9 @@ class Parser {
463
680
  else if (key === 'team') {
464
681
  args.team = val;
465
682
  }
683
+ else if (key === 'max') {
684
+ args.max = parseInt(val, 10);
685
+ }
466
686
  }
467
687
  return { name, args };
468
688
  }
@@ -579,7 +799,18 @@ class Parser {
579
799
  this.expect('{');
580
800
  const stmts = [];
581
801
  while (!this.check('}') && !this.check('eof')) {
582
- stmts.push(this.parseStmt());
802
+ try {
803
+ stmts.push(this.parseStmt());
804
+ }
805
+ catch (err) {
806
+ if (err instanceof diagnostics_1.DiagnosticError) {
807
+ this.parseErrors.push(err);
808
+ this.syncToNextStmt();
809
+ }
810
+ else {
811
+ throw err;
812
+ }
813
+ }
583
814
  }
584
815
  this.expect('}');
585
816
  return stmts;
@@ -589,19 +820,35 @@ class Parser {
589
820
  if (this.check('let')) {
590
821
  return this.parseLetStmt();
591
822
  }
823
+ // Const declaration (local)
824
+ if (this.check('const')) {
825
+ return this.parseLocalConstDecl();
826
+ }
592
827
  // Return statement
593
828
  if (this.check('return')) {
594
829
  return this.parseReturnStmt();
595
830
  }
596
- // Break statement
831
+ // Break statement (with optional label: break outer)
597
832
  if (this.check('break')) {
598
833
  const token = this.advance();
834
+ // Check if next token is an identifier (label name)
835
+ if (this.check('ident')) {
836
+ const labelToken = this.advance();
837
+ this.match(';');
838
+ return this.withLoc({ kind: 'break_label', label: labelToken.value }, token);
839
+ }
599
840
  this.match(';');
600
841
  return this.withLoc({ kind: 'break' }, token);
601
842
  }
602
- // Continue statement
843
+ // Continue statement (with optional label: continue outer)
603
844
  if (this.check('continue')) {
604
845
  const token = this.advance();
846
+ // Check if next token is an identifier (label name)
847
+ if (this.check('ident')) {
848
+ const labelToken = this.advance();
849
+ this.match(';');
850
+ return this.withLoc({ kind: 'continue_label', label: labelToken.value }, token);
851
+ }
605
852
  this.match(';');
606
853
  return this.withLoc({ kind: 'continue' }, token);
607
854
  }
@@ -609,10 +856,41 @@ class Parser {
609
856
  if (this.check('if')) {
610
857
  return this.parseIfStmt();
611
858
  }
859
+ // Labeled loop: ident ':' (while|for|foreach|repeat)
860
+ if (this.check('ident') && this.peek(1).kind === ':') {
861
+ const labelToken = this.advance(); // consume ident
862
+ const colonToken = this.advance(); // consume ':'
863
+ // Now parse the loop body
864
+ let loopStmt;
865
+ if (this.check('while')) {
866
+ loopStmt = this.parseWhileStmt();
867
+ }
868
+ else if (this.check('for')) {
869
+ loopStmt = this.parseForStmt();
870
+ }
871
+ else if (this.check('foreach')) {
872
+ loopStmt = this.parseForeachStmt();
873
+ }
874
+ else if (this.check('repeat')) {
875
+ loopStmt = this.parseRepeatStmt();
876
+ }
877
+ else {
878
+ throw new diagnostics_1.DiagnosticError('ParseError', `Expected loop statement after label '${labelToken.value}:', found '${this.peek().kind}'`, { line: labelToken.line, col: labelToken.col });
879
+ }
880
+ return this.withLoc({ kind: 'labeled_loop', label: labelToken.value, body: loopStmt }, labelToken);
881
+ }
612
882
  // While statement
613
883
  if (this.check('while')) {
614
884
  return this.parseWhileStmt();
615
885
  }
886
+ // Do-while statement
887
+ if (this.check('do')) {
888
+ return this.parseDoWhileStmt();
889
+ }
890
+ // Repeat N statement
891
+ if (this.check('repeat')) {
892
+ return this.parseRepeatStmt();
893
+ }
616
894
  // For statement
617
895
  if (this.check('for')) {
618
896
  return this.parseForStmt();
@@ -675,6 +953,16 @@ class Parser {
675
953
  this.match(';');
676
954
  return this.withLoc({ kind: 'let', name, type, init }, letToken);
677
955
  }
956
+ parseLocalConstDecl() {
957
+ const constToken = this.expect('const');
958
+ const name = this.expect('ident').value;
959
+ this.expect(':');
960
+ const type = this.parseType();
961
+ this.expect('=');
962
+ const value = this.parseExpr();
963
+ this.match(';');
964
+ return this.withLoc({ kind: 'const_decl', name, type, value }, constToken);
965
+ }
678
966
  parseReturnStmt() {
679
967
  const returnToken = this.expect('return');
680
968
  let value;
@@ -707,9 +995,7 @@ class Parser {
707
995
  }
708
996
  return this.withLoc({ kind: 'if_let_some', binding, init, then, else_ }, ifToken);
709
997
  }
710
- this.expect('(');
711
- const cond = this.parseExpr();
712
- this.expect(')');
998
+ const cond = this.parseParenOptionalCond();
713
999
  const then = this.parseBlock();
714
1000
  let else_;
715
1001
  if (this.match('else')) {
@@ -725,12 +1011,45 @@ class Parser {
725
1011
  }
726
1012
  parseWhileStmt() {
727
1013
  const whileToken = this.expect('while');
728
- this.expect('(');
729
- const cond = this.parseExpr();
730
- this.expect(')');
1014
+ // while let Some(x) = expr { ... }
1015
+ if (this.check('let') && this.peek(1).kind === 'ident' && this.peek(1).value === 'Some') {
1016
+ this.advance(); // consume 'let'
1017
+ this.advance(); // consume 'Some'
1018
+ this.expect('(');
1019
+ const binding = this.expect('ident').value;
1020
+ this.expect(')');
1021
+ this.expect('=');
1022
+ const init = this.parseExpr();
1023
+ const body = this.parseBlock();
1024
+ return this.withLoc({ kind: 'while_let_some', binding, init, body }, whileToken);
1025
+ }
1026
+ const cond = this.parseParenOptionalCond();
731
1027
  const body = this.parseBlock();
732
1028
  return this.withLoc({ kind: 'while', cond, body }, whileToken);
733
1029
  }
1030
+ parseDoWhileStmt() {
1031
+ const doToken = this.expect('do');
1032
+ const body = this.parseBlock();
1033
+ this.expect('while');
1034
+ const cond = this.parseParenOptionalCond();
1035
+ this.match(';');
1036
+ return this.withLoc({ kind: 'do_while', cond, body }, doToken);
1037
+ }
1038
+ parseRepeatStmt() {
1039
+ const repeatToken = this.expect('repeat');
1040
+ const countToken = this.expect('int_lit');
1041
+ const count = parseInt(countToken.value, 10);
1042
+ const body = this.parseBlock();
1043
+ return this.withLoc({ kind: 'repeat', count, body }, repeatToken);
1044
+ }
1045
+ parseParenOptionalCond() {
1046
+ if (this.match('(')) {
1047
+ const cond = this.parseExpr();
1048
+ this.expect(')');
1049
+ return cond;
1050
+ }
1051
+ return this.parseExpr();
1052
+ }
734
1053
  parseForStmt() {
735
1054
  const forToken = this.expect('for');
736
1055
  // Check for for-range syntax: for <ident> in <range_lit> { ... }
@@ -873,6 +1192,23 @@ class Parser {
873
1192
  this.expect(')');
874
1193
  return { kind: 'PatSome', binding };
875
1194
  }
1195
+ // Enum pattern: EnumName::Variant or EnumName::Variant(b1, b2, ...)
1196
+ if (this.check('ident') && this.peek(1).kind === '::') {
1197
+ const enumName = this.advance().value;
1198
+ this.expect('::');
1199
+ const variant = this.expect('ident').value;
1200
+ const bindings = [];
1201
+ if (this.check('(')) {
1202
+ this.advance(); // consume '('
1203
+ while (!this.check(')') && !this.check('eof')) {
1204
+ bindings.push(this.expect('ident').value);
1205
+ if (!this.match(','))
1206
+ break;
1207
+ }
1208
+ this.expect(')');
1209
+ }
1210
+ return { kind: 'PatEnum', enumName, variant, bindings };
1211
+ }
876
1212
  // Integer literal
877
1213
  if (this.check('int_lit')) {
878
1214
  const tok = this.advance();
@@ -1250,6 +1586,13 @@ class Parser {
1250
1586
  // Member call: entity.tag("name") → __entity_tag(entity, "name")
1251
1587
  // Also handle arr.push(val) and arr.length
1252
1588
  if (expr.kind === 'member') {
1589
+ // Option.unwrap_or(default) → unwrap_or AST node
1590
+ if (expr.field === 'unwrap_or') {
1591
+ const defaultExpr = this.parseExpr();
1592
+ this.expect(')');
1593
+ expr = this.withLoc({ kind: 'unwrap_or', opt: expr.obj, default_: defaultExpr }, this.getLocToken(expr) ?? openParenToken);
1594
+ continue;
1595
+ }
1253
1596
  const methodMap = {
1254
1597
  'tag': '__entity_tag',
1255
1598
  'untag': '__entity_untag',
@@ -1334,6 +1677,25 @@ class Parser {
1334
1677
  this.expect('::');
1335
1678
  const memberToken = this.expect('ident');
1336
1679
  if (this.check('(')) {
1680
+ // Peek inside: if first non-'(' token is `ident :` it's enum construction with named args.
1681
+ // We only treat it as enum_construct when there are actual named args (not empty parens),
1682
+ // because empty `()` is ambiguous and most commonly means a static method call.
1683
+ const isNamedArgs = this.peek(1).kind === 'ident' && this.peek(2).kind === ':';
1684
+ if (isNamedArgs) {
1685
+ // Enum variant construction: EnumName::Variant(field: expr, ...)
1686
+ this.advance(); // consume '('
1687
+ const args = [];
1688
+ while (!this.check(')') && !this.check('eof')) {
1689
+ const fieldName = this.expect('ident').value;
1690
+ this.expect(':');
1691
+ const value = this.parseExpr();
1692
+ args.push({ name: fieldName, value });
1693
+ if (!this.match(','))
1694
+ break;
1695
+ }
1696
+ this.expect(')');
1697
+ return this.withLoc({ kind: 'enum_construct', enumName: typeToken.value, variant: memberToken.value, args }, typeToken);
1698
+ }
1337
1699
  // Static method call: Type::method(args)
1338
1700
  this.advance(); // consume '('
1339
1701
  const args = this.parseArgs();