mt-lang 0.2.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 (258) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/AUTHORS +3 -0
  4. data/Gemfile +19 -0
  5. data/Gemfile.lock +82 -0
  6. data/LICENSE +21 -0
  7. data/README.md +1208 -0
  8. data/Rakefile +332 -0
  9. data/bin/mtc +8 -0
  10. data/bin/profile-mtc-checks +133 -0
  11. data/bin/tracy-profiler +0 -0
  12. data/docs/build-guide.md +536 -0
  13. data/docs/index.html +2778 -0
  14. data/docs/language-design.md +1519 -0
  15. data/docs/language-manual.md +1534 -0
  16. data/lib/milk_tea/base.rb +49 -0
  17. data/lib/milk_tea/bindings/bindgen/ast_parser.rb +398 -0
  18. data/lib/milk_tea/bindings/bindgen/declaration.rb +319 -0
  19. data/lib/milk_tea/bindings/bindgen/emitter.rb +387 -0
  20. data/lib/milk_tea/bindings/bindgen/overrides.rb +134 -0
  21. data/lib/milk_tea/bindings/bindgen/type_mapper.rb +622 -0
  22. data/lib/milk_tea/bindings/bindgen.rb +207 -0
  23. data/lib/milk_tea/bindings/cli.rb +121 -0
  24. data/lib/milk_tea/bindings/imported_bindings/defaults.rb +210 -0
  25. data/lib/milk_tea/bindings/imported_bindings/generator.rb +1114 -0
  26. data/lib/milk_tea/bindings/imported_bindings/method_source.rb +190 -0
  27. data/lib/milk_tea/bindings/imported_bindings/naming.rb +286 -0
  28. data/lib/milk_tea/bindings/imported_bindings.rb +215 -0
  29. data/lib/milk_tea/bindings/opengl_registry.rb +547 -0
  30. data/lib/milk_tea/bindings/raw_bindings/defaults.rb +1338 -0
  31. data/lib/milk_tea/bindings/raw_bindings.rb +269 -0
  32. data/lib/milk_tea/bindings/steamworks.rb +629 -0
  33. data/lib/milk_tea/bindings/upstream_sources.rb +352 -0
  34. data/lib/milk_tea/bindings/vendored_box2d.rb +79 -0
  35. data/lib/milk_tea/bindings/vendored_c_library.rb +322 -0
  36. data/lib/milk_tea/bindings/vendored_cjson.rb +52 -0
  37. data/lib/milk_tea/bindings/vendored_flecs.rb +78 -0
  38. data/lib/milk_tea/bindings/vendored_glfw.rb +77 -0
  39. data/lib/milk_tea/bindings/vendored_libuv.rb +75 -0
  40. data/lib/milk_tea/bindings/vendored_pcre2.rb +84 -0
  41. data/lib/milk_tea/bindings/vendored_raylib.rb +131 -0
  42. data/lib/milk_tea/bindings/vendored_sdl3.rb +78 -0
  43. data/lib/milk_tea/bindings/vendored_steamworks.rb +71 -0
  44. data/lib/milk_tea/bindings/vendored_tool.rb +71 -0
  45. data/lib/milk_tea/bindings/vendored_tools.rb +23 -0
  46. data/lib/milk_tea/bindings/vendored_tracy.rb +37 -0
  47. data/lib/milk_tea/bindings.rb +23 -0
  48. data/lib/milk_tea/core/ast.rb +311 -0
  49. data/lib/milk_tea/core/async_runtime_installer.rb +28 -0
  50. data/lib/milk_tea/core/binding_types.rb +18 -0
  51. data/lib/milk_tea/core/bindings/attribute_binding.rb +58 -0
  52. data/lib/milk_tea/core/bindings/function_binding.rb +5 -0
  53. data/lib/milk_tea/core/bindings/module_binding.rb +58 -0
  54. data/lib/milk_tea/core/bindings/value_binding.rb +21 -0
  55. data/lib/milk_tea/core/c_backend/aggregate_utils.rb +103 -0
  56. data/lib/milk_tea/core/c_backend/control_flow_emission.rb +412 -0
  57. data/lib/milk_tea/core/c_backend/expressions.rb +468 -0
  58. data/lib/milk_tea/core/c_backend/feature_detection.rb +483 -0
  59. data/lib/milk_tea/core/c_backend/reachability.rb +398 -0
  60. data/lib/milk_tea/core/c_backend/reinterpret.rb +226 -0
  61. data/lib/milk_tea/core/c_backend/runtime_helpers.rb +1080 -0
  62. data/lib/milk_tea/core/c_backend/statements.rb +563 -0
  63. data/lib/milk_tea/core/c_backend/type_collectors.rb +1545 -0
  64. data/lib/milk_tea/core/c_backend/type_declaration.rb +223 -0
  65. data/lib/milk_tea/core/c_backend/type_system.rb +345 -0
  66. data/lib/milk_tea/core/c_backend.rb +287 -0
  67. data/lib/milk_tea/core/compatibility_helpers.rb +79 -0
  68. data/lib/milk_tea/core/compile_time/const_eval.rb +187 -0
  69. data/lib/milk_tea/core/compile_time.rb +329 -0
  70. data/lib/milk_tea/core/control_flow/builder.rb +582 -0
  71. data/lib/milk_tea/core/control_flow/constant_propagation.rb +143 -0
  72. data/lib/milk_tea/core/control_flow/dataflow.rb +74 -0
  73. data/lib/milk_tea/core/control_flow/definite_assignment.rb +79 -0
  74. data/lib/milk_tea/core/control_flow/graph.rb +90 -0
  75. data/lib/milk_tea/core/control_flow/liveness.rb +24 -0
  76. data/lib/milk_tea/core/control_flow/nullability_flow.rb +43 -0
  77. data/lib/milk_tea/core/control_flow/reachability.rb +22 -0
  78. data/lib/milk_tea/core/control_flow/termination.rb +31 -0
  79. data/lib/milk_tea/core/control_flow.rb +34 -0
  80. data/lib/milk_tea/core/cst.rb +48 -0
  81. data/lib/milk_tea/core/cst_builder.rb +19 -0
  82. data/lib/milk_tea/core/ir.rb +85 -0
  83. data/lib/milk_tea/core/keywords.rb +97 -0
  84. data/lib/milk_tea/core/lexer/character_classes.rb +60 -0
  85. data/lib/milk_tea/core/lexer/format_strings.rb +225 -0
  86. data/lib/milk_tea/core/lexer/heredocs.rb +199 -0
  87. data/lib/milk_tea/core/lexer/indentation.rb +62 -0
  88. data/lib/milk_tea/core/lexer/numbers.rb +96 -0
  89. data/lib/milk_tea/core/lexer/recovery.rb +32 -0
  90. data/lib/milk_tea/core/lexer/strings.rb +167 -0
  91. data/lib/milk_tea/core/lexer/symbols.rb +71 -0
  92. data/lib/milk_tea/core/lexer/trivia.rb +53 -0
  93. data/lib/milk_tea/core/lexer.rb +430 -0
  94. data/lib/milk_tea/core/lowering/artifacts.rb +26 -0
  95. data/lib/milk_tea/core/lowering/async/analysis.rb +245 -0
  96. data/lib/milk_tea/core/lowering/async/lowering.rb +1399 -0
  97. data/lib/milk_tea/core/lowering/async/normalization.rb +459 -0
  98. data/lib/milk_tea/core/lowering/async.rb +714 -0
  99. data/lib/milk_tea/core/lowering/block.rb +1052 -0
  100. data/lib/milk_tea/core/lowering/calls.rb +1565 -0
  101. data/lib/milk_tea/core/lowering/declarations.rb +214 -0
  102. data/lib/milk_tea/core/lowering/dyn.rb +206 -0
  103. data/lib/milk_tea/core/lowering/events.rb +1054 -0
  104. data/lib/milk_tea/core/lowering/expressions.rb +1645 -0
  105. data/lib/milk_tea/core/lowering/foreign_cstr.rb +206 -0
  106. data/lib/milk_tea/core/lowering/functions.rb +242 -0
  107. data/lib/milk_tea/core/lowering/loops.rb +1087 -0
  108. data/lib/milk_tea/core/lowering/lowering_context.rb +80 -0
  109. data/lib/milk_tea/core/lowering/proc.rb +419 -0
  110. data/lib/milk_tea/core/lowering/resolve.rb +2516 -0
  111. data/lib/milk_tea/core/lowering/scans.rb +220 -0
  112. data/lib/milk_tea/core/lowering/str_buffer.rb +125 -0
  113. data/lib/milk_tea/core/lowering/utils.rb +1453 -0
  114. data/lib/milk_tea/core/lowering.rb +378 -0
  115. data/lib/milk_tea/core/module_binder.rb +181 -0
  116. data/lib/milk_tea/core/module_loader/errors.rb +21 -0
  117. data/lib/milk_tea/core/module_loader.rb +479 -0
  118. data/lib/milk_tea/core/module_path_resolver.rb +153 -0
  119. data/lib/milk_tea/core/module_roots.rb +88 -0
  120. data/lib/milk_tea/core/parser/attributes.rb +71 -0
  121. data/lib/milk_tea/core/parser/blocks.rb +119 -0
  122. data/lib/milk_tea/core/parser/declarations.rb +749 -0
  123. data/lib/milk_tea/core/parser/expressions.rb +624 -0
  124. data/lib/milk_tea/core/parser/recovery.rb +131 -0
  125. data/lib/milk_tea/core/parser/statements.rb +756 -0
  126. data/lib/milk_tea/core/parser/types.rb +271 -0
  127. data/lib/milk_tea/core/parser.rb +400 -0
  128. data/lib/milk_tea/core/prelude_installer.rb +29 -0
  129. data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +917 -0
  130. data/lib/milk_tea/core/pretty_printer/base_formatter.rb +87 -0
  131. data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +300 -0
  132. data/lib/milk_tea/core/pretty_printer.rb +17 -0
  133. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +314 -0
  134. data/lib/milk_tea/core/semantic_analyzer/attributes.rb +184 -0
  135. data/lib/milk_tea/core/semantic_analyzer/calls.rb +992 -0
  136. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1735 -0
  137. data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +355 -0
  138. data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +155 -0
  139. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +354 -0
  140. data/lib/milk_tea/core/semantic_analyzer/generics.rb +383 -0
  141. data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +78 -0
  142. data/lib/milk_tea/core/semantic_analyzer/module_context.rb +35 -0
  143. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +1438 -0
  144. data/lib/milk_tea/core/semantic_analyzer/nullability.rb +421 -0
  145. data/lib/milk_tea/core/semantic_analyzer/statements.rb +1308 -0
  146. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +588 -0
  147. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +307 -0
  148. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +851 -0
  149. data/lib/milk_tea/core/semantic_analyzer.rb +327 -0
  150. data/lib/milk_tea/core/token.rb +26 -0
  151. data/lib/milk_tea/core/token_stream.rb +30 -0
  152. data/lib/milk_tea/core/types/layout.rb +243 -0
  153. data/lib/milk_tea/core/types/predicates.rb +609 -0
  154. data/lib/milk_tea/core/types/registry.rb +83 -0
  155. data/lib/milk_tea/core/types/types.rb +1696 -0
  156. data/lib/milk_tea/core/types/visitor.rb +442 -0
  157. data/lib/milk_tea/core.rb +25 -0
  158. data/lib/milk_tea/dap/backends/lldb_dap.rb +158 -0
  159. data/lib/milk_tea/dap/protocol.rb +58 -0
  160. data/lib/milk_tea/dap/server/breakpoints.rb +66 -0
  161. data/lib/milk_tea/dap/server/debug_map.rb +291 -0
  162. data/lib/milk_tea/dap/server/handlers.rb +374 -0
  163. data/lib/milk_tea/dap/server/launch.rb +261 -0
  164. data/lib/milk_tea/dap/server/lldb_backend.rb +380 -0
  165. data/lib/milk_tea/dap/server/pause_diagnostics.rb +109 -0
  166. data/lib/milk_tea/dap/server/utilities.rb +160 -0
  167. data/lib/milk_tea/dap/server/wire.rb +55 -0
  168. data/lib/milk_tea/dap/server.rb +131 -0
  169. data/lib/milk_tea/dap/session.rb +152 -0
  170. data/lib/milk_tea/dap.rb +6 -0
  171. data/lib/milk_tea/lsp/dependency_resolution.rb +52 -0
  172. data/lib/milk_tea/lsp/diagnostics.rb +611 -0
  173. data/lib/milk_tea/lsp/protocol.rb +104 -0
  174. data/lib/milk_tea/lsp/server/call_hierarchy.rb +274 -0
  175. data/lib/milk_tea/lsp/server/code_actions.rb +446 -0
  176. data/lib/milk_tea/lsp/server/code_lens.rb +97 -0
  177. data/lib/milk_tea/lsp/server/completion.rb +1099 -0
  178. data/lib/milk_tea/lsp/server/configuration.rb +167 -0
  179. data/lib/milk_tea/lsp/server/debug_info.rb +45 -0
  180. data/lib/milk_tea/lsp/server/definition.rb +779 -0
  181. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +239 -0
  182. data/lib/milk_tea/lsp/server/execute_command.rb +25 -0
  183. data/lib/milk_tea/lsp/server/folding_range.rb +153 -0
  184. data/lib/milk_tea/lsp/server/formatting.rb +575 -0
  185. data/lib/milk_tea/lsp/server/hover.rb +1465 -0
  186. data/lib/milk_tea/lsp/server/inlay_hints.rb +204 -0
  187. data/lib/milk_tea/lsp/server/lifecycle.rb +234 -0
  188. data/lib/milk_tea/lsp/server/linked_editing_range.rb +43 -0
  189. data/lib/milk_tea/lsp/server/on_type_formatting.rb +73 -0
  190. data/lib/milk_tea/lsp/server/progress.rb +47 -0
  191. data/lib/milk_tea/lsp/server/references.rb +433 -0
  192. data/lib/milk_tea/lsp/server/rename.rb +598 -0
  193. data/lib/milk_tea/lsp/server/selection_range.rb +130 -0
  194. data/lib/milk_tea/lsp/server/semantic_tokens.rb +1745 -0
  195. data/lib/milk_tea/lsp/server/signature_help.rb +200 -0
  196. data/lib/milk_tea/lsp/server/text_documents.rb +125 -0
  197. data/lib/milk_tea/lsp/server/type_hierarchy.rb +167 -0
  198. data/lib/milk_tea/lsp/server/utilities.rb +520 -0
  199. data/lib/milk_tea/lsp/server.rb +415 -0
  200. data/lib/milk_tea/lsp/workspace/analysis.rb +209 -0
  201. data/lib/milk_tea/lsp/workspace/caches.rb +260 -0
  202. data/lib/milk_tea/lsp/workspace/collection.rb +98 -0
  203. data/lib/milk_tea/lsp/workspace/definition_index.rb +184 -0
  204. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +282 -0
  205. data/lib/milk_tea/lsp/workspace/store.rb +154 -0
  206. data/lib/milk_tea/lsp/workspace/utilities.rb +490 -0
  207. data/lib/milk_tea/lsp/workspace.rb +127 -0
  208. data/lib/milk_tea/lsp.rb +13 -0
  209. data/lib/milk_tea/packages/atomic_write.rb +63 -0
  210. data/lib/milk_tea/packages/dependency_solver.rb +194 -0
  211. data/lib/milk_tea/packages/graph.rb +139 -0
  212. data/lib/milk_tea/packages/lock.rb +421 -0
  213. data/lib/milk_tea/packages/manager_cli.rb +485 -0
  214. data/lib/milk_tea/packages/manifest.rb +356 -0
  215. data/lib/milk_tea/packages/manifest_editor.rb +134 -0
  216. data/lib/milk_tea/packages/registry_metadata_provider.rb +34 -0
  217. data/lib/milk_tea/packages/registry_store.rb +420 -0
  218. data/lib/milk_tea/packages/services.rb +41 -0
  219. data/lib/milk_tea/packages/source_cache.rb +71 -0
  220. data/lib/milk_tea/packages/source_fetcher.rb +124 -0
  221. data/lib/milk_tea/packages/source_resolver.rb +389 -0
  222. data/lib/milk_tea/packages/version.rb +164 -0
  223. data/lib/milk_tea/packages.rb +16 -0
  224. data/lib/milk_tea/tooling/asset_pack.rb +141 -0
  225. data/lib/milk_tea/tooling/build.rb +1124 -0
  226. data/lib/milk_tea/tooling/build_cache.rb +240 -0
  227. data/lib/milk_tea/tooling/cli.rb +2688 -0
  228. data/lib/milk_tea/tooling/cst_formatter.rb +13 -0
  229. data/lib/milk_tea/tooling/debug_info_formatter.rb +456 -0
  230. data/lib/milk_tea/tooling/debug_map.rb +248 -0
  231. data/lib/milk_tea/tooling/docs_app.rb +369 -0
  232. data/lib/milk_tea/tooling/error_formatter.rb +86 -0
  233. data/lib/milk_tea/tooling/formatter.rb +787 -0
  234. data/lib/milk_tea/tooling/linter/doc_tags.rb +212 -0
  235. data/lib/milk_tea/tooling/linter/fix_engine.rb +237 -0
  236. data/lib/milk_tea/tooling/linter/flow_rules.rb +380 -0
  237. data/lib/milk_tea/tooling/linter/imports_platform.rb +841 -0
  238. data/lib/milk_tea/tooling/linter/release_rules.rb +744 -0
  239. data/lib/milk_tea/tooling/linter/reserved_names.rb +199 -0
  240. data/lib/milk_tea/tooling/linter/rules.rb +593 -0
  241. data/lib/milk_tea/tooling/linter/source_helpers.rb +407 -0
  242. data/lib/milk_tea/tooling/linter/trailing_comma.rb +139 -0
  243. data/lib/milk_tea/tooling/linter/visitors.rb +1286 -0
  244. data/lib/milk_tea/tooling/linter.rb +798 -0
  245. data/lib/milk_tea/tooling/project_scaffold.rb +82 -0
  246. data/lib/milk_tea/tooling/public/css/docs.css +166 -0
  247. data/lib/milk_tea/tooling/public/js/docs.js +94 -0
  248. data/lib/milk_tea/tooling/run.rb +408 -0
  249. data/lib/milk_tea/tooling/templates/wasm_shell.html +48 -0
  250. data/lib/milk_tea/tooling/toolchain_cli.rb +157 -0
  251. data/lib/milk_tea/tooling/views/404.erb +7 -0
  252. data/lib/milk_tea/tooling/views/index.erb +87 -0
  253. data/lib/milk_tea/tooling/views/layout.erb +69 -0
  254. data/lib/milk_tea/tooling/views/module.erb +97 -0
  255. data/lib/milk_tea/tooling/views/stdlib.erb +21 -0
  256. data/lib/milk_tea/tooling.rb +20 -0
  257. data/lib/milk_tea.rb +8 -0
  258. metadata +426 -0
@@ -0,0 +1,1745 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module LSP
5
+ class Server
6
+ module ServerSemanticTokens
7
+ private
8
+
9
+ def handle_semantic_tokens_full(params)
10
+ uri = params.dig('textDocument', 'uri')
11
+ return { data: [] } unless uri
12
+
13
+ total_start = monotonic_time
14
+
15
+ content = @workspace.get_content(uri)
16
+ cache_key = content.hash
17
+ cached = @semantic_tokens_cache[uri]
18
+ if cached && cached[:content_hash] == cache_key
19
+ elapsed = elapsed_ms(total_start)
20
+ short_uri = shorten_uri(uri) || uri
21
+ log_perf_breakdown('textDocument/semanticTokens/full', elapsed,
22
+ "uri=#{short_uri} bytes=#{content.bytesize} lines=#{content.count("\n") + 1} cache=hit data_len=#{cached[:data].length}")
23
+ return { data: cached[:data] }
24
+ end
25
+
26
+ tokens_start = monotonic_time
27
+ tokens = @workspace.get_tokens(uri) || []
28
+ tokens_ms = elapsed_ms(tokens_start)
29
+
30
+ facts_start = monotonic_time
31
+ facts = @workspace.get_facts(uri, allow_last_good_fallback: semantic_tokens_allow_last_good_fallback?(uri))
32
+ facts_ms = elapsed_ms(facts_start)
33
+
34
+ build_start = monotonic_time
35
+ semantic_entries = build_semantic_token_entries(tokens, facts)
36
+ build_ms = elapsed_ms(build_start)
37
+
38
+ encode_start = monotonic_time
39
+ data = encode_semantic_tokens(semantic_entries)
40
+ encode_ms = elapsed_ms(encode_start)
41
+
42
+ @semantic_tokens_cache[uri] = { content_hash: cache_key, data: data }
43
+
44
+ result_id = next_semantic_token_result_id(uri)
45
+ @semantic_tokens_delta_cache[uri] = {
46
+ result_id: result_id,
47
+ content_hash: cache_key,
48
+ entries: semantic_entries,
49
+ }
50
+
51
+ elapsed = elapsed_ms(total_start)
52
+ short_uri = shorten_uri(uri) || uri
53
+ log_perf_breakdown('textDocument/semanticTokens/full', elapsed,
54
+ "uri=#{short_uri} bytes=#{content.bytesize} lines=#{content.count("\n") + 1} cache=miss tokens=#{tokens.length} entries=#{semantic_entries.length} data_len=#{data.length} facts=on stages_ms=tokens:#{tokens_ms},facts:#{facts_ms},build:#{build_ms},encode:#{encode_ms}")
55
+
56
+ { data: data }
57
+ rescue StandardError => e
58
+ warn "Error in semanticTokens/full handler: #{e.message}"
59
+ { data: [] }
60
+ end
61
+
62
+ def handle_semantic_tokens_delta(params)
63
+ uri = params.dig('textDocument', 'uri')
64
+ previous_result_id = params['previousResultId']
65
+ return handle_semantic_tokens_full(params) unless uri && previous_result_id
66
+
67
+ cached = @semantic_tokens_delta_cache[uri]
68
+ unless cached && cached[:result_id] == previous_result_id
69
+ return handle_semantic_tokens_full(params)
70
+ end
71
+
72
+ content = @workspace.get_content(uri)
73
+ cache_key = content.hash
74
+ if cached[:content_hash] == cache_key
75
+ return { resultId: cached[:result_id], edits: [] }
76
+ end
77
+
78
+ tokens = @workspace.get_tokens(uri) || []
79
+ facts = @workspace.get_facts(uri, allow_last_good_fallback: semantic_tokens_allow_last_good_fallback?(uri))
80
+ new_entries = build_semantic_token_entries(tokens, facts)
81
+
82
+ new_result_id = next_semantic_token_result_id(uri)
83
+ @semantic_tokens_delta_cache[uri] = {
84
+ result_id: new_result_id,
85
+ content_hash: cache_key,
86
+ entries: new_entries,
87
+ }
88
+
89
+ edits = compute_semantic_tokens_edits(cached[:entries], new_entries)
90
+ { resultId: new_result_id, edits: edits }
91
+ rescue StandardError => e
92
+ warn "Error in semanticTokens/full/delta handler: #{e.message}"
93
+ handle_semantic_tokens_full(params)
94
+ end
95
+
96
+ def handle_semantic_tokens_range(params)
97
+ uri = params.dig("textDocument", "uri")
98
+ range = params["range"]
99
+ return { data: [] } unless uri && range
100
+
101
+ content = @workspace.get_content(uri)
102
+ return { data: [] } unless content
103
+
104
+ tokens = @workspace.get_tokens(uri) || []
105
+ return { data: [] } if tokens.empty?
106
+
107
+ start_line = range.dig("start", "line") + 1
108
+ end_line = range.dig("end", "line") + 1
109
+
110
+ range_tokens = tokens.select do |t|
111
+ t.line >= start_line && t.line <= end_line &&
112
+ ![:newline, :indent, :dedent, :eof].include?(t.type)
113
+ end
114
+
115
+ facts = @workspace.get_facts(uri, allow_last_good_fallback: semantic_tokens_allow_last_good_fallback?(uri))
116
+ semantic_entries = build_semantic_token_entries(range_tokens, facts)
117
+
118
+ entries_in_range = semantic_entries.select do |entry|
119
+ entry[:line] >= start_line && entry[:line] <= end_line
120
+ end
121
+
122
+ data = encode_semantic_tokens(entries_in_range)
123
+ { data: data }
124
+ rescue StandardError => e
125
+ warn "Error in semanticTokens/range handler: #{e.message}"
126
+ { data: [] }
127
+ end
128
+
129
+ def build_semantic_token_entries(tokens, facts = nil)
130
+ # Precompute line → non-trivia tokens index so non_trivia_tokens_on_line
131
+ # is O(1) per call instead of O(n), turning the overall build from O(n²) to O(n).
132
+ trivia_types = Set[:newline, :indent, :dedent, :eof]
133
+ @tokens_by_line_cache = Hash.new { |h, k| h[k] = [] }
134
+ tokens.each { |t| @tokens_by_line_cache[t.line] << t unless trivia_types.include?(t.type) }
135
+ @attribute_name_semantic_overrides = build_attribute_name_semantic_overrides(tokens, facts)
136
+
137
+ entries = []
138
+
139
+ tokens.each_with_index do |tok, index|
140
+ next if [:newline, :indent, :dedent, :eof].include?(tok.type)
141
+
142
+ if tok.type == :fstring
143
+ next if embedded_heredoc_token?(tok)
144
+ fstring_interpolation_entries(tok, facts).each { |e| entries << e }
145
+ next
146
+ end
147
+
148
+ semantic_type, modifiers = classify_semantic_token(tokens, index, facts)
149
+ next unless semantic_type
150
+
151
+ token_semantic_entries(tok, semantic_type, modifiers).each { |entry| entries << entry }
152
+ end
153
+
154
+ entries.sort_by { |entry| [entry[:line], entry[:start_char]] }
155
+ ensure
156
+ @tokens_by_line_cache = nil
157
+ @attribute_name_semantic_overrides = nil
158
+ end
159
+
160
+ def fstring_interpolation_entries(fstring_tok, facts)
161
+ parts = fstring_tok.literal
162
+ return [{ line: fstring_tok.line - 1, start_char: fstring_tok.column - 1, length: fstring_tok.lexeme.length, type: :string, modifiers: [] }] unless parts.is_a?(Array)
163
+
164
+ result = []
165
+ fstr_line = fstring_tok.line - 1 # 0-indexed
166
+ fstr_col0 = fstring_tok.column - 1 # 0-indexed start of `f`
167
+ cursor = fstr_col0
168
+
169
+ parts.each do |part|
170
+ next unless part[:kind] == :expr
171
+
172
+ # part[:column] is 1-indexed column of the first char of the expression source
173
+ # (i.e. the char right after `#{`).
174
+ expr_col0 = part[:column] - 1 # 0-indexed
175
+ hash_col0 = expr_col0 - 2 # 0-indexed position of `#`
176
+
177
+ raw_len = part[:source].length + (part[:format_spec] ? 1 + part[:format_spec].length : 0)
178
+ rbrace_col0 = expr_col0 + raw_len # 0-indexed position of `}`
179
+
180
+ # :string for everything from cursor up to (but not including) `#`
181
+ text_len = hash_col0 - cursor
182
+ result << { line: fstr_line, start_char: cursor, length: text_len, type: :string, modifiers: [] } if text_len > 0
183
+
184
+ # classified entries for the expression source only (not format spec).
185
+ source = part[:source]
186
+ unless source.nil? || source.strip.empty?
187
+ begin
188
+ sub_tokens = interpolation_expression_tokens(part)
189
+ sub_tokens.each_with_index do |sub_tok, i|
190
+ sem_type, modifiers = classify_semantic_token(sub_tokens, i, facts)
191
+ next unless sem_type
192
+ result << {
193
+ line: sub_tok.line - 1,
194
+ start_char: sub_tok.column - 1,
195
+ length: sub_tok.lexeme.length,
196
+ type: sem_type,
197
+ modifiers: modifiers
198
+ }
199
+ end
200
+ rescue MilkTea::LexError
201
+ # Fall back to string coloring for malformed expression.
202
+ result << {
203
+ line: fstr_line,
204
+ start_char: expr_col0,
205
+ length: source.length,
206
+ type: :string,
207
+ modifiers: [],
208
+ }
209
+ end
210
+ end
211
+
212
+ # classified entries for format spec (if present), excluding the
213
+ # delimiter token so TextMate interpolation punctuation can style it.
214
+ if part[:format_spec]
215
+ spec_col0 = expr_col0 + source.length
216
+ # Format spec content (e.g., ".0", "3", ".5f") as individual token-like entries.
217
+ # Treat it as lexable content or just string for simplicity.
218
+ spec = part[:format_spec]
219
+ unless spec.empty?
220
+ begin
221
+ spec_tokens = MilkTea::Lexer.new(spec).lex
222
+ .reject { |t| [:newline, :indent, :dedent, :eof].include?(t.type) }
223
+ spec_tokens.each_with_index do |spec_tok, i|
224
+ spec_sem_type, spec_modifiers = classify_semantic_token(spec_tokens, i, facts)
225
+ next unless spec_sem_type
226
+ result << {
227
+ line: fstr_line,
228
+ start_char: spec_col0 + 1 + (spec_tok.column - 1),
229
+ length: spec_tok.lexeme.length,
230
+ type: spec_sem_type,
231
+ modifiers: spec_modifiers
232
+ }
233
+ end
234
+ rescue MilkTea::LexError
235
+ # Fall back: treat spec as a number/string token.
236
+ result << {
237
+ line: fstr_line,
238
+ start_char: spec_col0 + 1,
239
+ length: spec.length,
240
+ type: :number,
241
+ modifiers: []
242
+ }
243
+ end
244
+ end
245
+ end
246
+
247
+ cursor = rbrace_col0 + 1
248
+ end
249
+
250
+ # :string for tail text + closing `"`
251
+ fstr_end_col0 = fstr_col0 + fstring_tok.lexeme.length - 1
252
+ tail_len = fstr_end_col0 - cursor + 1
253
+ result << { line: fstr_line, start_char: cursor, length: tail_len, type: :string, modifiers: [] } if tail_len > 0
254
+
255
+ result
256
+ end
257
+
258
+ def classify_semantic_token(tokens, index, facts = nil)
259
+ tok = tokens[index]
260
+
261
+ if tok.type == :identifier || namespace_keyword_token?(tokens, index)
262
+ return classify_name_semantic(tok.lexeme, tokens, index, facts)
263
+ end
264
+
265
+ if [:string, :cstring].include?(tok.type)
266
+ return [nil, []] if embedded_heredoc_token?(tok)
267
+
268
+ return [:string, []]
269
+ end
270
+
271
+ if tok.type == :comment
272
+ return [:comment, []]
273
+ end
274
+
275
+ if [:integer, :float].include?(tok.type)
276
+ return [:number, []]
277
+ end
278
+
279
+ if KEYWORD_TOKEN_TYPES.include?(tok.type)
280
+ return [:keyword, []]
281
+ end
282
+
283
+ if OPERATOR_TOKEN_TYPES.include?(tok.type)
284
+ return [:operator, []]
285
+ end
286
+
287
+ [nil, []]
288
+ end
289
+
290
+ def embedded_heredoc_token?(token)
291
+ return false unless [:string, :cstring, :fstring].include?(token.type)
292
+
293
+ tag = token.lexeme[/\A(?:f|c)?<<-([A-Za-z_][A-Za-z0-9_]*)[ \t]*\n/, 1]
294
+ return false if tag.nil?
295
+
296
+ %w[GLSL VERT FRAG COMP JSON JSONC SQL HTML MT].include?(tag)
297
+ end
298
+
299
+ def token_semantic_entries(token, semantic_type, modifiers)
300
+ token.lexeme.split("\n", -1).each_with_index.filter_map do |segment, index|
301
+ next if segment.empty?
302
+
303
+ {
304
+ line: token.line - 1 + index,
305
+ start_char: index.zero? ? (token.column - 1) : 0,
306
+ length: segment.length,
307
+ type: semantic_type,
308
+ modifiers: modifiers
309
+ }
310
+ end
311
+ end
312
+
313
+ def classify_name_semantic(name, tokens, index, facts = nil)
314
+ tok = tokens[index]
315
+ prev_tok = previous_non_trivia_token(tokens, index)
316
+ next_tok = next_non_trivia_token(tokens, index + 1)
317
+ parameter_declaration = parameter_declaration_token?(tokens, index)
318
+ user_defined_function = facts ? facts.functions.key?(name) : lexically_declared_free_function_name?(tokens, name)
319
+
320
+ if @attribute_name_semantic_overrides && (override = @attribute_name_semantic_overrides[[tok.line, tok.column]])
321
+ return override
322
+ end
323
+
324
+ if (import_info = import_path_info_at(tokens, index, allow_keywords: true))
325
+ modifiers = []
326
+ modifiers << 'declaration' if import_info[:role] == :alias
327
+ return [:namespace, modifiers]
328
+ end
329
+
330
+ return [:namespace, []] if module_declaration_path_token?(tokens, index, allow_keywords: true)
331
+
332
+ if prev_tok && [:function, :fn, :proc].include?(prev_tok.type)
333
+ return [:function, ['declaration']]
334
+ end
335
+
336
+ if prev_tok && [:struct, :union, :enum, :flags, :variant, :type, :opaque, :interface].include?(prev_tok.type)
337
+ return [:type, ['declaration']]
338
+ end
339
+
340
+ return [:variable, []] if name == "_"
341
+
342
+ if prev_tok&.type == :event
343
+ return struct_event_declaration_token?(tokens, index) ? [:property, ['declaration']] : [:variable, ['declaration']]
344
+ end
345
+
346
+ if prev_tok&.type == :const
347
+ return [:variable, ['declaration', 'readonly']]
348
+ end
349
+
350
+ if prev_tok&.type == :let
351
+ return [:variable, ['declaration', 'readonly']] unless next_tok&.type == :lparen
352
+ end
353
+
354
+ if prev_tok&.type == :var
355
+ return [:variable, ['declaration']] unless next_tok&.type == :lparen
356
+ end
357
+
358
+ if prev_tok&.type == :for
359
+ return [:variable, ['declaration', 'readonly']]
360
+ end
361
+
362
+ return [:variable, ['declaration', 'readonly']] if match_arm_binding_token?(tokens, index)
363
+ return [:parameter, ['declaration']] if callable_parameter_declaration_token?(tokens, index)
364
+ return [:property, ['declaration']] if variant_payload_field_declaration_token?(tokens, index)
365
+ return [:property, ['declaration']] if field_declaration_token?(tokens, index)
366
+
367
+ if destructure_let_binding?(tokens, index)
368
+ return [:variable, ['declaration', 'readonly']]
369
+ end
370
+
371
+ if facts
372
+ return [:typeParameter, ['declaration']] if type_parameter_declaration_token?(facts, tokens, index)
373
+ return [:typeParameter, []] if type_parameter_reference_token?(facts, tokens, index)
374
+ end
375
+
376
+ return [:property, []] if named_argument_label_token?(tokens, index) && named_argument_label_in_type_constructor?(tokens, index, facts)
377
+ return [:parameter, []] if named_argument_label_token?(tokens, index)
378
+
379
+ if facts && prev_tok&.type != :dot && (generic_binding = generic_function_lexical_binding_semantic(facts, tok))
380
+ return generic_binding
381
+ end
382
+
383
+ if next_tok&.type == :dot && facts
384
+ return [:type, []] if known_type_name?(facts, name)
385
+ return [:type, []] if facts.interfaces.key?(name)
386
+ return [:namespace, []] if facts.imports.key?(name)
387
+
388
+ if (binding = local_semantic_value_binding(facts, tok, allow_same_line_future: parameter_declaration))
389
+ return semantic_value_binding_entry(binding, declaration: binding.kind == :param && parameter_declaration)
390
+ end
391
+
392
+ if (binding = facts.values[name])
393
+ return semantic_value_binding_entry(binding)
394
+ end
395
+ end
396
+
397
+ if facts && (known_type_name?(facts, name) || facts.interfaces.key?(name)) && identifier_in_type_argument_position?(tokens, index)
398
+ return [:type, []]
399
+ end
400
+
401
+ return [:enumMember, ['declaration']] if variant_enum_member_declaration?(tokens, index)
402
+
403
+ if prev_tok&.type == :dot
404
+ if facts
405
+ module_binding = imported_module_binding_for_member(tokens, index, facts)
406
+ if module_binding
407
+ if module_binding.functions.key?(name)
408
+ return [:function, []] if next_tok&.type == :lparen || specialized_call_with_type_args?(tokens, index)
409
+ return [:function, []] if next_tok&.type == :lbracket
410
+ return [:function, []] if imported_module_function_value_member_access_site?(facts, tokens, index)
411
+ return [:property, []]
412
+ end
413
+ return [:type, []] if module_binding.types.key?(name)
414
+ return [:type, []] if module_binding.interfaces.key?(name)
415
+ if (value_binding = module_binding.values[name])
416
+ modifiers = []
417
+ modifiers << 'readonly' if value_binding.respond_to?(:mutable) && value_binding.mutable == false
418
+ return [:variable, modifiers]
419
+ end
420
+ return [:namespace, []] if facts.imports.key?(name)
421
+ end
422
+
423
+ return [:type, []] if dot_nested_type_member?(tokens, index, facts)
424
+ return [:property, []] if callable_field_member_access?(name, tokens, index, facts)
425
+ return [:method, []] if static_type_member_access?(tokens, index, facts)
426
+ end
427
+
428
+ return [:enumMember, []] if type_name_member_access?(tokens, index, facts)
429
+ return [:method, []] if next_tok&.type == :lparen || specialized_call_with_type_args?(tokens, index)
430
+ return [:property, []]
431
+ end
432
+
433
+ if next_tok&.type == :lparen || specialized_call_with_type_args?(tokens, index)
434
+ if facts && (resolved = resolved_call_callee_semantic(name, tok, parameter_declaration, facts))
435
+ return resolved
436
+ end
437
+
438
+ return [:function, []] if user_defined_function
439
+
440
+ modifiers = []
441
+ modifiers << 'defaultLibrary' if BUILTIN_FUNCTION_NAMES.include?(name)
442
+ if BUILTIN_ASSOCIATED_HOOK_NAMES.include?(name) && specialized_call_with_type_args?(tokens, index) && !user_defined_function
443
+ modifiers << 'defaultLibrary'
444
+ end
445
+ return [:function, modifiers]
446
+ end
447
+
448
+ return [:function, []] if next_tok&.type == :lbracket && user_defined_function
449
+
450
+ if facts && identifier_in_type_reference_position?(tokens, index)
451
+ if known_type_name?(facts, name)
452
+ modifiers = []
453
+ modifiers << 'defaultLibrary' if DEFAULT_LIBRARY_TYPE_NAMES.include?(name)
454
+ return [:type, modifiers]
455
+ end
456
+ return [:type, []] if facts.interfaces.key?(name)
457
+
458
+ if DEFAULT_LIBRARY_TYPE_NAMES.include?(name)
459
+ return [:type, ['defaultLibrary']]
460
+ end
461
+ end
462
+
463
+ if facts
464
+
465
+ if (binding = local_semantic_value_binding(facts, tok, allow_same_line_future: parameter_declaration))
466
+ return semantic_value_binding_entry(binding, declaration: binding.kind == :param && parameter_declaration)
467
+ end
468
+
469
+ if known_type_name?(facts, name)
470
+ modifiers = []
471
+ modifiers << 'defaultLibrary' if DEFAULT_LIBRARY_TYPE_NAMES.include?(name)
472
+ return [:type, modifiers]
473
+ end
474
+ return [:type, []] if facts.interfaces.key?(name)
475
+
476
+ return [:namespace, []] if facts.imports.key?(name)
477
+
478
+ if (binding = facts.values[name])
479
+ return semantic_value_binding_entry(binding)
480
+ end
481
+
482
+ return [:function, []] if bare_function_value_identifier_site?(facts, tok)
483
+ end
484
+
485
+ if DEFAULT_LIBRARY_TYPE_NAMES.include?(name)
486
+ return [:type, ['defaultLibrary']]
487
+ end
488
+
489
+ return [:function, ['defaultLibrary']] if bare_builtin_specialization?(name, tokens, index)
490
+
491
+ [:variable, []]
492
+ end
493
+
494
+ def named_argument_label_token?(tokens, index)
495
+ prev_tok = previous_non_trivia_token(tokens, index)
496
+ next_tok = next_non_trivia_token(tokens, index + 1)
497
+ next_tok&.type == :equal && prev_tok && [:lparen, :comma].include?(prev_tok.type)
498
+ end
499
+
500
+ def named_argument_label_in_type_constructor?(tokens, index, facts)
501
+ return false unless facts
502
+
503
+ opener_index = parameter_list_opener_index(tokens, index)
504
+ return false unless opener_index
505
+
506
+ callee_index = previous_non_trivia_token_index(tokens, opener_index)
507
+ return false unless callee_index
508
+
509
+ if tokens[callee_index].type == :rbracket
510
+ lbracket_index = matching_opener_index(tokens, callee_index)
511
+ return false unless lbracket_index
512
+ callee_index = previous_non_trivia_token_index(tokens, lbracket_index)
513
+ end
514
+
515
+ return false unless callee_index && tokens[callee_index].type == :identifier
516
+
517
+ callee_name = tokens[callee_index].lexeme
518
+ return true if facts.types.key?(callee_name) || facts.interfaces.key?(callee_name)
519
+
520
+ dot_index = previous_non_trivia_token_index(tokens, callee_index)
521
+ return false unless dot_index && tokens[dot_index].type == :dot
522
+
523
+ receiver_index = previous_non_trivia_token_index(tokens, dot_index)
524
+ return false unless receiver_index
525
+
526
+ if tokens[receiver_index].type == :rbracket
527
+ lbracket_index = matching_opener_index(tokens, receiver_index)
528
+ return false unless lbracket_index
529
+ receiver_index = previous_non_trivia_token_index(tokens, lbracket_index)
530
+ end
531
+
532
+ return false unless receiver_index && tokens[receiver_index].type == :identifier
533
+
534
+ receiver_name = tokens[receiver_index].lexeme
535
+ facts.types.key?(receiver_name) || facts.interfaces.key?(receiver_name)
536
+ end
537
+
538
+ def match_arm_binding_token?(tokens, index)
539
+ prev_tok = previous_non_trivia_token(tokens, index)
540
+ next_tok = next_non_trivia_token(tokens, index + 1)
541
+ prev_tok&.type == :as && next_tok&.type == :colon
542
+ end
543
+
544
+ def field_declaration_token?(tokens, index)
545
+ tok = tokens[index]
546
+ return false unless tok&.type == :identifier
547
+ return false unless first_non_trivia_token_on_line?(tokens, index)
548
+ return false if parameter_declaration_token?(tokens, index)
549
+ return false if match_arm_binding_token?(tokens, index)
550
+
551
+ next_tok = next_non_trivia_token(tokens, index + 1)
552
+ next_tok&.type == :colon
553
+ end
554
+
555
+ def destructure_let_binding?(tokens, index)
556
+ tok = tokens[index]
557
+ return false unless tok&.type == :identifier
558
+
559
+ line_tokens = non_trivia_tokens_on_line(tokens, tok.line)
560
+ return false unless line_tokens.length >= 3
561
+
562
+ first = line_tokens[0]
563
+ return false unless [:let, :var].include?(first.type)
564
+
565
+ eq_idx = line_tokens.index { |t| t.type == :equal }
566
+ lparen_idx = line_tokens.index { |t| t.type == :lparen }
567
+ return false unless lparen_idx
568
+
569
+ return false if eq_idx && lparen_idx >= eq_idx
570
+
571
+ # let (a, b) = ...
572
+ if line_tokens[1]&.type == :lparen
573
+ return first.type == :let
574
+ end
575
+
576
+ # let Vec2(x, y) = ... — identifier then lparen adjacency
577
+ return false unless line_tokens[1]&.type == :identifier && lparen_idx == 2
578
+
579
+ first.type == :let
580
+ end
581
+
582
+ def struct_event_declaration_token?(tokens, index)
583
+ tok = tokens[index]
584
+ return false unless tok&.type == :identifier
585
+
586
+ prev_tok = previous_non_trivia_token(tokens, index)
587
+ return false unless prev_tok&.type == :event
588
+
589
+ line_tokens = non_trivia_tokens_on_line(tokens, tok.line)
590
+ line_start = line_tokens.first
591
+ return false unless line_start && line_start.column > 1
592
+
593
+ i = index - 1
594
+ while i >= 0
595
+ current = tokens[i]
596
+ i -= 1
597
+ next if [:newline, :indent, :dedent, :eof].include?(current.type)
598
+ next if current.line == tok.line
599
+ next if current.column >= line_start.column
600
+
601
+ header_line_toks = non_trivia_tokens_on_line(tokens, current.line)
602
+ return header_line_toks.first&.type == :struct
603
+ end
604
+
605
+ false
606
+ end
607
+
608
+ def variant_payload_field_declaration_token?(tokens, index)
609
+ return false unless parameter_declaration_token?(tokens, index)
610
+
611
+ opener_index = parameter_list_opener_index(tokens, index)
612
+ return false unless opener_index
613
+
614
+ head_index = previous_non_trivia_token_index(tokens, opener_index)
615
+ return false unless head_index
616
+
617
+ variant_enum_member_declaration?(tokens, head_index)
618
+ end
619
+
620
+ FOREIGN_PARAM_MODE_TOKENS = [:out, :in, :inout, :consuming].freeze
621
+ private_constant :FOREIGN_PARAM_MODE_TOKENS
622
+
623
+ def parameter_declaration_token?(tokens, index)
624
+ prev_tok = previous_non_trivia_token(tokens, index)
625
+ next_tok = next_non_trivia_token(tokens, index + 1)
626
+ next_tok&.type == :colon && prev_tok && (
627
+ [:lparen, :comma].include?(prev_tok.type) ||
628
+ FOREIGN_PARAM_MODE_TOKENS.include?(prev_tok.type)
629
+ )
630
+ end
631
+
632
+ def callable_parameter_declaration_token?(tokens, index)
633
+ return false unless parameter_declaration_token?(tokens, index)
634
+
635
+ opener_index = parameter_list_opener_index(tokens, index)
636
+ return false unless opener_index
637
+
638
+ head_index = previous_non_trivia_token_index(tokens, opener_index)
639
+ return false unless head_index
640
+
641
+ head = tokens[head_index]
642
+ return true if [:fn, :proc].include?(head.type)
643
+
644
+ if head.type == :rbracket
645
+ lbracket_index = matching_opener_index(tokens, head_index)
646
+ return false unless lbracket_index
647
+
648
+ head_index = previous_non_trivia_token_index(tokens, lbracket_index)
649
+ return false unless head_index
650
+
651
+ head = tokens[head_index]
652
+ end
653
+
654
+ return false unless head.type == :identifier
655
+
656
+ previous_non_trivia_token(tokens, head_index)&.type == :function
657
+ end
658
+
659
+ def parameter_list_opener_index(tokens, index)
660
+ depth = 0
661
+ i = index - 1
662
+ while i >= 0
663
+ tok = tokens[i]
664
+ if tok.type == :rparen
665
+ depth += 1
666
+ elsif tok.type == :lparen
667
+ return i if depth.zero?
668
+
669
+ depth -= 1
670
+ end
671
+ i -= 1
672
+ end
673
+
674
+ nil
675
+ end
676
+
677
+ def lexically_declared_free_function_name?(tokens, name)
678
+ lexically_declared_free_function_names(tokens).include?(name)
679
+ end
680
+
681
+ def lexically_declared_free_function_names(tokens)
682
+ cache = @lexically_declared_free_function_name_cache ||= {}
683
+ cached = cache[tokens.object_id]
684
+ return cached if cached
685
+
686
+ cache[tokens.object_id] = tokens.each_with_index.each_with_object(Set.new) do |(token, index), names|
687
+ next unless token.type == :identifier
688
+
689
+ prev_index = previous_non_trivia_token_index(tokens, index)
690
+ next unless prev_index
691
+
692
+ prev_tok = tokens[prev_index]
693
+ next unless [:function, :fn, :proc].include?(prev_tok.type)
694
+ next unless first_non_trivia_token_on_line?(tokens, prev_index)
695
+
696
+ names << token.lexeme
697
+ end
698
+ end
699
+
700
+ def generic_function_lexical_binding_semantic(facts, token)
701
+ kind = generic_function_lexical_binding_kind_at(facts, token.line, token.column, token.lexeme)
702
+ case kind
703
+ when :param
704
+ [:parameter, []]
705
+ when :variable
706
+ [:variable, []]
707
+ else
708
+ nil
709
+ end
710
+ end
711
+
712
+ def generic_function_lexical_binding_kind_at(facts, line, column, name)
713
+ generic_function_lexical_binding_scopes(facts).reverse_each do |scope|
714
+ next if line < scope[:start_line] || line > scope[:end_line]
715
+ next if line == scope[:start_line] && column < scope[:start_column]
716
+
717
+ kind = scope[:bindings][name]
718
+ return kind if kind
719
+ end
720
+
721
+ nil
722
+ end
723
+
724
+ def generic_function_lexical_binding_scopes(facts)
725
+ scopes = @generic_function_lexical_binding_scope_cache ||= {}
726
+ cached = scopes[facts.object_id]
727
+ unless cached
728
+ decls = Array(facts.ast&.declarations)
729
+ cached = decls.each_with_index.flat_map do |decl, index|
730
+ generic_function_lexical_scopes_for_declaration(
731
+ decl,
732
+ end_line: declaration_scope_end_line(decls, index),
733
+ )
734
+ end
735
+ scopes[facts.object_id] = cached
736
+ end
737
+
738
+ cached
739
+ end
740
+
741
+ def generic_function_lexical_scopes_for_declaration(decl, end_line: Float::INFINITY)
742
+ if decl.is_a?(AST::ExtendingBlock)
743
+ receiver_type_params = generic_type_parameter_names_for_extending_block(decl)
744
+ methods = Array(decl.methods)
745
+ return methods.each_with_index.flat_map do |method, index|
746
+ generic_method_lexical_scopes(
747
+ method,
748
+ receiver_type_params: receiver_type_params,
749
+ end_line: nested_declaration_scope_end_line(methods, index, fallback_end_line: end_line),
750
+ )
751
+ end
752
+ end
753
+
754
+ return [] unless generic_function_declaration?(decl)
755
+
756
+ generic_callable_lexical_scopes(decl, end_line: generic_statement_list_end_line(decl.body, decl.line))
757
+ end
758
+
759
+ def generic_method_lexical_scopes(method, receiver_type_params:, end_line:)
760
+ return [] unless method.respond_to?(:body) && !method.body.nil?
761
+ return [] if receiver_type_params.empty? && Array(method.type_params).empty?
762
+
763
+ generic_callable_lexical_scopes(
764
+ method,
765
+ end_line:,
766
+ include_receiver: method.respond_to?(:kind) && method.kind != :static,
767
+ )
768
+ end
769
+
770
+ def generic_callable_lexical_scopes(decl, end_line:, include_receiver: false)
771
+ scopes = []
772
+ current_bindings = {}
773
+ current_bindings['this'] = :param if include_receiver
774
+ Array(decl.params).each do |param|
775
+ next unless param.respond_to?(:name)
776
+
777
+ current_bindings[param.name] = :param
778
+ end
779
+
780
+ unless current_bindings.empty?
781
+ scopes << {
782
+ start_line: decl.line,
783
+ start_column: 0,
784
+ end_line: end_line,
785
+ bindings: current_bindings.dup,
786
+ }
787
+ end
788
+
789
+ collect_generic_function_local_scopes(Array(decl.body), current_bindings, end_line, scopes)
790
+
791
+ scopes
792
+ end
793
+
794
+ def generic_function_declaration?(decl)
795
+ decl.respond_to?(:type_params) &&
796
+ Array(decl.type_params).any? &&
797
+ decl.respond_to?(:params) &&
798
+ decl.respond_to?(:body) &&
799
+ !decl.body.nil?
800
+ end
801
+
802
+ def collect_generic_function_local_scopes(statements, current_bindings, block_end_line, scopes)
803
+ active_bindings = current_bindings.dup
804
+ Array(statements).each do |statement|
805
+ case statement
806
+ when AST::LocalDecl
807
+ active_bindings[statement.name] = statement.kind == :var ? :var : :let
808
+ scopes << generic_binding_scope(statement, active_bindings, block_end_line)
809
+ when AST::IfStmt
810
+ Array(statement.branches).each do |branch|
811
+ branch_body = Array(branch.body)
812
+ branch_end_line = generic_statement_list_end_line(branch_body, statement.line)
813
+ collect_generic_function_local_scopes(branch_body, active_bindings, branch_end_line, scopes)
814
+ end
815
+
816
+ else_body = Array(statement.else_body)
817
+ unless else_body.empty?
818
+ else_end_line = generic_statement_list_end_line(else_body, statement.line)
819
+ collect_generic_function_local_scopes(else_body, active_bindings, else_end_line, scopes)
820
+ end
821
+ when AST::MatchStmt
822
+ Array(statement.arms).each do |arm|
823
+ arm_bindings = active_bindings.dup
824
+ arm_body = Array(arm.body)
825
+ arm_end_line = generic_statement_list_end_line(arm_body, statement.line)
826
+ if arm.respond_to?(:binding_name) && arm.binding_name
827
+ arm_bindings[arm.binding_name] = :let
828
+ scopes << generic_binding_scope(arm, arm_bindings, arm_end_line)
829
+ end
830
+ collect_generic_function_local_scopes(arm_body, arm_bindings, arm_end_line, scopes)
831
+ end
832
+ when AST::UnsafeStmt, AST::WhileStmt, AST::DeferStmt
833
+ body = Array(statement.body)
834
+ body_end_line = generic_statement_list_end_line(body, statement.line)
835
+ collect_generic_function_local_scopes(body, active_bindings, body_end_line, scopes)
836
+ when AST::ForStmt
837
+ next unless statement.respond_to?(:name) && statement.name
838
+
839
+ body = Array(statement.body)
840
+ body_end_line = generic_statement_list_end_line(body, statement.line)
841
+ for_bindings = active_bindings.dup
842
+ for_bindings[statement.name] = :let
843
+ scopes << generic_binding_scope(statement, for_bindings, body_end_line)
844
+ collect_generic_function_local_scopes(body, for_bindings, body_end_line, scopes)
845
+ end
846
+ end
847
+ end
848
+
849
+ def generic_binding_scope(node, bindings, end_line)
850
+ {
851
+ start_line: node.respond_to?(:line) && node.line ? node.line : 0,
852
+ start_column: node.respond_to?(:column) && node.column ? node.column : 0,
853
+ end_line: end_line,
854
+ bindings: bindings.dup,
855
+ }
856
+ end
857
+
858
+ def generic_statement_list_end_line(statements, fallback_line)
859
+ Array(statements).reduce(fallback_line || 0) do |max_line, statement|
860
+ [max_line, generic_statement_end_line(statement)].compact.max
861
+ end
862
+ end
863
+
864
+ def generic_statement_end_line(statement)
865
+ return 0 unless statement
866
+
867
+ case statement
868
+ when AST::IfStmt
869
+ branch_lines = Array(statement.branches).map do |branch|
870
+ generic_statement_list_end_line(Array(branch.body), branch.respond_to?(:line) ? branch.line : statement.line)
871
+ end
872
+ else_line = generic_statement_list_end_line(Array(statement.else_body), statement.line)
873
+ ([statement.line, else_line] + branch_lines).compact.max
874
+ when AST::MatchStmt
875
+ arm_lines = Array(statement.arms).map do |arm|
876
+ generic_statement_list_end_line(Array(arm.body), arm.respond_to?(:line) ? arm.line : statement.line)
877
+ end
878
+ ([statement.line] + arm_lines).compact.max
879
+ when AST::UnsafeStmt, AST::WhileStmt, AST::ForStmt, AST::DeferStmt
880
+ [statement.line, generic_statement_list_end_line(Array(statement.body), statement.line)].compact.max
881
+ else
882
+ statement.respond_to?(:line) ? statement.line : 0
883
+ end
884
+ end
885
+
886
+ def namespace_keyword_token?(tokens, index)
887
+ tok = tokens[index]
888
+ return false unless tok && Token::KEYWORDS.value?(tok.type)
889
+
890
+ import_path_info_at(tokens, index, allow_keywords: true) ||
891
+ module_declaration_path_token?(tokens, index, allow_keywords: true)
892
+
893
+ end
894
+
895
+ def local_semantic_value_binding(facts, token, allow_same_line_future: false)
896
+ char = token.column - 1
897
+ [token.line - 1, token.line].uniq.each do |line|
898
+ frame = enclosing_completion_frame(facts, line)
899
+ next unless frame
900
+
901
+ snapshot = latest_completion_snapshot(frame, line, char)
902
+ binding = snapshot&.bindings&.dig(token.lexeme)
903
+ return binding if binding
904
+
905
+ next unless allow_same_line_future
906
+
907
+ future_snapshot = same_line_future_completion_snapshot(frame, line, char)
908
+ binding = future_snapshot&.bindings&.dig(token.lexeme)
909
+ return binding if binding
910
+ end
911
+
912
+ nil
913
+ end
914
+
915
+ def semantic_value_binding_entry(binding, declaration: false)
916
+ case binding.kind
917
+ when :param
918
+ modifiers = []
919
+ modifiers << 'declaration' if declaration
920
+ [:parameter, modifiers]
921
+ when :const, :let
922
+ [:variable, ['readonly']]
923
+ else
924
+ modifiers = []
925
+ modifiers << 'declaration' if declaration
926
+ [:variable, modifiers]
927
+ end
928
+ end
929
+
930
+ def resolved_call_callee_semantic(name, token, parameter_declaration, facts)
931
+ if (binding = local_semantic_value_binding(facts, token, allow_same_line_future: parameter_declaration))
932
+ return semantic_value_binding_entry(binding, declaration: binding.kind == :param && parameter_declaration)
933
+ end
934
+
935
+ if (binding = facts.values[name])
936
+ return semantic_value_binding_entry(binding)
937
+ end
938
+
939
+ modifiers = []
940
+ modifiers << 'defaultLibrary' if BUILTIN_FUNCTION_NAMES.include?(name)
941
+ return [:function, modifiers] if BUILTIN_FUNCTION_NAMES.include?(name)
942
+ return [:function, modifiers] if facts.functions.key?(name)
943
+ return [:type, []] if constructible_semantic_type?(facts.types[name])
944
+
945
+ nil
946
+ end
947
+
948
+ def callable_field_member_access?(name, tokens, index, facts)
949
+ next_tok = next_non_trivia_token(tokens, index + 1)
950
+ return false unless next_tok&.type == :lparen
951
+
952
+ dot_index = previous_non_trivia_token_index(tokens, index)
953
+ return false unless dot_index && tokens[dot_index].type == :dot
954
+
955
+ receiver_index = previous_non_trivia_token_index(tokens, dot_index)
956
+ return false unless receiver_index
957
+
958
+ receiver_tok = tokens[receiver_index]
959
+ return false unless receiver_tok.type == :identifier
960
+
961
+ resolve_receiver_value_type(facts, receiver_tok).then do |receiver_type|
962
+ next false unless receiver_type
963
+
964
+ field_receiver_type = project_field_receiver_type_for_completion(receiver_type)
965
+ next false unless field_receiver_type.respond_to?(:field)
966
+
967
+ callable_semantic_type?(field_receiver_type.field(name))
968
+ end
969
+ end
970
+
971
+ def resolve_receiver_value_type(facts, token)
972
+ char = token.column
973
+
974
+ [token.line - 1, token.line].uniq.each do |line|
975
+ receiver_type = resolve_dot_receiver_value_type(facts, token.lexeme, line, char)
976
+ return receiver_type if receiver_type
977
+ end
978
+
979
+ nil
980
+ end
981
+
982
+ def callable_semantic_type?(type)
983
+ type.is_a?(Types::Function) || type.is_a?(Types::Proc)
984
+ end
985
+
986
+ def known_type_name?(facts, name)
987
+ return false unless facts
988
+ return true if facts.types.key?(name)
989
+ facts.types.each_value do |type|
990
+ return true if type.respond_to?(:nested_types) && type.nested_types.key?(name)
991
+ end
992
+ false
993
+ end
994
+
995
+ def dot_nested_type_member?(tokens, index, facts)
996
+ return false unless facts
997
+
998
+ dot_index = index - 1
999
+ return false unless dot_index >= 0 && tokens[dot_index].type == :dot
1000
+
1001
+ receiver_index = previous_non_trivia_token_index(tokens, dot_index)
1002
+ return false unless receiver_index && tokens[receiver_index].type == :identifier
1003
+
1004
+ receiver_name = tokens[receiver_index].lexeme
1005
+ type = resolve_struct_type_name(facts, receiver_name)
1006
+ return false unless type.is_a?(Types::Struct)
1007
+
1008
+ member_name = tokens[index].lexeme
1009
+ type.nested_types.key?(member_name)
1010
+ end
1011
+
1012
+ def resolve_struct_type_name(facts, name)
1013
+ type = facts.types[name]
1014
+ return type if type.is_a?(Types::Struct)
1015
+ facts.types.each_value do |t|
1016
+ next unless t.respond_to?(:nested_types)
1017
+ found = t.nested_types[name]
1018
+ return found if found.is_a?(Types::Struct)
1019
+ end
1020
+ nil
1021
+ end
1022
+
1023
+ def constructible_semantic_type?(type)
1024
+ type.is_a?(Types::Struct) || type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::StringView) || type.is_a?(Types::Task) || type.is_a?(Types::Vector) || type.is_a?(Types::Matrix) || type.is_a?(Types::Quaternion)
1025
+ end
1026
+
1027
+ def bare_builtin_specialization?(name, tokens, index)
1028
+ return false unless name == 'zero' || name == 'default'
1029
+
1030
+ next_index = next_non_trivia_token_index(tokens, index + 1)
1031
+ return false unless next_index && tokens[next_index].type == :lbracket
1032
+
1033
+ rbracket_index = matching_closer_index(tokens, next_index, :lbracket, :rbracket)
1034
+ return false unless rbracket_index
1035
+
1036
+ after_bracket_index = next_non_trivia_token_index(tokens, rbracket_index + 1)
1037
+ after_bracket_index.nil? || tokens[after_bracket_index].type != :lparen
1038
+ end
1039
+
1040
+ def bare_function_value_identifier_site?(facts, token)
1041
+ facts.functions.key?(token.lexeme) &&
1042
+ facts.callable_value_identifier_sites.fetch([token.line, token.column], false)
1043
+ end
1044
+
1045
+ def imported_module_function_value_member_access_site?(facts, tokens, index)
1046
+ dot_index = previous_non_trivia_token_index(tokens, index)
1047
+ return false unless dot_index && tokens[dot_index].type == :dot
1048
+
1049
+ receiver_index = previous_non_trivia_token_index(tokens, dot_index)
1050
+ return false unless receiver_index
1051
+
1052
+ receiver = tokens[receiver_index]
1053
+ return false unless receiver.type == :identifier
1054
+
1055
+ facts.callable_value_member_access_sites.fetch(
1056
+ [receiver.lexeme, receiver.line, receiver.column, tokens[index].lexeme],
1057
+ false,
1058
+ )
1059
+ end
1060
+
1061
+ def imported_module_binding_for_member(tokens, index, facts)
1062
+ dot_index = previous_non_trivia_token_index(tokens, index)
1063
+ return nil unless dot_index && tokens[dot_index].type == :dot
1064
+
1065
+ receiver_index = previous_non_trivia_token_index(tokens, dot_index)
1066
+ return nil unless receiver_index
1067
+
1068
+ receiver = tokens[receiver_index]
1069
+ return nil unless receiver.type == :identifier
1070
+
1071
+ facts.imports[receiver.lexeme]
1072
+ end
1073
+
1074
+ def static_type_member_access?(tokens, index, facts)
1075
+ receiver_info = dot_type_receiver_info(tokens, index, facts)
1076
+ return false unless receiver_info
1077
+
1078
+ !static_method_binding_for_receiver(facts, receiver_info[:type], tokens[index].lexeme).nil?
1079
+ end
1080
+
1081
+ def dot_type_receiver_info(tokens, index, facts)
1082
+ dot_index = previous_non_trivia_token_index(tokens, index)
1083
+ return nil unless dot_index && tokens[dot_index].type == :dot
1084
+
1085
+ receiver_index = previous_non_trivia_token_index(tokens, dot_index)
1086
+ return nil unless receiver_index
1087
+
1088
+ if tokens[receiver_index].type == :rbracket
1089
+ lbracket_index = matching_opener_index(tokens, receiver_index)
1090
+ return nil unless lbracket_index
1091
+
1092
+ receiver_index = previous_non_trivia_token_index(tokens, lbracket_index)
1093
+ return nil unless receiver_index
1094
+ end
1095
+
1096
+ receiver = tokens[receiver_index]
1097
+ return nil unless receiver.type == :identifier
1098
+
1099
+ receiver_name = receiver.lexeme
1100
+ receiver_path = receiver_name
1101
+
1102
+ module_dot_index = previous_non_trivia_token_index(tokens, receiver_index)
1103
+ if module_dot_index && tokens[module_dot_index].type == :dot
1104
+ module_index = previous_non_trivia_token_index(tokens, module_dot_index)
1105
+ return nil unless module_index && tokens[module_index].type == :identifier
1106
+
1107
+ receiver_path = "#{tokens[module_index].lexeme}.#{receiver_name}"
1108
+ end
1109
+
1110
+ resolve_type_receiver_info(facts, receiver_name, receiver_path)
1111
+ end
1112
+
1113
+ def specialized_call_with_type_args?(tokens, index)
1114
+ next_index = next_non_trivia_token_index(tokens, index + 1)
1115
+ return false unless next_index && tokens[next_index].type == :lbracket
1116
+
1117
+ rbracket_index = matching_closer_index(tokens, next_index, :lbracket, :rbracket)
1118
+ return false unless rbracket_index
1119
+
1120
+ after_bracket_index = next_non_trivia_token_index(tokens, rbracket_index + 1)
1121
+ after_bracket_index && tokens[after_bracket_index].type == :lparen
1122
+ end
1123
+
1124
+ def identifier_in_type_argument_position?(tokens, index)
1125
+ lbracket_index = previous_non_trivia_token_index(tokens, index)
1126
+ return false unless lbracket_index
1127
+
1128
+ if tokens[lbracket_index].type == :comma
1129
+ depth = 0
1130
+ i = lbracket_index - 1
1131
+ lbracket_index = nil
1132
+ while i >= 0
1133
+ tok = tokens[i]
1134
+ if tok.type == :rbracket
1135
+ depth += 1
1136
+ elsif tok.type == :lbracket
1137
+ if depth.zero?
1138
+ lbracket_index = i
1139
+ break
1140
+ end
1141
+
1142
+ depth -= 1
1143
+ end
1144
+ i -= 1
1145
+ end
1146
+ end
1147
+
1148
+ return false unless lbracket_index && tokens[lbracket_index].type == :lbracket
1149
+
1150
+ rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
1151
+ return false unless rbracket_index
1152
+
1153
+ next_index = next_non_trivia_token_index(tokens, index + 1)
1154
+ return false unless next_index
1155
+
1156
+ # Type argument entries should stay inside the current [] pair.
1157
+ next_index <= rbracket_index
1158
+ end
1159
+
1160
+ def type_parameter_declaration_token?(facts, tokens, index)
1161
+ info = type_parameter_declaration_info_on_line(tokens, tokens[index].line)
1162
+ info && info[:tokens].any? { |token| token.equal?(tokens[index]) }
1163
+ end
1164
+
1165
+ def type_parameter_reference_token?(facts, tokens, index)
1166
+ tok = tokens[index]
1167
+ return false unless type_parameter_names_in_scope(facts, tok.line).include?(tok.lexeme)
1168
+ return false if type_parameter_declaration_token?(facts, tokens, index)
1169
+
1170
+ identifier_in_type_parameter_reference_position?(tokens, index)
1171
+ end
1172
+
1173
+ def identifier_in_type_parameter_reference_position?(tokens, index)
1174
+ return true if identifier_in_type_argument_position?(tokens, index)
1175
+
1176
+ prev_tok = previous_non_trivia_token(tokens, index)
1177
+ [:colon, :arrow].include?(prev_tok&.type)
1178
+ end
1179
+
1180
+ def identifier_in_type_reference_position?(tokens, index)
1181
+ return true if identifier_in_type_argument_position?(tokens, index)
1182
+
1183
+ prev_tok = previous_non_trivia_token(tokens, index)
1184
+ return true if [:colon, :arrow, :as].include?(prev_tok&.type)
1185
+
1186
+ line_tokens = non_trivia_tokens_on_line(tokens, tokens[index].line)
1187
+ return true if prev_tok&.type == :equal && line_tokens.first&.type == :type
1188
+
1189
+ next_index = next_non_trivia_token_index(tokens, index + 1)
1190
+ return false unless next_index && tokens[next_index].type == :less
1191
+
1192
+ minus_index = next_non_trivia_token_index(tokens, next_index + 1)
1193
+ return false unless minus_index && tokens[minus_index].type == :minus
1194
+
1195
+ tokens[next_index].line == tokens[index].line &&
1196
+ tokens[next_index].column == (tokens[index].column + tokens[index].lexeme.length) &&
1197
+ tokens[minus_index].line == tokens[next_index].line &&
1198
+ tokens[minus_index].column == (tokens[next_index].column + tokens[next_index].lexeme.length)
1199
+ end
1200
+
1201
+ def type_parameter_declaration_info_on_line(tokens, line)
1202
+ line_tokens = non_trivia_tokens_on_line(tokens, line)
1203
+ return nil if line_tokens.empty?
1204
+
1205
+ header_index = line_tokens.index { |line_tok| generic_type_parameter_header_token?(line_tok.type) }
1206
+ return nil unless header_index
1207
+
1208
+ name_index = ((header_index + 1)...line_tokens.length).find { |i| line_tokens[i].type == :identifier }
1209
+ return nil unless name_index
1210
+
1211
+ lbracket_index = name_index + 1
1212
+ return nil unless line_tokens[lbracket_index]&.type == :lbracket
1213
+
1214
+ depth = 0
1215
+ type_param_tokens = []
1216
+ expect_name = false
1217
+ i = lbracket_index
1218
+ while i < line_tokens.length
1219
+ tok = line_tokens[i]
1220
+ case tok.type
1221
+ when :lbracket
1222
+ depth += 1
1223
+ expect_name = true if depth == 1
1224
+ when :rbracket
1225
+ depth -= 1
1226
+ return {
1227
+ names: type_param_tokens.map(&:lexeme),
1228
+ tokens: type_param_tokens,
1229
+ } if depth.zero?
1230
+ when :comma
1231
+ expect_name = true if depth == 1
1232
+ when :at
1233
+ expect_name = false if depth == 1
1234
+ when :implements
1235
+ expect_name = false if depth == 1
1236
+ else
1237
+ if depth == 1 && expect_name && tok.type == :identifier
1238
+ type_param_tokens << tok
1239
+ expect_name = false
1240
+ end
1241
+ end
1242
+ i += 1
1243
+ end
1244
+
1245
+ nil
1246
+ end
1247
+
1248
+ def generic_type_parameter_header_token?(type)
1249
+ [:function, :struct, :union, :enum, :flags, :variant, :type, :extending].include?(type)
1250
+ end
1251
+
1252
+ def type_parameter_names_in_scope(facts, line)
1253
+ scopes = @type_parameter_scope_cache ||= {}
1254
+ cached = scopes[facts.object_id]
1255
+ unless cached
1256
+ decls = Array(facts.ast&.declarations)
1257
+ cached = decls.each_with_index.flat_map do |decl, index|
1258
+ type_parameter_scopes_for_declaration(
1259
+ decl,
1260
+ end_line: declaration_scope_end_line(decls, index),
1261
+ )
1262
+ end
1263
+ scopes[facts.object_id] = cached
1264
+ end
1265
+
1266
+ cached.reverse_each do |scope|
1267
+ return scope[:names] if line >= scope[:start_line] && line <= scope[:end_line]
1268
+ end
1269
+
1270
+ []
1271
+ end
1272
+
1273
+ def type_parameter_scopes_for_declaration(decl, end_line: Float::INFINITY)
1274
+ if decl.is_a?(AST::ExtendingBlock)
1275
+ receiver_names = generic_type_parameter_names_for_extending_block(decl)
1276
+ methods = Array(decl.methods)
1277
+ return methods.each_with_index.filter_map do |method, index|
1278
+ names = receiver_names + generic_type_parameter_names_for_declaration(method)
1279
+ next if names.empty? || method.line.nil?
1280
+
1281
+ {
1282
+ start_line: method.line,
1283
+ end_line: nested_declaration_scope_end_line(methods, index, fallback_end_line: end_line),
1284
+ names: names.uniq,
1285
+ }
1286
+ end
1287
+ end
1288
+
1289
+ names = generic_type_parameter_names_for_declaration(decl)
1290
+ return [] if names.empty? || decl.line.nil?
1291
+
1292
+ [{
1293
+ start_line: decl.line,
1294
+ end_line: end_line,
1295
+ names: names,
1296
+ }]
1297
+ end
1298
+
1299
+ def generic_type_parameter_names_for_declaration(decl)
1300
+ return [] unless decl.respond_to?(:type_params)
1301
+
1302
+ Array(decl.type_params).filter_map { |type_param| type_param.respond_to?(:name) ? type_param.name : nil }
1303
+ end
1304
+
1305
+ def generic_type_parameter_names_for_extending_block(decl)
1306
+ return [] unless decl.respond_to?(:type_name)
1307
+
1308
+ type_ref = decl.type_name
1309
+ return [] unless type_ref.is_a?(AST::TypeRef)
1310
+
1311
+ Array(type_ref.arguments).filter_map do |argument|
1312
+ simple_type_parameter_name_from_type_argument(argument)
1313
+ end
1314
+ end
1315
+
1316
+ def simple_type_parameter_name_from_type_argument(argument)
1317
+ value = argument.respond_to?(:value) ? argument.value : nil
1318
+ return nil unless value.is_a?(AST::TypeRef)
1319
+ return nil unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
1320
+
1321
+ value.name.parts.first
1322
+ end
1323
+
1324
+ def declaration_scope_end_line(decls, index)
1325
+ nested_declaration_scope_end_line(decls, index, fallback_end_line: Float::INFINITY)
1326
+ end
1327
+
1328
+ def nested_declaration_scope_end_line(decls, index, fallback_end_line:)
1329
+ next_decl = decls[(index + 1)..]&.find { |candidate| candidate.respond_to?(:line) && !candidate.line.nil? }
1330
+ next_decl ? next_decl.line - 1 : fallback_end_line
1331
+ end
1332
+
1333
+ def matching_closer_index(tokens, opener_index, opener_type, closer_type)
1334
+ depth = 0
1335
+ i = opener_index
1336
+ while i < tokens.length
1337
+ tok = tokens[i]
1338
+ if tok.type == opener_type
1339
+ depth += 1
1340
+ elsif tok.type == closer_type
1341
+ depth -= 1
1342
+ return i if depth.zero?
1343
+ end
1344
+ i += 1
1345
+ end
1346
+ nil
1347
+ end
1348
+
1349
+ def import_path_info_at(tokens, index, allow_keywords: false)
1350
+ tok = tokens[index]
1351
+ return nil unless tok
1352
+ return nil unless tok.type == :identifier || (allow_keywords && Token::KEYWORDS.value?(tok.type))
1353
+
1354
+ line_tokens = non_trivia_tokens_on_line(tokens, tok.line)
1355
+ return nil if line_tokens.empty? || line_tokens.first.type != :import
1356
+
1357
+ as_index = line_tokens.index { |line_tok| line_tok.type == :as }
1358
+ module_tokens = line_tokens[1...(as_index || line_tokens.length)] || []
1359
+ alias_token = as_index ? line_tokens[as_index + 1] : nil
1360
+
1361
+ module_identifiers = module_tokens.select do |line_tok|
1362
+ line_tok.type == :identifier || (allow_keywords && Token::KEYWORDS.value?(line_tok.type))
1363
+ end
1364
+ return nil if module_identifiers.empty?
1365
+
1366
+ module_name = module_identifiers.map(&:lexeme).join('.')
1367
+ return { module_name: module_name, role: :module_path } if module_identifiers.include?(tok)
1368
+ return { module_name: module_name, role: :alias } if alias_token == tok
1369
+
1370
+ nil
1371
+ end
1372
+
1373
+ def variant_enum_member_declaration?(tokens, index)
1374
+ tok = tokens[index]
1375
+ line_tokens = non_trivia_tokens_on_line(tokens, tok.line)
1376
+ return false unless line_tokens.first.equal?(tok) && tok.column > 1
1377
+
1378
+ i = index - 1
1379
+ while i >= 0
1380
+ t = tokens[i]
1381
+ i -= 1
1382
+ next if [:newline, :indent, :dedent, :eof].include?(t.type)
1383
+ next if t.line == tok.line
1384
+ next if t.column >= tok.column
1385
+
1386
+ header_line_toks = non_trivia_tokens_on_line(tokens, t.line)
1387
+ header_kind = header_line_toks.find { |header_tok| [:variant, :enum, :flags].include?(header_tok.type) }
1388
+ return !header_kind.nil?
1389
+ end
1390
+ false
1391
+ end
1392
+
1393
+ def type_name_member_access?(tokens, index, facts = nil)
1394
+ dot_index = previous_non_trivia_token_index(tokens, index)
1395
+ return false unless dot_index && tokens[dot_index].type == :dot
1396
+
1397
+ receiver_index = previous_non_trivia_token_index(tokens, dot_index)
1398
+ return false unless receiver_index
1399
+
1400
+ type_name_receiver_token?(tokens, receiver_index, facts)
1401
+ end
1402
+
1403
+ def type_name_receiver_token?(tokens, index, facts = nil)
1404
+ receiver = tokens[index]
1405
+
1406
+ if receiver.type == :identifier
1407
+ return true if receiver.lexeme.match?(/\A[A-Z]/)
1408
+ return true if facts && facts.types.key?(receiver.lexeme)
1409
+
1410
+ if facts
1411
+ module_binding = imported_module_binding_for_member(tokens, index, facts)
1412
+ return true if module_binding && module_binding.types.key?(receiver.lexeme)
1413
+ end
1414
+
1415
+ return false
1416
+ end
1417
+
1418
+ if receiver.type == :rbracket
1419
+ lbracket_i = matching_opener_index(tokens, index)
1420
+ return false unless lbracket_i
1421
+
1422
+ base_index = previous_non_trivia_token_index(tokens, lbracket_i)
1423
+ return false unless base_index
1424
+
1425
+ return type_name_receiver_token?(tokens, base_index, facts)
1426
+ end
1427
+
1428
+ false
1429
+ end
1430
+
1431
+ def matching_opener_index(tokens, closer_index)
1432
+ closer = tokens[closer_index]
1433
+ return nil unless closer
1434
+
1435
+ opener_type, closer_type = case closer.type
1436
+ when :rbracket then [:lbracket, :rbracket]
1437
+ when :rparen then [:lparen, :rparen]
1438
+ else return nil
1439
+ end
1440
+
1441
+ depth = 0
1442
+ i = closer_index
1443
+ while i >= 0
1444
+ t = tokens[i]
1445
+ if t.type == closer_type
1446
+ depth += 1
1447
+ elsif t.type == opener_type
1448
+ depth -= 1
1449
+ return i if depth.zero?
1450
+ end
1451
+ i -= 1
1452
+ end
1453
+ nil
1454
+ end
1455
+
1456
+ def non_trivia_tokens_on_line(tokens, line)
1457
+ return @tokens_by_line_cache[line] if @tokens_by_line_cache
1458
+
1459
+ tokens.select do |tok|
1460
+ tok.line == line && ![:newline, :indent, :dedent, :eof].include?(tok.type)
1461
+ end
1462
+ end
1463
+
1464
+ def build_attribute_name_semantic_overrides(tokens, facts)
1465
+ return {} unless facts&.respond_to?(:ast) && facts.ast
1466
+
1467
+ token_indices_by_position = tokens.each_with_index.each_with_object({}) do |(token, index), positions|
1468
+ positions[[token.line, token.column]] = index
1469
+ end
1470
+ overrides = {}
1471
+
1472
+ walk_ast_nodes(facts.ast) do |node|
1473
+ case node
1474
+ when AST::AttributeDecl
1475
+ mark_attribute_name_override(
1476
+ overrides,
1477
+ token_indices_by_position,
1478
+ tokens,
1479
+ [node.name],
1480
+ line: node.line,
1481
+ column: node.column,
1482
+ declaration: true,
1483
+ )
1484
+ when AST::AttributeApplication
1485
+ mark_attribute_name_override(
1486
+ overrides,
1487
+ token_indices_by_position,
1488
+ tokens,
1489
+ node.name.parts,
1490
+ line: node.line,
1491
+ column: node.column,
1492
+ )
1493
+ when AST::Call
1494
+ mark_attribute_reflection_name_overrides(overrides, token_indices_by_position, tokens, node)
1495
+ end
1496
+ end
1497
+
1498
+ overrides
1499
+ end
1500
+
1501
+ def walk_ast_nodes(node, &block)
1502
+ case node
1503
+ when Array
1504
+ node.each { |entry| walk_ast_nodes(entry, &block) }
1505
+ when String, Symbol, Numeric, TrueClass, FalseClass, NilClass
1506
+ nil
1507
+ else
1508
+ return unless node.class.name&.start_with?("MilkTea::AST::")
1509
+
1510
+ yield node
1511
+ node.to_h.each_value { |value| walk_ast_nodes(value, &block) }
1512
+ end
1513
+ end
1514
+
1515
+ def mark_attribute_reflection_name_overrides(overrides, token_indices_by_position, tokens, call_expression)
1516
+ callee = call_expression.callee
1517
+ return unless callee.is_a?(AST::Identifier)
1518
+ return unless %w[has_attribute attribute_of].include?(callee.name)
1519
+ return unless call_expression.arguments.length >= 2
1520
+
1521
+ attribute_name_expression = call_expression.arguments[1].value
1522
+
1523
+ case attribute_name_expression
1524
+ when AST::Identifier
1525
+ mark_attribute_name_override(
1526
+ overrides,
1527
+ token_indices_by_position,
1528
+ tokens,
1529
+ [attribute_name_expression.name],
1530
+ line: attribute_name_expression.line,
1531
+ column: attribute_name_expression.column,
1532
+ )
1533
+ when AST::MemberAccess
1534
+ return unless attribute_name_expression.receiver.is_a?(AST::Identifier)
1535
+
1536
+ mark_attribute_name_override(
1537
+ overrides,
1538
+ token_indices_by_position,
1539
+ tokens,
1540
+ [attribute_name_expression.receiver.name, attribute_name_expression.member],
1541
+ line: attribute_name_expression.receiver.line,
1542
+ column: attribute_name_expression.receiver.column,
1543
+ )
1544
+ end
1545
+ end
1546
+
1547
+ def mark_attribute_name_override(overrides, token_indices_by_position, tokens, parts, line:, column:, declaration: false)
1548
+ current_index = token_indices_by_position[[line, column]]
1549
+ return unless current_index
1550
+
1551
+ parts.each_with_index do |part, part_index|
1552
+ token = tokens[current_index]
1553
+ return unless token&.lexeme == part
1554
+
1555
+ if part_index == parts.length - 1
1556
+ modifiers = []
1557
+ modifiers << 'declaration' if declaration
1558
+ overrides[[token.line, token.column]] = [:decorator, modifiers]
1559
+ return
1560
+ end
1561
+
1562
+ overrides[[token.line, token.column]] = [:namespace, []]
1563
+ dot_index = next_non_trivia_token_index(tokens, current_index + 1)
1564
+ return unless dot_index && tokens[dot_index].type == :dot
1565
+
1566
+ current_index = next_non_trivia_token_index(tokens, dot_index + 1)
1567
+ return unless current_index
1568
+ end
1569
+ end
1570
+
1571
+ def module_declaration_path_token?(tokens, index, allow_keywords: false)
1572
+ !module_declaration_info_at(tokens, index, allow_keywords:).nil?
1573
+ end
1574
+
1575
+ def module_declaration_info_at(tokens, index, allow_keywords: false)
1576
+ tok = tokens[index]
1577
+ return nil unless tok&.type == :identifier || (allow_keywords && Token::KEYWORDS.value?(tok.type))
1578
+
1579
+ line_tokens = non_trivia_tokens_on_line(tokens, tok.line)
1580
+ return nil if line_tokens.empty? || line_tokens.first.type != :module
1581
+
1582
+ path_tokens = line_tokens[1..].to_a.select do |line_tok|
1583
+ line_tok.type == :identifier || (allow_keywords && Token::KEYWORDS.value?(line_tok.type))
1584
+ end
1585
+ return nil unless path_tokens.any? { |line_tok| line_tok.equal?(tok) }
1586
+
1587
+ {
1588
+ module_name: path_tokens.map(&:lexeme).join('.'),
1589
+ }
1590
+ end
1591
+
1592
+ def previous_non_trivia_token(tokens, index)
1593
+ prev_index = previous_non_trivia_token_index(tokens, index)
1594
+ return nil unless prev_index
1595
+
1596
+ tokens[prev_index]
1597
+ end
1598
+
1599
+ def first_non_trivia_token_on_line?(tokens, index)
1600
+ token = tokens[index]
1601
+ return false unless token
1602
+
1603
+ i = index - 1
1604
+ while i >= 0
1605
+ previous = tokens[i]
1606
+ return true if previous.type == :newline
1607
+ return false if previous.line == token.line && ![:indent, :dedent].include?(previous.type)
1608
+
1609
+ i -= 1
1610
+ end
1611
+
1612
+ true
1613
+ end
1614
+
1615
+ def previous_non_trivia_token_index(tokens, index)
1616
+ i = index - 1
1617
+ while i >= 0
1618
+ tok = tokens[i]
1619
+ return i unless [:newline, :indent, :dedent].include?(tok.type)
1620
+ i -= 1
1621
+ end
1622
+ nil
1623
+ end
1624
+
1625
+ def next_non_trivia_token_index(tokens, index)
1626
+ i = index
1627
+ while i < tokens.length
1628
+ tok = tokens[i]
1629
+ return i unless [:newline, :indent, :dedent].include?(tok.type)
1630
+ i += 1
1631
+ end
1632
+ nil
1633
+ end
1634
+
1635
+ def encode_semantic_tokens(entries)
1636
+ data = []
1637
+ prev_line = 0
1638
+ prev_char = 0
1639
+
1640
+ entries.each do |entry|
1641
+ delta_line = entry[:line] - prev_line
1642
+ delta_start = delta_line.zero? ? entry[:start_char] - prev_char : entry[:start_char]
1643
+ type_index = SEMANTIC_TOKEN_TYPES.index(entry[:type].to_s) || 0
1644
+ modifiers_bitset = semantic_modifiers_bitset(entry[:modifiers])
1645
+
1646
+ data << delta_line
1647
+ data << delta_start
1648
+ data << entry[:length]
1649
+ data << type_index
1650
+ data << modifiers_bitset
1651
+
1652
+ prev_line = entry[:line]
1653
+ prev_char = entry[:start_char]
1654
+ end
1655
+
1656
+ data
1657
+ end
1658
+
1659
+ def next_semantic_token_result_id(uri)
1660
+ @semantic_token_result_counter ||= 0
1661
+ @semantic_token_result_counter += 1
1662
+ "#{uri}:#{@semantic_token_result_counter}"
1663
+ end
1664
+
1665
+ def compute_semantic_tokens_edits(old_entries, new_entries)
1666
+ return [] if old_entries == new_entries
1667
+
1668
+ prefix = find_semantic_token_common_prefix(old_entries, new_entries)
1669
+ suffix = find_semantic_token_common_suffix(old_entries, new_entries, prefix)
1670
+
1671
+ old_mid = old_entries.length - prefix - suffix
1672
+ new_mid = new_entries.length - prefix - suffix
1673
+
1674
+ if old_mid.zero? && new_mid.zero?
1675
+ return []
1676
+ end
1677
+
1678
+ start_offset = prefix * 5
1679
+ delete_count = old_mid * 5
1680
+ insert_tokens = encode_semantic_tokens(new_entries[prefix...(new_entries.length - suffix)])
1681
+
1682
+ [{ start: start_offset, deleteCount: delete_count, data: insert_tokens }]
1683
+ end
1684
+
1685
+ def find_semantic_token_common_prefix(old_entries, new_entries)
1686
+ limit = [old_entries.length, new_entries.length].min
1687
+ prefix = 0
1688
+ while prefix < limit && semantic_token_entry_equal?(old_entries[prefix], new_entries[prefix])
1689
+ prefix += 1
1690
+ end
1691
+ prefix
1692
+ end
1693
+
1694
+ def find_semantic_token_common_suffix(old_entries, new_entries, prefix)
1695
+ old_limit = old_entries.length - prefix
1696
+ new_limit = new_entries.length - prefix
1697
+ limit = [old_limit, new_limit].min
1698
+ suffix = 0
1699
+ while suffix < limit &&
1700
+ semantic_token_entry_equal?(old_entries[old_entries.length - 1 - suffix],
1701
+ new_entries[new_entries.length - 1 - suffix])
1702
+ suffix += 1
1703
+ end
1704
+ suffix
1705
+ end
1706
+
1707
+ def semantic_token_entry_equal?(a, b)
1708
+ a[:line] == b[:line] &&
1709
+ a[:start_char] == b[:start_char] &&
1710
+ a[:length] == b[:length] &&
1711
+ a[:type] == b[:type] &&
1712
+ a[:modifiers] == b[:modifiers]
1713
+ end
1714
+
1715
+ def semantic_modifiers_bitset(modifiers)
1716
+ bits = 0
1717
+ Array(modifiers).each do |modifier|
1718
+ idx = SEMANTIC_TOKEN_MODIFIERS.index(modifier.to_s)
1719
+ next unless idx
1720
+
1721
+ bits |= (1 << idx)
1722
+ end
1723
+ bits
1724
+ end
1725
+
1726
+ def generic_function_binding_for_line(facts, line)
1727
+ generic_function_bindings(facts).filter_map do |binding|
1728
+ next unless binding.ast.respond_to?(:body) && binding.ast.respond_to?(:line)
1729
+
1730
+ start_line = binding.ast.line
1731
+ end_line = generic_statement_list_end_line(Array(binding.ast.body), start_line)
1732
+ next unless start_line <= line && line <= end_line
1733
+
1734
+ [end_line - start_line, -start_line, binding]
1735
+ end.min_by { |span, start_line, _binding| [span, start_line] }&.last
1736
+ end
1737
+
1738
+ def generic_function_bindings(facts)
1739
+ facts.functions.each_value.select { |binding| binding.type_params.any? } +
1740
+ facts.methods.each_value.flat_map(&:values).select { |binding| binding.type_params.any? }
1741
+ end
1742
+ end
1743
+ end
1744
+ end
1745
+ end