@soundscript/soundscript 0.1.12 → 0.1.15

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 (441) hide show
  1. package/package.json +15 -6
  2. package/project-transform/index.js +2 -0
  3. package/project-transform/index.ts +8 -0
  4. package/project-transform/src/annotation_syntax.js +948 -0
  5. package/project-transform/src/annotation_syntax.ts +1217 -0
  6. package/project-transform/src/build_package.js +475 -0
  7. package/project-transform/src/build_package.ts +683 -0
  8. package/project-transform/src/bundled/portable-web-globals.d.ts +153 -0
  9. package/project-transform/src/bundled/runtime_externs.js +220 -0
  10. package/project-transform/src/bundled/runtime_externs.ts +237 -0
  11. package/project-transform/src/bundled/sound-libs/lib.decorators.d.ts +385 -0
  12. package/project-transform/src/bundled/sound-libs/lib.decorators.legacy.d.ts +22 -0
  13. package/project-transform/src/bundled/sound-libs/lib.dom.asynciterable.d.ts +42 -0
  14. package/project-transform/src/bundled/sound-libs/lib.dom.d.ts +39440 -0
  15. package/project-transform/src/bundled/sound-libs/lib.es2015.collection.d.ts +149 -0
  16. package/project-transform/src/bundled/sound-libs/lib.es2015.core.d.ts +657 -0
  17. package/project-transform/src/bundled/sound-libs/lib.es2015.d.ts +28 -0
  18. package/project-transform/src/bundled/sound-libs/lib.es2015.generator.d.ts +77 -0
  19. package/project-transform/src/bundled/sound-libs/lib.es2015.iterable.d.ts +616 -0
  20. package/project-transform/src/bundled/sound-libs/lib.es2015.promise.d.ts +80 -0
  21. package/project-transform/src/bundled/sound-libs/lib.es2015.proxy.d.ts +128 -0
  22. package/project-transform/src/bundled/sound-libs/lib.es2015.reflect.d.ts +144 -0
  23. package/project-transform/src/bundled/sound-libs/lib.es2015.symbol.d.ts +46 -0
  24. package/project-transform/src/bundled/sound-libs/lib.es2015.symbol.wellknown.d.ts +170 -0
  25. package/project-transform/src/bundled/sound-libs/lib.es2016.array.include.d.ts +116 -0
  26. package/project-transform/src/bundled/sound-libs/lib.es2016.d.ts +21 -0
  27. package/project-transform/src/bundled/sound-libs/lib.es2017.arraybuffer.d.ts +21 -0
  28. package/project-transform/src/bundled/sound-libs/lib.es2017.d.ts +26 -0
  29. package/project-transform/src/bundled/sound-libs/lib.es2017.date.d.ts +31 -0
  30. package/project-transform/src/bundled/sound-libs/lib.es2017.object.d.ts +49 -0
  31. package/project-transform/src/bundled/sound-libs/lib.es2017.string.d.ts +45 -0
  32. package/project-transform/src/bundled/sound-libs/lib.es2017.typedarrays.d.ts +53 -0
  33. package/project-transform/src/bundled/sound-libs/lib.es2018.asyncgenerator.d.ts +77 -0
  34. package/project-transform/src/bundled/sound-libs/lib.es2018.asynciterable.d.ts +57 -0
  35. package/project-transform/src/bundled/sound-libs/lib.es2018.d.ts +24 -0
  36. package/project-transform/src/bundled/sound-libs/lib.es2018.promise.d.ts +30 -0
  37. package/project-transform/src/bundled/sound-libs/lib.es2018.regexp.d.ts +37 -0
  38. package/project-transform/src/bundled/sound-libs/lib.es2019.array.d.ts +79 -0
  39. package/project-transform/src/bundled/sound-libs/lib.es2019.d.ts +24 -0
  40. package/project-transform/src/bundled/sound-libs/lib.es2019.object.d.ts +47 -0
  41. package/project-transform/src/bundled/sound-libs/lib.es2019.string.d.ts +37 -0
  42. package/project-transform/src/bundled/sound-libs/lib.es2019.symbol.d.ts +24 -0
  43. package/project-transform/src/bundled/sound-libs/lib.es2020.bigint.d.ts +765 -0
  44. package/project-transform/src/bundled/sound-libs/lib.es2020.d.ts +27 -0
  45. package/project-transform/src/bundled/sound-libs/lib.es2020.date.d.ts +42 -0
  46. package/project-transform/src/bundled/sound-libs/lib.es2020.number.d.ts +28 -0
  47. package/project-transform/src/bundled/sound-libs/lib.es2020.promise.d.ts +49 -0
  48. package/project-transform/src/bundled/sound-libs/lib.es2020.string.d.ts +44 -0
  49. package/project-transform/src/bundled/sound-libs/lib.es2020.symbol.wellknown.d.ts +41 -0
  50. package/project-transform/src/bundled/sound-libs/lib.es2021.d.ts +23 -0
  51. package/project-transform/src/bundled/sound-libs/lib.es2021.promise.d.ts +48 -0
  52. package/project-transform/src/bundled/sound-libs/lib.es2021.string.d.ts +33 -0
  53. package/project-transform/src/bundled/sound-libs/lib.es2021.weakref.d.ts +78 -0
  54. package/project-transform/src/bundled/sound-libs/lib.es2022.array.d.ts +121 -0
  55. package/project-transform/src/bundled/sound-libs/lib.es2022.d.ts +25 -0
  56. package/project-transform/src/bundled/sound-libs/lib.es2022.error.d.ts +75 -0
  57. package/project-transform/src/bundled/sound-libs/lib.es2022.object.d.ts +26 -0
  58. package/project-transform/src/bundled/sound-libs/lib.es2022.regexp.d.ts +39 -0
  59. package/project-transform/src/bundled/sound-libs/lib.es2022.string.d.ts +25 -0
  60. package/project-transform/src/bundled/sound-libs/lib.es2023.array.d.ts +924 -0
  61. package/project-transform/src/bundled/sound-libs/lib.es2023.collection.d.ts +21 -0
  62. package/project-transform/src/bundled/sound-libs/lib.es2023.d.ts +22 -0
  63. package/project-transform/src/bundled/sound-libs/lib.es2024.arraybuffer.d.ts +65 -0
  64. package/project-transform/src/bundled/sound-libs/lib.es2024.collection.d.ts +29 -0
  65. package/project-transform/src/bundled/sound-libs/lib.es2024.d.ts +26 -0
  66. package/project-transform/src/bundled/sound-libs/lib.es2024.object.d.ts +33 -0
  67. package/project-transform/src/bundled/sound-libs/lib.es2024.promise.d.ts +35 -0
  68. package/project-transform/src/bundled/sound-libs/lib.es2024.regexp.d.ts +25 -0
  69. package/project-transform/src/bundled/sound-libs/lib.es2024.string.d.ts +29 -0
  70. package/project-transform/src/bundled/sound-libs/lib.es5.d.ts +4924 -0
  71. package/project-transform/src/bundled/sound_stdlib.js +142 -0
  72. package/project-transform/src/bundled/sound_stdlib.ts +180 -0
  73. package/project-transform/src/checker/analyze_project.js +1361 -0
  74. package/project-transform/src/checker/analyze_project.ts +2246 -0
  75. package/project-transform/src/checker/diagnostics.js +112 -0
  76. package/project-transform/src/checker/diagnostics.ts +222 -0
  77. package/project-transform/src/checker/engine/context.js +235 -0
  78. package/project-transform/src/checker/engine/context.ts +340 -0
  79. package/project-transform/src/checker/engine/diagnostic_codes.js +72 -0
  80. package/project-transform/src/checker/engine/diagnostic_codes.ts +95 -0
  81. package/project-transform/src/checker/engine/facts.js +35 -0
  82. package/project-transform/src/checker/engine/facts.ts +48 -0
  83. package/project-transform/src/checker/engine/types.js +1 -0
  84. package/project-transform/src/checker/engine/types.ts +485 -0
  85. package/project-transform/src/checker/proof_escape_hatch_diagnostics.js +104 -0
  86. package/project-transform/src/checker/proof_escape_hatch_diagnostics.ts +173 -0
  87. package/project-transform/src/checker/rules/async_surface.js +231 -0
  88. package/project-transform/src/checker/rules/async_surface.ts +335 -0
  89. package/project-transform/src/checker/rules/class_lifecycle.js +798 -0
  90. package/project-transform/src/checker/rules/class_lifecycle.ts +1276 -0
  91. package/project-transform/src/checker/rules/directive_validation.js +571 -0
  92. package/project-transform/src/checker/rules/directive_validation.ts +938 -0
  93. package/project-transform/src/checker/rules/directives.js +23 -0
  94. package/project-transform/src/checker/rules/directives.ts +25 -0
  95. package/project-transform/src/checker/rules/flow.js +202 -0
  96. package/project-transform/src/checker/rules/flow.ts +333 -0
  97. package/project-transform/src/checker/rules/flow_facts.js +601 -0
  98. package/project-transform/src/checker/rules/flow_facts.ts +978 -0
  99. package/project-transform/src/checker/rules/flow_invalidation.js +1119 -0
  100. package/project-transform/src/checker/rules/flow_invalidation.ts +2150 -0
  101. package/project-transform/src/checker/rules/flow_shared.js +2822 -0
  102. package/project-transform/src/checker/rules/flow_shared.ts +4383 -0
  103. package/project-transform/src/checker/rules/foreign_boundary.js +120 -0
  104. package/project-transform/src/checker/rules/foreign_boundary.ts +196 -0
  105. package/project-transform/src/checker/rules/foreign_projection.js +279 -0
  106. package/project-transform/src/checker/rules/foreign_projection.ts +425 -0
  107. package/project-transform/src/checker/rules/generated_helpers.js +13 -0
  108. package/project-transform/src/checker/rules/generated_helpers.ts +18 -0
  109. package/project-transform/src/checker/rules/index.js +35 -0
  110. package/project-transform/src/checker/rules/index.ts +49 -0
  111. package/project-transform/src/checker/rules/namespace_object.js +845 -0
  112. package/project-transform/src/checker/rules/namespace_object.ts +1224 -0
  113. package/project-transform/src/checker/rules/non_ordinary_recovery.js +1328 -0
  114. package/project-transform/src/checker/rules/non_ordinary_recovery.ts +2391 -0
  115. package/project-transform/src/checker/rules/null_prototype.js +3 -0
  116. package/project-transform/src/checker/rules/null_prototype.ts +6 -0
  117. package/project-transform/src/checker/rules/overloads.js +181 -0
  118. package/project-transform/src/checker/rules/overloads.ts +317 -0
  119. package/project-transform/src/checker/rules/predicate_verification.js +691 -0
  120. package/project-transform/src/checker/rules/predicate_verification.ts +1088 -0
  121. package/project-transform/src/checker/rules/prototype_hardening.js +237 -0
  122. package/project-transform/src/checker/rules/prototype_hardening.ts +343 -0
  123. package/project-transform/src/checker/rules/receiver_discipline.js +263 -0
  124. package/project-transform/src/checker/rules/receiver_discipline.ts +356 -0
  125. package/project-transform/src/checker/rules/relations.js +6861 -0
  126. package/project-transform/src/checker/rules/relations.ts +12158 -0
  127. package/project-transform/src/checker/rules/resolved_builtins.js +274 -0
  128. package/project-transform/src/checker/rules/resolved_builtins.ts +438 -0
  129. package/project-transform/src/checker/rules/trust.js +217 -0
  130. package/project-transform/src/checker/rules/trust.ts +301 -0
  131. package/project-transform/src/checker/rules/type_guards.js +173 -0
  132. package/project-transform/src/checker/rules/type_guards.ts +257 -0
  133. package/project-transform/src/checker/rules/universal.js +17 -0
  134. package/project-transform/src/checker/rules/universal.ts +22 -0
  135. package/project-transform/src/checker/rules/unsafe_value_origin.js +80 -0
  136. package/project-transform/src/checker/rules/unsafe_value_origin.ts +125 -0
  137. package/project-transform/src/checker/rules/unsound_imports.js +218 -0
  138. package/project-transform/src/checker/rules/unsound_imports.ts +301 -0
  139. package/project-transform/src/checker/rules/unsound_syntax.js +1695 -0
  140. package/project-transform/src/checker/rules/unsound_syntax.ts +2540 -0
  141. package/project-transform/src/checker/rules/value_types.js +206 -0
  142. package/project-transform/src/checker/rules/value_types.ts +407 -0
  143. package/project-transform/src/checker/timing.js +43 -0
  144. package/project-transform/src/checker/timing.ts +78 -0
  145. package/project-transform/src/checker/unsupported_feature_messages.js +337 -0
  146. package/project-transform/src/checker/unsupported_feature_messages.ts +531 -0
  147. package/project-transform/src/cli.js +892 -0
  148. package/project-transform/src/cli.ts +1476 -0
  149. package/project-transform/src/compiler/compile_project.js +319 -0
  150. package/project-transform/src/compiler/compile_project.ts +508 -0
  151. package/project-transform/src/compiler/errors.js +10 -0
  152. package/project-transform/src/compiler/errors.ts +29 -0
  153. package/project-transform/src/compiler/ir.js +1 -0
  154. package/project-transform/src/compiler/ir.ts +1526 -0
  155. package/project-transform/src/compiler/lower.js +30550 -0
  156. package/project-transform/src/compiler/lower.ts +43645 -0
  157. package/project-transform/src/compiler/lower_arrays.js +140 -0
  158. package/project-transform/src/compiler/lower_arrays.ts +190 -0
  159. package/project-transform/src/compiler/lower_strings.js +121 -0
  160. package/project-transform/src/compiler/lower_strings.ts +198 -0
  161. package/project-transform/src/compiler/lower_tagged.js +329 -0
  162. package/project-transform/src/compiler/lower_tagged.ts +427 -0
  163. package/project-transform/src/compiler/lower_views.js +171 -0
  164. package/project-transform/src/compiler/lower_views.ts +251 -0
  165. package/project-transform/src/compiler/object_keys.js +25 -0
  166. package/project-transform/src/compiler/object_keys.ts +35 -0
  167. package/project-transform/src/compiler/runtime_ir.js +30 -0
  168. package/project-transform/src/compiler/runtime_ir.ts +727 -0
  169. package/project-transform/src/compiler/tagged_boundary.js +18 -0
  170. package/project-transform/src/compiler/tagged_boundary.ts +37 -0
  171. package/project-transform/src/compiler/toolchain.js +170 -0
  172. package/project-transform/src/compiler/toolchain.ts +229 -0
  173. package/project-transform/src/compiler/unicode_case_data.js +2102 -0
  174. package/project-transform/src/compiler/unicode_case_data.ts +2112 -0
  175. package/project-transform/src/compiler/wasm_js_host_runtime.js +656 -0
  176. package/project-transform/src/compiler/wasm_js_host_runtime.ts +762 -0
  177. package/project-transform/src/compiler/wat_arrays.js +3132 -0
  178. package/project-transform/src/compiler/wat_arrays.ts +3768 -0
  179. package/project-transform/src/compiler/wat_emitter.js +17952 -0
  180. package/project-transform/src/compiler/wat_emitter.ts +22812 -0
  181. package/project-transform/src/compiler/wat_strings.js +129 -0
  182. package/project-transform/src/compiler/wat_strings.ts +187 -0
  183. package/project-transform/src/compiler/wat_tagged.js +548 -0
  184. package/project-transform/src/compiler/wat_tagged.ts +674 -0
  185. package/project-transform/src/compiler_generator_runner.js +153 -0
  186. package/project-transform/src/compiler_generator_runner.ts +171 -0
  187. package/project-transform/src/compiler_object_test_helpers.js +69 -0
  188. package/project-transform/src/compiler_object_test_helpers.ts +96 -0
  189. package/project-transform/src/compiler_promise_runner.js +2116 -0
  190. package/project-transform/src/compiler_promise_runner.ts +2184 -0
  191. package/project-transform/src/compiler_test_helpers.js +854 -0
  192. package/project-transform/src/compiler_test_helpers.ts +1087 -0
  193. package/project-transform/src/config.js +568 -0
  194. package/project-transform/src/config.ts +892 -0
  195. package/project-transform/src/diagnostic_metadata.js +67 -0
  196. package/project-transform/src/diagnostic_metadata.ts +99 -0
  197. package/project-transform/src/diagnostic_reference.js +1368 -0
  198. package/project-transform/src/diagnostic_reference.ts +1523 -0
  199. package/project-transform/src/editor_diagnostics_worker.js +176 -0
  200. package/project-transform/src/editor_diagnostics_worker.ts +250 -0
  201. package/project-transform/src/editor_projection.js +224 -0
  202. package/project-transform/src/editor_projection.ts +421 -0
  203. package/project-transform/src/frontend/builtin_expanded_program_test_cleanup.js +47 -0
  204. package/project-transform/src/frontend/builtin_expanded_program_test_cleanup.ts +72 -0
  205. package/project-transform/src/frontend/builtin_macro_support.js +842 -0
  206. package/project-transform/src/frontend/builtin_macro_support.ts +1386 -0
  207. package/project-transform/src/frontend/builtin_macros.js +409 -0
  208. package/project-transform/src/frontend/builtin_macros.ts +542 -0
  209. package/project-transform/src/frontend/component_poc_runtime.js +279 -0
  210. package/project-transform/src/frontend/component_poc_runtime.ts +372 -0
  211. package/project-transform/src/frontend/css_macro.js +148 -0
  212. package/project-transform/src/frontend/css_macro.ts +222 -0
  213. package/project-transform/src/frontend/derive_macros.js +2072 -0
  214. package/project-transform/src/frontend/derive_macros.ts +3188 -0
  215. package/project-transform/src/frontend/embedded_fragment_support.js +106 -0
  216. package/project-transform/src/frontend/embedded_fragment_support.ts +172 -0
  217. package/project-transform/src/frontend/error_normalization.js +403 -0
  218. package/project-transform/src/frontend/error_normalization.ts +832 -0
  219. package/project-transform/src/frontend/error_stdlib_support.js +1 -0
  220. package/project-transform/src/frontend/error_stdlib_support.ts +6 -0
  221. package/project-transform/src/frontend/expand_project.js +169 -0
  222. package/project-transform/src/frontend/expand_project.ts +248 -0
  223. package/project-transform/src/frontend/format_soundscript.js +297 -0
  224. package/project-transform/src/frontend/format_soundscript.ts +582 -0
  225. package/project-transform/src/frontend/graphql_macro.js +174 -0
  226. package/project-transform/src/frontend/graphql_macro.ts +253 -0
  227. package/project-transform/src/frontend/hash_context.js +83 -0
  228. package/project-transform/src/frontend/hash_context.ts +113 -0
  229. package/project-transform/src/frontend/hkt_macro.js +448 -0
  230. package/project-transform/src/frontend/hkt_macro.ts +897 -0
  231. package/project-transform/src/frontend/import_binding_usage.js +190 -0
  232. package/project-transform/src/frontend/import_binding_usage.ts +277 -0
  233. package/project-transform/src/frontend/macro_advanced_backend_adapter.js +58 -0
  234. package/project-transform/src/frontend/macro_advanced_backend_adapter.ts +123 -0
  235. package/project-transform/src/frontend/macro_advanced_context.js +826 -0
  236. package/project-transform/src/frontend/macro_advanced_context.ts +1102 -0
  237. package/project-transform/src/frontend/macro_advanced_output.js +21 -0
  238. package/project-transform/src/frontend/macro_advanced_output.ts +41 -0
  239. package/project-transform/src/frontend/macro_api.js +353 -0
  240. package/project-transform/src/frontend/macro_api.ts +1722 -0
  241. package/project-transform/src/frontend/macro_api_internal.js +35 -0
  242. package/project-transform/src/frontend/macro_api_internal.ts +80 -0
  243. package/project-transform/src/frontend/macro_api_module_support.js +39 -0
  244. package/project-transform/src/frontend/macro_api_module_support.ts +65 -0
  245. package/project-transform/src/frontend/macro_backend_adapter.js +272 -0
  246. package/project-transform/src/frontend/macro_backend_adapter.ts +420 -0
  247. package/project-transform/src/frontend/macro_context.js +816 -0
  248. package/project-transform/src/frontend/macro_context.ts +1105 -0
  249. package/project-transform/src/frontend/macro_debug.js +99 -0
  250. package/project-transform/src/frontend/macro_debug.ts +157 -0
  251. package/project-transform/src/frontend/macro_definition_support.js +28 -0
  252. package/project-transform/src/frontend/macro_definition_support.ts +73 -0
  253. package/project-transform/src/frontend/macro_errors.js +40 -0
  254. package/project-transform/src/frontend/macro_errors.ts +70 -0
  255. package/project-transform/src/frontend/macro_expander.js +919 -0
  256. package/project-transform/src/frontend/macro_expander.ts +1611 -0
  257. package/project-transform/src/frontend/macro_factory_support.js +176 -0
  258. package/project-transform/src/frontend/macro_factory_support.ts +263 -0
  259. package/project-transform/src/frontend/macro_host_ast_internal.js +64 -0
  260. package/project-transform/src/frontend/macro_host_ast_internal.ts +109 -0
  261. package/project-transform/src/frontend/macro_index.js +27 -0
  262. package/project-transform/src/frontend/macro_index.ts +50 -0
  263. package/project-transform/src/frontend/macro_loader.js +281 -0
  264. package/project-transform/src/frontend/macro_loader.ts +506 -0
  265. package/project-transform/src/frontend/macro_operand_semantics.js +838 -0
  266. package/project-transform/src/frontend/macro_operand_semantics.ts +1489 -0
  267. package/project-transform/src/frontend/macro_output.js +54 -0
  268. package/project-transform/src/frontend/macro_output.ts +123 -0
  269. package/project-transform/src/frontend/macro_parser.js +611 -0
  270. package/project-transform/src/frontend/macro_parser.ts +832 -0
  271. package/project-transform/src/frontend/macro_resolver.js +69 -0
  272. package/project-transform/src/frontend/macro_resolver.ts +125 -0
  273. package/project-transform/src/frontend/macro_rewrite.js +285 -0
  274. package/project-transform/src/frontend/macro_rewrite.ts +442 -0
  275. package/project-transform/src/frontend/macro_runtime_support.js +232 -0
  276. package/project-transform/src/frontend/macro_runtime_support.ts +324 -0
  277. package/project-transform/src/frontend/macro_scanner.js +393 -0
  278. package/project-transform/src/frontend/macro_scanner.ts +455 -0
  279. package/project-transform/src/frontend/macro_semantic_backend_adapter.js +87 -0
  280. package/project-transform/src/frontend/macro_semantic_backend_adapter.ts +166 -0
  281. package/project-transform/src/frontend/macro_semantic_context.js +5 -0
  282. package/project-transform/src/frontend/macro_semantic_context.ts +12 -0
  283. package/project-transform/src/frontend/macro_semantic_output.js +24 -0
  284. package/project-transform/src/frontend/macro_semantic_output.ts +47 -0
  285. package/project-transform/src/frontend/macro_semantic_types.js +1 -0
  286. package/project-transform/src/frontend/macro_semantic_types.ts +98 -0
  287. package/project-transform/src/frontend/macro_semantics.js +1172 -0
  288. package/project-transform/src/frontend/macro_semantics.ts +1502 -0
  289. package/project-transform/src/frontend/macro_site_kind_support.js +164 -0
  290. package/project-transform/src/frontend/macro_site_kind_support.ts +255 -0
  291. package/project-transform/src/frontend/macro_syntax_internal.js +1950 -0
  292. package/project-transform/src/frontend/macro_syntax_internal.ts +3338 -0
  293. package/project-transform/src/frontend/macro_templates.js +57 -0
  294. package/project-transform/src/frontend/macro_templates.ts +143 -0
  295. package/project-transform/src/frontend/macro_test_helpers.js +82 -0
  296. package/project-transform/src/frontend/macro_test_helpers.ts +136 -0
  297. package/project-transform/src/frontend/macro_types.js +1 -0
  298. package/project-transform/src/frontend/macro_types.ts +103 -0
  299. package/project-transform/src/frontend/macro_vm.js +39 -0
  300. package/project-transform/src/frontend/macro_vm.ts +113 -0
  301. package/project-transform/src/frontend/match_macro.js +885 -0
  302. package/project-transform/src/frontend/match_macro.ts +1220 -0
  303. package/project-transform/src/frontend/numeric_normalization.js +824 -0
  304. package/project-transform/src/frontend/numeric_normalization.ts +1380 -0
  305. package/project-transform/src/frontend/numeric_prelude.js +278 -0
  306. package/project-transform/src/frontend/numeric_prelude.ts +370 -0
  307. package/project-transform/src/frontend/project_frontend.js +2396 -0
  308. package/project-transform/src/frontend/project_frontend.ts +3776 -0
  309. package/project-transform/src/frontend/project_macro_support.js +1401 -0
  310. package/project-transform/src/frontend/project_macro_support.ts +2137 -0
  311. package/project-transform/src/frontend/sql_macro.js +175 -0
  312. package/project-transform/src/frontend/sql_macro.ts +254 -0
  313. package/project-transform/src/frontend/sql_stdlib_support.js +1 -0
  314. package/project-transform/src/frontend/sql_stdlib_support.ts +6 -0
  315. package/project-transform/src/frontend/std_package_support.js +228 -0
  316. package/project-transform/src/frontend/std_package_support.ts +400 -0
  317. package/project-transform/src/frontend/value_normalization.js +306 -0
  318. package/project-transform/src/frontend/value_normalization.ts +599 -0
  319. package/project-transform/src/lsp/project_service.js +4771 -0
  320. package/project-transform/src/lsp/project_service.ts +7580 -0
  321. package/project-transform/src/lsp/protocol.js +9 -0
  322. package/project-transform/src/lsp/protocol.ts +38 -0
  323. package/project-transform/src/lsp/server.js +355 -0
  324. package/project-transform/src/lsp/server.ts +671 -0
  325. package/project-transform/src/lsp/session.js +49 -0
  326. package/project-transform/src/lsp/session.ts +48 -0
  327. package/project-transform/src/lsp/timing.js +43 -0
  328. package/project-transform/src/lsp/timing.ts +76 -0
  329. package/project-transform/src/lsp/transport.js +205 -0
  330. package/project-transform/src/lsp/transport.ts +253 -0
  331. package/project-transform/src/lsp_main.js +5 -0
  332. package/project-transform/src/lsp_main.ts +7 -0
  333. package/project-transform/src/macros.d.ts +1 -0
  334. package/project-transform/src/macros.js +1 -0
  335. package/project-transform/src/macros.ts +1 -0
  336. package/project-transform/src/main.js +24 -0
  337. package/project-transform/src/main.ts +28 -0
  338. package/project-transform/src/platform/host.js +264 -0
  339. package/project-transform/src/platform/host.ts +343 -0
  340. package/project-transform/src/platform/path.js +8 -0
  341. package/project-transform/src/platform/path.ts +20 -0
  342. package/project-transform/src/public_macro_api/macro_api.d.ts +1054 -0
  343. package/project-transform/src/public_macro_api/macro_semantic_types.d.ts +66 -0
  344. package/project-transform/src/public_macro_api/macro_types.d.ts +70 -0
  345. package/project-transform/src/run_program.js +14 -0
  346. package/project-transform/src/run_program.ts +33 -0
  347. package/project-transform/src/runtime/materialize.js +371 -0
  348. package/project-transform/src/runtime/materialize.ts +502 -0
  349. package/project-transform/src/runtime/on_demand.js +203 -0
  350. package/project-transform/src/runtime/on_demand.ts +305 -0
  351. package/project-transform/src/runtime/source_maps.js +205 -0
  352. package/project-transform/src/runtime/source_maps.ts +297 -0
  353. package/project-transform/src/runtime/transform.js +148 -0
  354. package/project-transform/src/runtime/transform.ts +295 -0
  355. package/project-transform/src/service/types.js +1 -0
  356. package/project-transform/src/service/types.ts +22 -0
  357. package/project-transform/src/soundscript_packages.js +477 -0
  358. package/project-transform/src/soundscript_packages.ts +754 -0
  359. package/project-transform/src/soundscript_runtime_specifiers.js +88 -0
  360. package/project-transform/src/soundscript_runtime_specifiers.ts +96 -0
  361. package/project-transform/src/stdlib/async.d.ts +81 -0
  362. package/project-transform/src/stdlib/async.js +213 -0
  363. package/project-transform/src/stdlib/async.ts +315 -0
  364. package/project-transform/src/stdlib/codec.d.ts +32 -0
  365. package/project-transform/src/stdlib/codec.js +30 -0
  366. package/project-transform/src/stdlib/codec.ts +76 -0
  367. package/project-transform/src/stdlib/compare.d.ts +28 -0
  368. package/project-transform/src/stdlib/compare.js +115 -0
  369. package/project-transform/src/stdlib/compare.ts +151 -0
  370. package/project-transform/src/stdlib/css.d.ts +16 -0
  371. package/project-transform/src/stdlib/css.js +9 -0
  372. package/project-transform/src/stdlib/css.ts +28 -0
  373. package/project-transform/src/stdlib/debug.d.ts +2 -0
  374. package/project-transform/src/stdlib/debug.js +9 -0
  375. package/project-transform/src/stdlib/debug.ts +10 -0
  376. package/project-transform/src/stdlib/decode.d.ts +86 -0
  377. package/project-transform/src/stdlib/decode.js +254 -0
  378. package/project-transform/src/stdlib/decode.ts +390 -0
  379. package/project-transform/src/stdlib/derive.d.ts +6 -0
  380. package/project-transform/src/stdlib/derive.js +7 -0
  381. package/project-transform/src/stdlib/derive.ts +7 -0
  382. package/project-transform/src/stdlib/encode.d.ts +100 -0
  383. package/project-transform/src/stdlib/encode.js +130 -0
  384. package/project-transform/src/stdlib/encode.ts +259 -0
  385. package/project-transform/src/stdlib/failures.d.ts +23 -0
  386. package/project-transform/src/stdlib/failures.js +41 -0
  387. package/project-transform/src/stdlib/failures.ts +64 -0
  388. package/project-transform/src/stdlib/fetch.d.ts +67 -0
  389. package/project-transform/src/stdlib/fetch.js +5 -0
  390. package/project-transform/src/stdlib/fetch.ts +11 -0
  391. package/project-transform/src/stdlib/graphql.d.ts +16 -0
  392. package/project-transform/src/stdlib/graphql.js +9 -0
  393. package/project-transform/src/stdlib/graphql.ts +28 -0
  394. package/project-transform/src/stdlib/hash.d.ts +34 -0
  395. package/project-transform/src/stdlib/hash.js +110 -0
  396. package/project-transform/src/stdlib/hash.ts +188 -0
  397. package/project-transform/src/stdlib/hkt.d.ts +40 -0
  398. package/project-transform/src/stdlib/hkt.js +3 -0
  399. package/project-transform/src/stdlib/hkt.ts +41 -0
  400. package/project-transform/src/stdlib/index.d.ts +9 -0
  401. package/project-transform/src/stdlib/index.js +15 -0
  402. package/project-transform/src/stdlib/index.ts +23 -0
  403. package/project-transform/src/stdlib/json.d.ts +125 -0
  404. package/project-transform/src/stdlib/json.js +764 -0
  405. package/project-transform/src/stdlib/json.ts +1034 -0
  406. package/project-transform/src/stdlib/match.d.ts +11 -0
  407. package/project-transform/src/stdlib/match.js +13 -0
  408. package/project-transform/src/stdlib/match.ts +26 -0
  409. package/project-transform/src/stdlib/numerics.d.ts +523 -0
  410. package/project-transform/src/stdlib/numerics.js +1356 -0
  411. package/project-transform/src/stdlib/numerics.ts +1937 -0
  412. package/project-transform/src/stdlib/random.d.ts +19 -0
  413. package/project-transform/src/stdlib/random.js +3 -0
  414. package/project-transform/src/stdlib/random.ts +5 -0
  415. package/project-transform/src/stdlib/result.d.ts +68 -0
  416. package/project-transform/src/stdlib/result.js +139 -0
  417. package/project-transform/src/stdlib/result.ts +248 -0
  418. package/project-transform/src/stdlib/sql.d.ts +22 -0
  419. package/project-transform/src/stdlib/sql.js +23 -0
  420. package/project-transform/src/stdlib/sql.ts +53 -0
  421. package/project-transform/src/stdlib/text.d.ts +24 -0
  422. package/project-transform/src/stdlib/text.js +3 -0
  423. package/project-transform/src/stdlib/text.ts +4 -0
  424. package/project-transform/src/stdlib/thunk.d.ts +2 -0
  425. package/project-transform/src/stdlib/thunk.js +9 -0
  426. package/project-transform/src/stdlib/thunk.ts +15 -0
  427. package/project-transform/src/stdlib/typeclasses.d.ts +57 -0
  428. package/project-transform/src/stdlib/typeclasses.js +78 -0
  429. package/project-transform/src/stdlib/typeclasses.ts +173 -0
  430. package/project-transform/src/stdlib/url.d.ts +37 -0
  431. package/project-transform/src/stdlib/url.js +3 -0
  432. package/project-transform/src/stdlib/url.ts +4 -0
  433. package/project-transform/src/stdlib/value.d.ts +9 -0
  434. package/project-transform/src/stdlib/value.js +104 -0
  435. package/project-transform/src/stdlib/value.ts +133 -0
  436. package/project-transform/src/test_installed_stdlib.js +147 -0
  437. package/project-transform/src/test_installed_stdlib.ts +245 -0
  438. package/project-transform/src/test_macro_package_fixture.js +50 -0
  439. package/project-transform/src/test_macro_package_fixture.ts +68 -0
  440. package/project-transform/src/value_deep_safe.js +191 -0
  441. package/project-transform/src/value_deep_safe.ts +273 -0
@@ -0,0 +1,1220 @@
1
+ import type {
2
+ ExprSyntax,
3
+ InvocationSyntax,
4
+ MacroArrayLiteralExprSyntax,
5
+ MacroContext,
6
+ MacroFunctionExprSyntax,
7
+ MacroHoverContext,
8
+ MacroPositionHoverContext,
9
+ MacroHoverResult,
10
+ MacroParameterSyntax,
11
+ MacroSemanticToken,
12
+ MacroSemanticTokensContext,
13
+ } from './macro_api.ts';
14
+ import type { MacroFiniteCase, MacroRuntimeKind } from './macro_semantic_types.ts';
15
+
16
+ type MatchTypeofPatternKind = MacroRuntimeKind;
17
+
18
+ type MatchObjectPatternKey =
19
+ | { readonly kind: 'computed'; readonly expressionText: string }
20
+ | { readonly kind: 'identifier'; readonly text: string }
21
+ | { readonly kind: 'literal'; readonly code: string };
22
+
23
+ interface MatchObjectPropertyPattern {
24
+ readonly key: MatchObjectPatternKey;
25
+ readonly pattern: MatchPattern;
26
+ }
27
+
28
+ type MatchArrayPatternElement =
29
+ | { readonly kind: 'elision' }
30
+ | MatchPattern;
31
+
32
+ type MatchPattern =
33
+ | { readonly kind: 'binding'; readonly name: string }
34
+ | {
35
+ readonly elements: readonly MatchArrayPatternElement[];
36
+ readonly kind: 'array';
37
+ readonly rest: MatchPattern | null;
38
+ }
39
+ | {
40
+ readonly bindingName: string | null;
41
+ readonly className: string;
42
+ readonly kind: 'instanceof';
43
+ readonly narrowedTypeText?: string;
44
+ }
45
+ | { readonly kind: 'literal'; readonly code: string }
46
+ | {
47
+ readonly kind: 'object';
48
+ readonly properties: readonly MatchObjectPropertyPattern[];
49
+ readonly rest: string | null;
50
+ }
51
+ | {
52
+ readonly bindingName: string | null;
53
+ readonly kind: 'typeof';
54
+ readonly typeName: MatchTypeofPatternKind;
55
+ }
56
+ | { readonly kind: 'wildcard' };
57
+
58
+ interface LoweringState {
59
+ readonly computedKeyOrder: readonly MatchObjectPatternKey[];
60
+ readonly computedKeyTemps: WeakMap<object, string>;
61
+ readonly needsArrayExtractHelper: boolean;
62
+ readonly needsObjectRestHelper: boolean;
63
+ }
64
+
65
+ interface ArrayMatchArm {
66
+ readonly armText: string;
67
+ readonly emittedArmText: string;
68
+ readonly emittedGuardText: string | null;
69
+ readonly fallbackTypeText: string;
70
+ readonly guardText: string | null;
71
+ readonly isCatchAll: boolean;
72
+ readonly parameter: MacroParameterSyntax;
73
+ readonly patterns: readonly MatchPattern[];
74
+ }
75
+
76
+ function emittedArrowText(
77
+ functionExpr: ReturnType<ExprSyntax['asFunction']>,
78
+ fallbackTypeText: string | null,
79
+ ): string {
80
+ if (!functionExpr) {
81
+ return '';
82
+ }
83
+
84
+ const [parameter] = functionExpr.parameters;
85
+ if (!parameter || parameter.hasExplicitType() || parameter.name === null) {
86
+ return functionExpr.text();
87
+ }
88
+ if (!fallbackTypeText) {
89
+ return functionExpr.text();
90
+ }
91
+
92
+ const blockBody = functionExpr.body();
93
+ const exprBody = functionExpr.returnedExpr();
94
+ const bodyText = blockBody?.text() ?? exprBody?.text();
95
+ if (!bodyText) {
96
+ return functionExpr.text();
97
+ }
98
+
99
+ return `((${parameter.name}: ${fallbackTypeText}) => ${bodyText})`;
100
+ }
101
+
102
+ function spanContains(
103
+ span: { readonly start: number; readonly end: number },
104
+ position: number,
105
+ ): boolean {
106
+ return position >= span.start && position <= span.end;
107
+ }
108
+
109
+ function validateExplicitObjectTypeArmAnnotation(
110
+ ctx: MacroContext,
111
+ parameter: MacroParameterSyntax,
112
+ ): void {
113
+ const explicitType = parameter.explicitType()?.asObjectLiteral();
114
+ if (!explicitType) {
115
+ return;
116
+ }
117
+
118
+ const shorthandMembers = explicitType.members.filter((member) =>
119
+ member.memberKind === 'property_signature' && !member.hasExplicitType()
120
+ );
121
+ if (shorthandMembers.length === 0) {
122
+ return;
123
+ }
124
+
125
+ ctx.error(
126
+ `Match object-type arm annotations do not support untyped shorthand members in \`${explicitType.text()}\`. Use explicit property types, or destructure against a named type like \`({ value }: Ok) => ...\`.`,
127
+ explicitType,
128
+ );
129
+ }
130
+
131
+ function appendParameterSemanticTokens(
132
+ tokens: MacroSemanticToken[],
133
+ parameter: MacroParameterSyntax,
134
+ ): void {
135
+ for (const binding of parameter.bindingIdentifiers()) {
136
+ tokens.push({
137
+ modifiers: ['declaration'],
138
+ span: binding.span,
139
+ type: 'parameter',
140
+ });
141
+ }
142
+ }
143
+
144
+ function appendArmSemanticTokens(
145
+ tokens: MacroSemanticToken[],
146
+ expression: ExprSyntax,
147
+ ): void {
148
+ const functionExpr = expression.unparenthesized().asFunction();
149
+ if (functionExpr?.functionKind === 'arrow') {
150
+ for (const parameter of functionExpr.parameters) {
151
+ appendParameterSemanticTokens(tokens, parameter);
152
+ }
153
+ return;
154
+ }
155
+
156
+ const call = expression.unparenthesized().asCall();
157
+ if (call?.callee.asIdentifier() === 'where') {
158
+ for (const argument of call.args) {
159
+ appendArmSemanticTokens(tokens, argument);
160
+ }
161
+ }
162
+ }
163
+
164
+ const MATCH_REJECTED_LEGACY_NUMERIC_TYPES = new Set(['NumberLike', 'BigintLike', 'numeric']);
165
+ const MATCH_MACHINE_NUMERIC_RUNTIME_KINDS = new Set([
166
+ 'f64',
167
+ 'f32',
168
+ 'i8',
169
+ 'i16',
170
+ 'i32',
171
+ 'i64',
172
+ 'u8',
173
+ 'u16',
174
+ 'u32',
175
+ 'u64',
176
+ ]);
177
+
178
+ function normalizedExplicitTypeText(parameter: MacroParameterSyntax): string | null {
179
+ return parameter.explicitType()?.text().replace(/\s+/gu, '') ?? null;
180
+ }
181
+
182
+ function validateNumericMatchTypeText(
183
+ ctx: MacroContext,
184
+ parameter: MacroParameterSyntax,
185
+ ): void {
186
+ const normalizedTypeText = normalizedExplicitTypeText(parameter);
187
+ if (!normalizedTypeText) {
188
+ return;
189
+ }
190
+
191
+ if (MATCH_REJECTED_LEGACY_NUMERIC_TYPES.has(normalizedTypeText)) {
192
+ ctx.error(
193
+ 'Match no longer supports legacy NumberLike, BigintLike, or numeric patterns. Use host `number`/`bigint`, exact machine leaves like `u8`, or machine families like `Int`, `Float`, and `Numeric`.',
194
+ );
195
+ }
196
+ }
197
+
198
+ function isIdentifierText(text: string): boolean {
199
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(text);
200
+ }
201
+
202
+ function finiteCaseKeyToPatternKey(key: string): MatchObjectPatternKey {
203
+ return isIdentifierText(key)
204
+ ? { kind: 'identifier', text: key }
205
+ : { kind: 'literal', code: JSON.stringify(key) };
206
+ }
207
+
208
+ function patternFromFiniteCase(
209
+ finiteCase: MacroFiniteCase,
210
+ narrowedTypeText?: string,
211
+ ): MatchPattern {
212
+ switch (finiteCase.kind) {
213
+ case 'literal':
214
+ return { kind: 'literal', code: finiteCase.code };
215
+ case 'runtime':
216
+ return { kind: 'typeof', bindingName: null, typeName: finiteCase.typeName };
217
+ case 'class':
218
+ return {
219
+ kind: 'instanceof',
220
+ bindingName: null,
221
+ className: finiteCase.className,
222
+ narrowedTypeText,
223
+ };
224
+ case 'object':
225
+ return {
226
+ kind: 'object',
227
+ properties: finiteCase.properties.map((property) => ({
228
+ key: finiteCaseKeyToPatternKey(property.key),
229
+ pattern: property.finiteCase
230
+ ? patternFromFiniteCase(property.finiteCase)
231
+ : { kind: 'wildcard' },
232
+ })),
233
+ rest: null,
234
+ };
235
+ case 'array':
236
+ return {
237
+ kind: 'array',
238
+ elements: finiteCase.elements.map((element) =>
239
+ element.finiteCase ? patternFromFiniteCase(element.finiteCase) : { kind: 'wildcard' }
240
+ ),
241
+ rest: null,
242
+ };
243
+ }
244
+ }
245
+
246
+ function preludeConstructorPredicate(className: string): string | null {
247
+ switch (simpleClassName(className)) {
248
+ case 'Ok':
249
+ return 'isOk';
250
+ case 'Err':
251
+ return 'isErr';
252
+ case 'Some':
253
+ return 'isSome';
254
+ case 'None':
255
+ return 'isNone';
256
+ default:
257
+ return null;
258
+ }
259
+ }
260
+
261
+ function fallbackNarrowedTypeForClass(className: string): string {
262
+ switch (simpleClassName(className)) {
263
+ case 'Ok':
264
+ return 'Ok<unknown>';
265
+ case 'Err':
266
+ return 'Err<unknown>';
267
+ case 'Some':
268
+ return 'Some<unknown>';
269
+ case 'None':
270
+ return 'None';
271
+ default:
272
+ return className;
273
+ }
274
+ }
275
+
276
+ function hasCatchAllArm(arm: ArrayMatchArm): boolean {
277
+ return arm.guardText === null && arm.isCatchAll;
278
+ }
279
+
280
+ function armCoversFiniteCase(arm: ArrayMatchArm, finiteCase: MacroFiniteCase): boolean {
281
+ if (arm.guardText !== null) {
282
+ return false;
283
+ }
284
+ return arm.isCatchAll ||
285
+ arm.patterns.some((pattern) => patternCoversFiniteCase(pattern, finiteCase));
286
+ }
287
+
288
+ function indentLines(lines: readonly string[]): string[] {
289
+ return lines.map((line) => line.length === 0 ? line : ` ${line}`);
290
+ }
291
+
292
+ function wrapGuard(condition: string, successLines: readonly string[]): string[] {
293
+ return [
294
+ `if (${condition}) {`,
295
+ ...indentLines(successLines),
296
+ '}',
297
+ ];
298
+ }
299
+
300
+ function canonicalLiteralCode(code: string): string {
301
+ const trimmed = code.trim();
302
+ if (
303
+ (trimmed.startsWith("'") && trimmed.endsWith("'")) ||
304
+ (trimmed.startsWith('"') && trimmed.endsWith('"')) ||
305
+ (trimmed.startsWith('`') && trimmed.endsWith('`'))
306
+ ) {
307
+ return JSON.stringify(trimmed.slice(1, -1));
308
+ }
309
+
310
+ return trimmed;
311
+ }
312
+
313
+ function simpleClassName(text: string): string {
314
+ const segments = text.split('.');
315
+ return segments[segments.length - 1] ?? text;
316
+ }
317
+
318
+ function staticObjectKeyCode(key: MatchObjectPatternKey): string | null {
319
+ switch (key.kind) {
320
+ case 'computed':
321
+ return null;
322
+ case 'identifier':
323
+ return JSON.stringify(key.text);
324
+ case 'literal':
325
+ return canonicalLiteralCode(key.code);
326
+ }
327
+ }
328
+
329
+ function typeofTypeConstraint(typeName: MatchTypeofPatternKind): string {
330
+ switch (typeName) {
331
+ case 'bigint':
332
+ return 'bigint';
333
+ case 'boolean':
334
+ return 'boolean';
335
+ case 'f32':
336
+ return 'f32';
337
+ case 'f64':
338
+ return 'f64';
339
+ case 'function':
340
+ return 'Function';
341
+ case 'i8':
342
+ return 'i8';
343
+ case 'i16':
344
+ return 'i16';
345
+ case 'i32':
346
+ return 'i32';
347
+ case 'i64':
348
+ return 'i64';
349
+ case 'number':
350
+ return 'number';
351
+ case 'object':
352
+ return 'object | null';
353
+ case 'string':
354
+ return 'string';
355
+ case 'symbol':
356
+ return 'symbol';
357
+ case 'u8':
358
+ return 'u8';
359
+ case 'u16':
360
+ return 'u16';
361
+ case 'u32':
362
+ return 'u32';
363
+ case 'u64':
364
+ return 'u64';
365
+ case 'undefined':
366
+ return 'undefined';
367
+ }
368
+ }
369
+
370
+ function machineNumericKindCondition(subjectExpr: string, kind: string): string {
371
+ return `typeof ${subjectExpr} === "object" && ${subjectExpr} !== null && (${subjectExpr} as { __soundscript_numeric_kind?: unknown }).__soundscript_numeric_kind === ${JSON.stringify(kind)}`;
372
+ }
373
+
374
+ function isStringLiteralCode(code: string): boolean {
375
+ const trimmed = canonicalLiteralCode(code);
376
+ return trimmed.startsWith('"') && trimmed.endsWith('"');
377
+ }
378
+
379
+ function isNumberLiteralCode(code: string): boolean {
380
+ return /^-?\d+(?:\.\d+)?$/u.test(canonicalLiteralCode(code));
381
+ }
382
+
383
+ function isBooleanLiteralCode(code: string): boolean {
384
+ const trimmed = canonicalLiteralCode(code);
385
+ return trimmed === 'true' || trimmed === 'false';
386
+ }
387
+
388
+ function finiteObjectProperty(
389
+ finiteCase: Extract<MacroFiniteCase, { kind: 'object' }>,
390
+ propertyKey: string,
391
+ ) {
392
+ return finiteCase.properties.find((property) => property.key === propertyKey) ?? null;
393
+ }
394
+
395
+ function finiteCaseFromTupleSlice(
396
+ finiteCase: Extract<MacroFiniteCase, { kind: 'array' }>,
397
+ startIndex: number,
398
+ ): MacroFiniteCase {
399
+ return {
400
+ kind: 'array',
401
+ exactLength: Math.max(0, finiteCase.exactLength - startIndex),
402
+ elements: finiteCase.elements.slice(startIndex),
403
+ };
404
+ }
405
+
406
+ function patternCoversNestedFiniteCase(
407
+ pattern: MatchPattern,
408
+ finiteCase: MacroFiniteCase | null,
409
+ ): boolean {
410
+ if (finiteCase === null) {
411
+ return pattern.kind === 'binding' || pattern.kind === 'wildcard';
412
+ }
413
+ return patternCoversFiniteCase(pattern, finiteCase);
414
+ }
415
+
416
+ function patternCoversFiniteCase(pattern: MatchPattern, finiteCase: MacroFiniteCase): boolean {
417
+ switch (pattern.kind) {
418
+ case 'wildcard':
419
+ case 'binding':
420
+ return true;
421
+ case 'literal':
422
+ return finiteCase.kind === 'literal' &&
423
+ finiteCase.code === canonicalLiteralCode(pattern.code);
424
+ case 'instanceof':
425
+ return finiteCase.kind === 'class' &&
426
+ finiteCase.className === simpleClassName(pattern.className);
427
+ case 'typeof':
428
+ if (finiteCase.kind === 'runtime') {
429
+ return finiteCase.typeName === pattern.typeName;
430
+ }
431
+ switch (pattern.typeName) {
432
+ case 'string':
433
+ return finiteCase.kind === 'literal' && isStringLiteralCode(finiteCase.code);
434
+ case 'number':
435
+ return finiteCase.kind === 'literal' && isNumberLiteralCode(finiteCase.code);
436
+ case 'boolean':
437
+ return finiteCase.kind === 'literal' && isBooleanLiteralCode(finiteCase.code);
438
+ case 'object':
439
+ return finiteCase.kind === 'object' ||
440
+ finiteCase.kind === 'array' ||
441
+ finiteCase.kind === 'class' ||
442
+ (finiteCase.kind === 'literal' && finiteCase.code === 'null');
443
+ default:
444
+ return false;
445
+ }
446
+ case 'array':
447
+ if (finiteCase.kind !== 'array') {
448
+ return false;
449
+ }
450
+
451
+ if (finiteCase.exactLength < pattern.elements.length) {
452
+ return false;
453
+ }
454
+
455
+ for (let index = 0; index < pattern.elements.length; index += 1) {
456
+ const element = pattern.elements[index]!;
457
+ if (element.kind === 'elision') {
458
+ continue;
459
+ }
460
+ if (
461
+ !patternCoversNestedFiniteCase(element, finiteCase.elements[index]?.finiteCase ?? null)
462
+ ) {
463
+ return false;
464
+ }
465
+ }
466
+
467
+ if (pattern.rest !== null) {
468
+ return patternCoversNestedFiniteCase(
469
+ pattern.rest,
470
+ finiteCaseFromTupleSlice(finiteCase, pattern.elements.length),
471
+ );
472
+ }
473
+
474
+ return true;
475
+ case 'object':
476
+ if (finiteCase.kind !== 'object') {
477
+ return false;
478
+ }
479
+
480
+ return pattern.properties.every((property) => {
481
+ const staticKey = staticObjectKeyCode(property.key);
482
+ if (!staticKey) {
483
+ return false;
484
+ }
485
+
486
+ const propertyKey = staticKey.startsWith('"') && staticKey.endsWith('"')
487
+ ? JSON.parse(staticKey) as string
488
+ : staticKey;
489
+ const finiteProperty = finiteObjectProperty(finiteCase, propertyKey);
490
+ if (!finiteProperty) {
491
+ return false;
492
+ }
493
+
494
+ return patternCoversNestedFiniteCase(property.pattern, finiteProperty.finiteCase);
495
+ });
496
+ }
497
+ }
498
+
499
+ function parseArrayMatchArm(
500
+ ctx: MacroContext,
501
+ armSyntax: ExprSyntax,
502
+ ): ArrayMatchArm {
503
+ let armNode = armSyntax;
504
+ let guardNode: ExprSyntax | null = null;
505
+ const whereCall = armSyntax.unparenthesized().asCall();
506
+ if (whereCall?.callee.asIdentifier() === 'where') {
507
+ if (whereCall.args.length !== 2) {
508
+ ctx.error('Match where(...) arms require exactly two arguments: where(arm, predicate).');
509
+ }
510
+ armNode = whereCall.args[0]!;
511
+ guardNode = whereCall.args[1]!;
512
+ }
513
+
514
+ const armFunction = armNode.asFunction();
515
+ if (!armFunction) {
516
+ ctx.error(
517
+ 'Match array arms must be single-parameter arrow functions or where(arm, predicate).',
518
+ );
519
+ }
520
+
521
+ if (armFunction.functionKind !== 'arrow') {
522
+ ctx.error('Match array arms currently require arrow functions.');
523
+ }
524
+ if (armFunction.typeParameterCount() > 0) {
525
+ ctx.error('Match array arms do not support type-parameterized arrows.');
526
+ }
527
+ if (armFunction.hasAsyncModifier()) {
528
+ ctx.error('Match array arms do not support async arrows.');
529
+ }
530
+ if (armFunction.parameters.length !== 1) {
531
+ ctx.error('Match array arms require exactly one parameter.');
532
+ }
533
+
534
+ const [parameter] = armFunction.parameters;
535
+ if (!parameter) {
536
+ ctx.error('Match array arms require exactly one parameter.');
537
+ }
538
+
539
+ if (parameter.isRest()) {
540
+ ctx.error('Match array arms do not support rest parameters.');
541
+ }
542
+ if (parameter.hasDefault()) {
543
+ ctx.error('Match array arms do not support default parameter values.');
544
+ }
545
+
546
+ const scrutineeTypeText = ctx.semantics.argType(0)?.displayText ?? 'unknown';
547
+ const emittedArmText = emittedArrowText(armFunction, scrutineeTypeText);
548
+ const guardFunction = guardNode?.asFunction() ?? null;
549
+ const emittedGuardText = guardFunction
550
+ ? emittedArrowText(
551
+ guardFunction,
552
+ parameter.hasExplicitType() ? parameter.explicitType()?.text() ?? scrutineeTypeText : scrutineeTypeText,
553
+ )
554
+ : guardNode?.text() ?? null;
555
+
556
+ if (!parameter.hasExplicitType()) {
557
+ if (parameter.name === null) {
558
+ ctx.error('Match destructuring arms require an explicit runtime-matchable parameter type.');
559
+ }
560
+ return {
561
+ armText: armNode.text(),
562
+ emittedArmText,
563
+ emittedGuardText,
564
+ fallbackTypeText: scrutineeTypeText,
565
+ guardText: guardNode?.text() ?? null,
566
+ isCatchAll: true,
567
+ parameter,
568
+ patterns: [],
569
+ };
570
+ }
571
+
572
+ validateExplicitObjectTypeArmAnnotation(ctx, parameter);
573
+ validateNumericMatchTypeText(ctx, parameter);
574
+
575
+ const parameterType = ctx.semantics.parameterType(parameter);
576
+ if (parameterType === null) {
577
+ ctx.error('Match arm parameter types must lower to honest runtime matchers.');
578
+ }
579
+
580
+ const finiteCases = ctx.semantics.finiteCases(parameterType);
581
+ if (!finiteCases || finiteCases.length === 0) {
582
+ ctx.error('Match arm parameter types must lower to honest runtime matchers.');
583
+ }
584
+
585
+ return {
586
+ armText: armNode.text(),
587
+ emittedArmText,
588
+ emittedGuardText,
589
+ fallbackTypeText: scrutineeTypeText,
590
+ guardText: guardNode?.text() ?? null,
591
+ isCatchAll: false,
592
+ parameter,
593
+ patterns: finiteCases.map((finiteCase) =>
594
+ patternFromFiniteCase(
595
+ finiteCase,
596
+ finiteCases.length === 1 ? parameter.explicitType()?.text() : undefined,
597
+ )
598
+ ),
599
+ };
600
+ }
601
+
602
+ function parseArrayMatchArms(
603
+ ctx: MacroContext,
604
+ armArrayExpr: MacroArrayLiteralExprSyntax,
605
+ ): readonly ArrayMatchArm[] {
606
+ const expandedArmArrayExpr = ctx.semantics.argExpanded(1)?.asArrayLiteral() ?? armArrayExpr;
607
+ const arms = expandedArmArrayExpr.elements.map((element) => {
608
+ if (element.isSpread || element.expression() === null) {
609
+ ctx.error('Match arms do not support spreads or omitted array elements.');
610
+ }
611
+ return parseArrayMatchArm(ctx, element.expression()!);
612
+ });
613
+
614
+ if (arms.length === 0) {
615
+ ctx.error('Match requires at least one arm.');
616
+ }
617
+
618
+ return arms;
619
+ }
620
+
621
+ function requiresCatchAllForArms(ctx: MacroContext, arms: readonly ArrayMatchArm[]): boolean {
622
+ const scrutineeType = ctx.semantics.argType(0);
623
+ if (!scrutineeType) {
624
+ return true;
625
+ }
626
+
627
+ const finiteCases = ctx.semantics.finiteCases(scrutineeType);
628
+ if (!finiteCases || finiteCases.length === 0) {
629
+ return true;
630
+ }
631
+
632
+ return finiteCases.some((finiteCase) =>
633
+ !arms.some((arm) => armCoversFiniteCase(arm, finiteCase))
634
+ );
635
+ }
636
+
637
+ function validateArrayMatchArms(ctx: MacroContext, arms: readonly ArrayMatchArm[]): void {
638
+ const catchAllIndex = arms.findIndex(hasCatchAllArm);
639
+ if (catchAllIndex === -1 && requiresCatchAllForArms(ctx, arms)) {
640
+ ctx.error(
641
+ 'Match requires a final catch-all arm unless the scrutinee type is provably exhaustive.',
642
+ );
643
+ }
644
+ if (catchAllIndex >= 0 && catchAllIndex !== arms.length - 1) {
645
+ ctx.error('Match catch-all arms must be the final arm.');
646
+ }
647
+ }
648
+
649
+ function collectLoweringState(pattern: MatchPattern): LoweringState {
650
+ const computedKeyOrder: MatchObjectPatternKey[] = [];
651
+ const computedKeyTemps = new WeakMap<object, string>();
652
+ let nextTempIndex = 1;
653
+ let needsArrayExtractHelper = false;
654
+ let needsObjectRestHelper = false;
655
+
656
+ function visit(current: MatchPattern) {
657
+ switch (current.kind) {
658
+ case 'array':
659
+ needsArrayExtractHelper = true;
660
+ for (const element of current.elements) {
661
+ if (element.kind !== 'elision') {
662
+ visit(element);
663
+ }
664
+ }
665
+ if (current.rest) {
666
+ visit(current.rest);
667
+ }
668
+ break;
669
+ case 'binding':
670
+ case 'instanceof':
671
+ case 'literal':
672
+ case 'typeof':
673
+ case 'wildcard':
674
+ break;
675
+ case 'object':
676
+ if (current.rest !== null) {
677
+ needsObjectRestHelper = true;
678
+ }
679
+ for (const property of current.properties) {
680
+ if (property.key.kind === 'computed' && !computedKeyTemps.has(property.key)) {
681
+ computedKeyTemps.set(property.key, `__sts_match_key_${nextTempIndex++}`);
682
+ computedKeyOrder.push(property.key);
683
+ }
684
+ visit(property.pattern);
685
+ }
686
+ break;
687
+ }
688
+ }
689
+
690
+ visit(pattern);
691
+ return {
692
+ computedKeyOrder,
693
+ computedKeyTemps,
694
+ needsArrayExtractHelper,
695
+ needsObjectRestHelper,
696
+ };
697
+ }
698
+
699
+ function runtimeObjectKeyExpression(key: MatchObjectPatternKey, state: LoweringState): string {
700
+ switch (key.kind) {
701
+ case 'computed': {
702
+ const temp = state.computedKeyTemps.get(key);
703
+ if (!temp) {
704
+ throw new Error('Missing computed object key temp.');
705
+ }
706
+ return temp;
707
+ }
708
+ case 'identifier':
709
+ return JSON.stringify(key.text);
710
+ case 'literal':
711
+ return key.code;
712
+ }
713
+ }
714
+
715
+ function objectRestExcludedType(key: MatchObjectPatternKey, state: LoweringState): string {
716
+ switch (key.kind) {
717
+ case 'computed':
718
+ return `typeof ${runtimeObjectKeyExpression(key, state)}`;
719
+ case 'identifier':
720
+ return JSON.stringify(key.text);
721
+ case 'literal':
722
+ return canonicalLiteralCode(key.code);
723
+ }
724
+ }
725
+
726
+ function propertyAccessExpression(
727
+ subjectExpr: string,
728
+ key: MatchObjectPatternKey,
729
+ state: LoweringState,
730
+ ): string {
731
+ switch (key.kind) {
732
+ case 'identifier':
733
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(key.text)
734
+ ? `${subjectExpr}.${key.text}`
735
+ : `${subjectExpr}[${JSON.stringify(key.text)}]`;
736
+ case 'literal':
737
+ return `${subjectExpr}[${key.code}]`;
738
+ case 'computed':
739
+ return `${subjectExpr}[${runtimeObjectKeyExpression(key, state)}]`;
740
+ }
741
+ }
742
+
743
+ function objectLikeCondition(subjectExpr: string): string {
744
+ return `((typeof ${subjectExpr} === "object" || typeof ${subjectExpr} === "function") && ${subjectExpr} !== null)`;
745
+ }
746
+
747
+ function objectRestExpression(
748
+ subjectExpr: string,
749
+ properties: readonly MatchObjectPropertyPattern[],
750
+ state: LoweringState,
751
+ ): string {
752
+ return `__sts_match_object_rest(${subjectExpr}, [${
753
+ properties.map((property) => runtimeObjectKeyExpression(property.key, state)).join(', ')
754
+ }])`;
755
+ }
756
+
757
+ function objectRestBindingStatement(
758
+ bindingName: string,
759
+ subjectExpr: string,
760
+ properties: readonly MatchObjectPropertyPattern[],
761
+ state: LoweringState,
762
+ typed: boolean,
763
+ ): string {
764
+ const expression = objectRestExpression(subjectExpr, properties, state);
765
+ if (!typed) {
766
+ return `const ${bindingName} = ${expression};`;
767
+ }
768
+
769
+ const excludedType = properties.length === 0
770
+ ? 'never'
771
+ : properties.map((property) => objectRestExcludedType(property.key, state)).join(' | ');
772
+ return `const ${bindingName} = ${expression} as __sts_match_omit<typeof ${subjectExpr}, ${excludedType}>;`;
773
+ }
774
+
775
+ function bindingStatementsForPattern(
776
+ pattern: MatchPattern,
777
+ subjectExpr: string,
778
+ state: LoweringState,
779
+ typed = false,
780
+ ): string[] {
781
+ switch (pattern.kind) {
782
+ case 'binding':
783
+ return [`const ${pattern.name} = ${subjectExpr};`];
784
+ case 'wildcard':
785
+ case 'literal':
786
+ return [];
787
+ case 'typeof':
788
+ return pattern.bindingName ? [`const ${pattern.bindingName} = ${subjectExpr};`] : [];
789
+ case 'instanceof':
790
+ return pattern.bindingName ? [`const ${pattern.bindingName} = ${subjectExpr};`] : [];
791
+ case 'object': {
792
+ const lines: string[] = [];
793
+ for (const property of pattern.properties) {
794
+ lines.push(...bindingStatementsForPattern(
795
+ property.pattern,
796
+ propertyAccessExpression(subjectExpr, property.key, state),
797
+ state,
798
+ typed,
799
+ ));
800
+ }
801
+ if (pattern.rest) {
802
+ lines.push(
803
+ objectRestBindingStatement(pattern.rest, subjectExpr, pattern.properties, state, typed),
804
+ );
805
+ }
806
+ return lines;
807
+ }
808
+ case 'array': {
809
+ const lines: string[] = [];
810
+ pattern.elements.forEach((element, index) => {
811
+ if (element.kind === 'elision') {
812
+ return;
813
+ }
814
+ lines.push(...bindingStatementsForPattern(
815
+ element,
816
+ `${subjectExpr}[${index}]`,
817
+ state,
818
+ typed,
819
+ ));
820
+ });
821
+ if (pattern.rest) {
822
+ lines.push(...bindingStatementsForPattern(
823
+ pattern.rest,
824
+ `${subjectExpr}.slice(${pattern.elements.length})`,
825
+ state,
826
+ typed,
827
+ ));
828
+ }
829
+ return lines;
830
+ }
831
+ }
832
+ }
833
+
834
+ function lowerObjectProperty(
835
+ property: MatchObjectPropertyPattern,
836
+ subjectExpr: string,
837
+ successLines: readonly string[],
838
+ state: LoweringState,
839
+ ): string[] {
840
+ const keyExpr = runtimeObjectKeyExpression(property.key, state);
841
+ let lines = lowerPattern(
842
+ property.pattern,
843
+ propertyAccessExpression(subjectExpr, property.key, state),
844
+ successLines,
845
+ state,
846
+ );
847
+ lines = wrapGuard(`${keyExpr} in ${subjectExpr}`, lines);
848
+ if (property.key.kind === 'computed') {
849
+ lines = [
850
+ `const ${keyExpr} = (${property.key.expressionText});`,
851
+ ...lines,
852
+ ];
853
+ }
854
+ return lines;
855
+ }
856
+
857
+ function lowerPattern(
858
+ pattern: MatchPattern,
859
+ subjectExpr: string,
860
+ successLines: readonly string[],
861
+ state: LoweringState,
862
+ ): string[] {
863
+ switch (pattern.kind) {
864
+ case 'binding':
865
+ return [`const ${pattern.name} = ${subjectExpr};`, ...successLines];
866
+ case 'wildcard':
867
+ return [...successLines];
868
+ case 'literal':
869
+ return wrapGuard(`${subjectExpr} === ${pattern.code}`, successLines);
870
+ case 'typeof': {
871
+ const inner = pattern.bindingName
872
+ ? [`const ${pattern.bindingName} = ${subjectExpr};`, ...successLines]
873
+ : [...successLines];
874
+ const condition = pattern.typeName === 'object'
875
+ ? objectLikeCondition(subjectExpr)
876
+ : MATCH_MACHINE_NUMERIC_RUNTIME_KINDS.has(pattern.typeName)
877
+ ? machineNumericKindCondition(subjectExpr, pattern.typeName)
878
+ : `typeof ${subjectExpr} === ${JSON.stringify(pattern.typeName)}`;
879
+ return wrapGuard(condition, inner);
880
+ }
881
+ case 'instanceof': {
882
+ const inner = pattern.bindingName
883
+ ? [`const ${pattern.bindingName} = ${subjectExpr};`, ...successLines]
884
+ : [...successLines];
885
+ const predicate = preludeConstructorPredicate(pattern.className);
886
+ return wrapGuard(
887
+ predicate ? `${predicate}(${subjectExpr})` : `${subjectExpr} instanceof ${pattern.className}`,
888
+ inner,
889
+ );
890
+ }
891
+ case 'object': {
892
+ let lines = [...successLines];
893
+ if (pattern.rest) {
894
+ lines = [
895
+ objectRestBindingStatement(pattern.rest, subjectExpr, pattern.properties, state, false),
896
+ ...lines,
897
+ ];
898
+ }
899
+ for (let index = pattern.properties.length - 1; index >= 0; index -= 1) {
900
+ lines = lowerObjectProperty(pattern.properties[index]!, subjectExpr, lines, state);
901
+ }
902
+ return wrapGuard(objectLikeCondition(subjectExpr), lines);
903
+ }
904
+ case 'array': {
905
+ let lines = [...successLines];
906
+ if (pattern.rest) {
907
+ lines = lowerPattern(
908
+ pattern.rest,
909
+ `${subjectExpr}.slice(${pattern.elements.length})`,
910
+ lines,
911
+ state,
912
+ );
913
+ }
914
+ for (let index = pattern.elements.length - 1; index >= 0; index -= 1) {
915
+ const element = pattern.elements[index]!;
916
+ if (element.kind === 'elision') {
917
+ continue;
918
+ }
919
+ lines = lowerPattern(element, `${subjectExpr}[${index}]`, lines, state);
920
+ }
921
+ return wrapGuard(
922
+ `Array.isArray(${subjectExpr}) && ${subjectExpr}.length >= ${pattern.elements.length}`,
923
+ lines,
924
+ );
925
+ }
926
+ }
927
+ }
928
+
929
+ function formatPatternTypeKey(key: MatchObjectPatternKey): string {
930
+ switch (key.kind) {
931
+ case 'computed':
932
+ return `[${key.expressionText}]`;
933
+ case 'identifier':
934
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(key.text) ? key.text : JSON.stringify(key.text);
935
+ case 'literal':
936
+ return key.code;
937
+ }
938
+ }
939
+
940
+ function arrayTypeConstraint(pattern: Extract<MatchPattern, { kind: 'array' }>): string {
941
+ if (pattern.elements.length === 0 && pattern.rest === null) {
942
+ return 'readonly unknown[]';
943
+ }
944
+
945
+ const entries = pattern.elements.map((element) =>
946
+ element.kind === 'elision' ? 'unknown' : typeConstraintForPattern(element)
947
+ );
948
+ return `readonly [${entries.join(', ')}${entries.length > 0 ? ', ' : ''}...unknown[]]`;
949
+ }
950
+
951
+ function objectTypeConstraint(pattern: Extract<MatchPattern, { kind: 'object' }>): string {
952
+ const staticProperties = pattern.properties
953
+ .filter((property) => property.key.kind !== 'computed')
954
+ .map((property) =>
955
+ `${formatPatternTypeKey(property.key)}: ${typeConstraintForPattern(property.pattern)}`
956
+ );
957
+ if (staticProperties.length === 0) {
958
+ return 'object';
959
+ }
960
+ return `{ ${staticProperties.join('; ')} }`;
961
+ }
962
+
963
+ function typeConstraintForPattern(pattern: MatchPattern): string {
964
+ switch (pattern.kind) {
965
+ case 'binding':
966
+ case 'wildcard':
967
+ return 'unknown';
968
+ case 'literal':
969
+ return pattern.code;
970
+ case 'typeof':
971
+ return typeofTypeConstraint(pattern.typeName);
972
+ case 'instanceof':
973
+ return pattern.narrowedTypeText ?? fallbackNarrowedTypeForClass(pattern.className);
974
+ case 'object':
975
+ return objectTypeConstraint(pattern);
976
+ case 'array':
977
+ return arrayTypeConstraint(pattern);
978
+ }
979
+ }
980
+
981
+ function narrowedTypeForPattern(scrutineeType: string, pattern: MatchPattern): string {
982
+ switch (pattern.kind) {
983
+ case 'binding':
984
+ case 'wildcard':
985
+ return scrutineeType;
986
+ case 'literal':
987
+ return `Extract<${scrutineeType}, ${pattern.code}>`;
988
+ case 'typeof':
989
+ return `Extract<${scrutineeType}, ${typeofTypeConstraint(pattern.typeName)}>`;
990
+ case 'instanceof':
991
+ return `Extract<${scrutineeType}, ${pattern.narrowedTypeText ?? fallbackNarrowedTypeForClass(pattern.className)}>`;
992
+ case 'object':
993
+ return `Extract<${scrutineeType}, ${objectTypeConstraint(pattern)}>`;
994
+ case 'array':
995
+ return `Extract<${scrutineeType}, ${arrayTypeConstraint(pattern)}>`;
996
+ }
997
+ }
998
+
999
+ function usesNativeControlFlowNarrowing(pattern: MatchPattern): boolean {
1000
+ switch (pattern.kind) {
1001
+ case 'binding':
1002
+ case 'instanceof':
1003
+ case 'literal':
1004
+ case 'wildcard':
1005
+ return true;
1006
+ case 'typeof':
1007
+ return !MATCH_MACHINE_NUMERIC_RUNTIME_KINDS.has(pattern.typeName);
1008
+ case 'array':
1009
+ case 'object':
1010
+ return false;
1011
+ }
1012
+ }
1013
+
1014
+ function lowerArrayMatchArm(arm: ArrayMatchArm, subjectExpr: string): string {
1015
+ if (arm.isCatchAll) {
1016
+ const successLines = arm.emittedGuardText
1017
+ ? wrapGuard(`(${arm.emittedGuardText})(${subjectExpr})`, [
1018
+ `return (${arm.emittedArmText})(${subjectExpr});`,
1019
+ ])
1020
+ : [`return (${arm.emittedArmText})(${subjectExpr});`];
1021
+ return successLines.join('\n');
1022
+ }
1023
+
1024
+ return arm.patterns.map((pattern) => {
1025
+ const narrowedSubjectExpr = usesNativeControlFlowNarrowing(pattern)
1026
+ ? subjectExpr
1027
+ : `(${subjectExpr} as ${narrowedTypeForPattern(arm.fallbackTypeText, pattern)})`;
1028
+ const successLines = arm.emittedGuardText
1029
+ ? wrapGuard(`(${arm.emittedGuardText})(${narrowedSubjectExpr})`, [
1030
+ `return (${arm.emittedArmText})(${narrowedSubjectExpr});`,
1031
+ ])
1032
+ : [`return (${arm.emittedArmText})(${narrowedSubjectExpr});`];
1033
+ return lowerPattern(pattern, subjectExpr, successLines, collectLoweringState(pattern)).join('\n');
1034
+ }).join('\n');
1035
+ }
1036
+
1037
+ export function semanticTokensForMatchMacro(
1038
+ ctx: MacroSemanticTokensContext,
1039
+ ): readonly MacroSemanticToken[] {
1040
+ const node = ctx.node as InvocationSyntax;
1041
+ const armArraySyntax = node.args[1]?.asArrayLiteral();
1042
+ if (!armArraySyntax) {
1043
+ return [];
1044
+ }
1045
+
1046
+ const tokens: MacroSemanticToken[] = [];
1047
+ for (const element of armArraySyntax.elements) {
1048
+ const expression = element.expression();
1049
+ if (element.isSpread || expression === null) {
1050
+ continue;
1051
+ }
1052
+ appendArmSemanticTokens(tokens, expression);
1053
+ }
1054
+
1055
+ return tokens;
1056
+ }
1057
+
1058
+ export function hoverMatchMacro(ctx: MacroHoverContext): MacroHoverResult | null {
1059
+ return {
1060
+ contents: [
1061
+ '**macro** `Match`',
1062
+ '',
1063
+ 'Evaluates the scrutinee once and returns the first matching arm.',
1064
+ '',
1065
+ 'Preferred form:',
1066
+ '- `Match (value) [ ({ value }: Ok) => value, (x: string) => x.length, (_) => 0 ]`',
1067
+ '- guards layer through `where(arm, predicate)`',
1068
+ ].join('\n'),
1069
+ };
1070
+ }
1071
+
1072
+ export function hoverMatchMacroPosition(
1073
+ ctx: MacroPositionHoverContext,
1074
+ ): MacroHoverResult | null {
1075
+ const invocation = ctx.node as InvocationSyntax;
1076
+ const armArrayExpr = invocation.args[1]?.asArrayLiteral();
1077
+ if (!armArrayExpr) {
1078
+ return null;
1079
+ }
1080
+
1081
+ const sourcePosition = ctx.node.span.start + ctx.offset;
1082
+ const invocationText = invocation.text();
1083
+ const invocationTextOffset = sourcePosition - invocation.span.start;
1084
+ const fallbackTypeText = ctx.macro.semantics.argType(0)?.displayText ?? 'unknown';
1085
+ for (const element of armArrayExpr.elements) {
1086
+ if (element.isSpread) {
1087
+ continue;
1088
+ }
1089
+ const expression = element.expression();
1090
+ if (!expression) {
1091
+ continue;
1092
+ }
1093
+ const whereCall = expression.unparenthesized().asCall();
1094
+ const armNode = whereCall?.callee.asIdentifier() === 'where'
1095
+ ? (whereCall.args[0] ?? expression)
1096
+ : expression;
1097
+ const armFunction = armNode.asFunction();
1098
+ const parameter = armFunction?.parameters[0];
1099
+ if (!parameter) {
1100
+ continue;
1101
+ }
1102
+ const armTypeText = parameter.hasExplicitType()
1103
+ ? parameter.explicitType()?.text() ?? fallbackTypeText
1104
+ : fallbackTypeText;
1105
+
1106
+ if (!parameter.hasExplicitType()) {
1107
+ for (const binding of parameter.bindingIdentifiers()) {
1108
+ if (spanContains(binding.span, sourcePosition)) {
1109
+ return {
1110
+ contents: `\`\`\`ts\n${binding.name}: ${armTypeText}\n\`\`\``,
1111
+ };
1112
+ }
1113
+ if (
1114
+ identifierAtOffsetEquals(
1115
+ invocationText,
1116
+ invocationTextOffset,
1117
+ binding.name,
1118
+ ) && isPositionInsideFunctionBody(armFunction, sourcePosition)
1119
+ ) {
1120
+ return {
1121
+ contents: `\`\`\`ts\n${binding.name}: ${armTypeText}\n\`\`\``,
1122
+ };
1123
+ }
1124
+ }
1125
+ }
1126
+
1127
+ const guardFunction = whereCall?.callee.asIdentifier() === 'where'
1128
+ ? whereCall.args[1]?.asFunction() ?? null
1129
+ : null;
1130
+ const guardParameter = guardFunction?.parameters[0];
1131
+ if (!guardParameter || guardParameter.hasExplicitType()) {
1132
+ continue;
1133
+ }
1134
+ for (const binding of guardParameter.bindingIdentifiers()) {
1135
+ if (spanContains(binding.span, sourcePosition)) {
1136
+ return {
1137
+ contents: `\`\`\`ts\n${binding.name}: ${armTypeText}\n\`\`\``,
1138
+ };
1139
+ }
1140
+ if (
1141
+ identifierAtOffsetEquals(
1142
+ invocationText,
1143
+ invocationTextOffset,
1144
+ binding.name,
1145
+ ) && isPositionInsideFunctionBody(guardFunction, sourcePosition)
1146
+ ) {
1147
+ return {
1148
+ contents: `\`\`\`ts\n${binding.name}: ${armTypeText}\n\`\`\``,
1149
+ };
1150
+ }
1151
+ }
1152
+ }
1153
+
1154
+ return null;
1155
+ }
1156
+
1157
+ function isIdentifierPart(character: string | undefined): boolean {
1158
+ return character !== undefined && /[\p{ID_Continue}_$\u200C\u200D]/u.test(character);
1159
+ }
1160
+
1161
+ function identifierAtOffsetEquals(text: string, offset: number, name: string): boolean {
1162
+ if (offset < 0 || offset >= text.length) {
1163
+ return false;
1164
+ }
1165
+ const start = offset;
1166
+ const end = offset + name.length;
1167
+ if (text.slice(start, end) !== name) {
1168
+ return false;
1169
+ }
1170
+ const before = start > 0 ? text[start - 1] : undefined;
1171
+ const after = end < text.length ? text[end] : undefined;
1172
+ return !isIdentifierPart(before) && !isIdentifierPart(after);
1173
+ }
1174
+
1175
+ function isPositionInsideFunctionBody(
1176
+ fn: MacroFunctionExprSyntax | null,
1177
+ sourcePosition: number,
1178
+ ): boolean {
1179
+ if (!fn) {
1180
+ return false;
1181
+ }
1182
+ const blockBody = fn.body();
1183
+ if (blockBody && spanContains(blockBody.span, sourcePosition)) {
1184
+ return true;
1185
+ }
1186
+ const returnedExpr = fn.returnedExpr();
1187
+ if (returnedExpr && spanContains(returnedExpr.span, sourcePosition)) {
1188
+ return true;
1189
+ }
1190
+ const returnedJsx = fn.returnedJsx();
1191
+ return returnedJsx ? spanContains(returnedJsx.span, sourcePosition) : false;
1192
+ }
1193
+
1194
+ function expandArrayMatchMacro(
1195
+ ctx: MacroContext,
1196
+ valueExpr: ExprSyntax,
1197
+ armArrayExpr: MacroArrayLiteralExprSyntax,
1198
+ ) {
1199
+ const arms = parseArrayMatchArms(ctx, armArrayExpr);
1200
+ validateArrayMatchArms(ctx, arms);
1201
+
1202
+ const scrutinee = '__sts_match_value';
1203
+ const armCode = arms.map((arm) => lowerArrayMatchArm(arm, scrutinee)).join('\n');
1204
+
1205
+ return ctx.output.expr(ctx.quote.expr`
1206
+ (() => {
1207
+ const ${scrutinee} = (${valueExpr.text()});
1208
+ ${armCode}
1209
+ throw new Error("Match reached an unexpected non-exhaustive state.");
1210
+ })()
1211
+ `);
1212
+ }
1213
+
1214
+ export function expandMatchMacro(
1215
+ ctx: MacroContext,
1216
+ valueExpr: ExprSyntax,
1217
+ armArrayExpr: MacroArrayLiteralExprSyntax,
1218
+ ) {
1219
+ return expandArrayMatchMacro(ctx, valueExpr, armArrayExpr);
1220
+ }