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.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/AUTHORS +3 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +82 -0
- data/LICENSE +21 -0
- data/README.md +1208 -0
- data/Rakefile +332 -0
- data/bin/mtc +8 -0
- data/bin/profile-mtc-checks +133 -0
- data/bin/tracy-profiler +0 -0
- data/docs/build-guide.md +536 -0
- data/docs/index.html +2778 -0
- data/docs/language-design.md +1519 -0
- data/docs/language-manual.md +1534 -0
- data/lib/milk_tea/base.rb +49 -0
- data/lib/milk_tea/bindings/bindgen/ast_parser.rb +398 -0
- data/lib/milk_tea/bindings/bindgen/declaration.rb +319 -0
- data/lib/milk_tea/bindings/bindgen/emitter.rb +387 -0
- data/lib/milk_tea/bindings/bindgen/overrides.rb +134 -0
- data/lib/milk_tea/bindings/bindgen/type_mapper.rb +622 -0
- data/lib/milk_tea/bindings/bindgen.rb +207 -0
- data/lib/milk_tea/bindings/cli.rb +121 -0
- data/lib/milk_tea/bindings/imported_bindings/defaults.rb +210 -0
- data/lib/milk_tea/bindings/imported_bindings/generator.rb +1114 -0
- data/lib/milk_tea/bindings/imported_bindings/method_source.rb +190 -0
- data/lib/milk_tea/bindings/imported_bindings/naming.rb +286 -0
- data/lib/milk_tea/bindings/imported_bindings.rb +215 -0
- data/lib/milk_tea/bindings/opengl_registry.rb +547 -0
- data/lib/milk_tea/bindings/raw_bindings/defaults.rb +1338 -0
- data/lib/milk_tea/bindings/raw_bindings.rb +269 -0
- data/lib/milk_tea/bindings/steamworks.rb +629 -0
- data/lib/milk_tea/bindings/upstream_sources.rb +352 -0
- data/lib/milk_tea/bindings/vendored_box2d.rb +79 -0
- data/lib/milk_tea/bindings/vendored_c_library.rb +322 -0
- data/lib/milk_tea/bindings/vendored_cjson.rb +52 -0
- data/lib/milk_tea/bindings/vendored_flecs.rb +78 -0
- data/lib/milk_tea/bindings/vendored_glfw.rb +77 -0
- data/lib/milk_tea/bindings/vendored_libuv.rb +75 -0
- data/lib/milk_tea/bindings/vendored_pcre2.rb +84 -0
- data/lib/milk_tea/bindings/vendored_raylib.rb +131 -0
- data/lib/milk_tea/bindings/vendored_sdl3.rb +78 -0
- data/lib/milk_tea/bindings/vendored_steamworks.rb +71 -0
- data/lib/milk_tea/bindings/vendored_tool.rb +71 -0
- data/lib/milk_tea/bindings/vendored_tools.rb +23 -0
- data/lib/milk_tea/bindings/vendored_tracy.rb +37 -0
- data/lib/milk_tea/bindings.rb +23 -0
- data/lib/milk_tea/core/ast.rb +311 -0
- data/lib/milk_tea/core/async_runtime_installer.rb +28 -0
- data/lib/milk_tea/core/binding_types.rb +18 -0
- data/lib/milk_tea/core/bindings/attribute_binding.rb +58 -0
- data/lib/milk_tea/core/bindings/function_binding.rb +5 -0
- data/lib/milk_tea/core/bindings/module_binding.rb +58 -0
- data/lib/milk_tea/core/bindings/value_binding.rb +21 -0
- data/lib/milk_tea/core/c_backend/aggregate_utils.rb +103 -0
- data/lib/milk_tea/core/c_backend/control_flow_emission.rb +412 -0
- data/lib/milk_tea/core/c_backend/expressions.rb +468 -0
- data/lib/milk_tea/core/c_backend/feature_detection.rb +483 -0
- data/lib/milk_tea/core/c_backend/reachability.rb +398 -0
- data/lib/milk_tea/core/c_backend/reinterpret.rb +226 -0
- data/lib/milk_tea/core/c_backend/runtime_helpers.rb +1080 -0
- data/lib/milk_tea/core/c_backend/statements.rb +563 -0
- data/lib/milk_tea/core/c_backend/type_collectors.rb +1545 -0
- data/lib/milk_tea/core/c_backend/type_declaration.rb +223 -0
- data/lib/milk_tea/core/c_backend/type_system.rb +345 -0
- data/lib/milk_tea/core/c_backend.rb +287 -0
- data/lib/milk_tea/core/compatibility_helpers.rb +79 -0
- data/lib/milk_tea/core/compile_time/const_eval.rb +187 -0
- data/lib/milk_tea/core/compile_time.rb +329 -0
- data/lib/milk_tea/core/control_flow/builder.rb +582 -0
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +143 -0
- data/lib/milk_tea/core/control_flow/dataflow.rb +74 -0
- data/lib/milk_tea/core/control_flow/definite_assignment.rb +79 -0
- data/lib/milk_tea/core/control_flow/graph.rb +90 -0
- data/lib/milk_tea/core/control_flow/liveness.rb +24 -0
- data/lib/milk_tea/core/control_flow/nullability_flow.rb +43 -0
- data/lib/milk_tea/core/control_flow/reachability.rb +22 -0
- data/lib/milk_tea/core/control_flow/termination.rb +31 -0
- data/lib/milk_tea/core/control_flow.rb +34 -0
- data/lib/milk_tea/core/cst.rb +48 -0
- data/lib/milk_tea/core/cst_builder.rb +19 -0
- data/lib/milk_tea/core/ir.rb +85 -0
- data/lib/milk_tea/core/keywords.rb +97 -0
- data/lib/milk_tea/core/lexer/character_classes.rb +60 -0
- data/lib/milk_tea/core/lexer/format_strings.rb +225 -0
- data/lib/milk_tea/core/lexer/heredocs.rb +199 -0
- data/lib/milk_tea/core/lexer/indentation.rb +62 -0
- data/lib/milk_tea/core/lexer/numbers.rb +96 -0
- data/lib/milk_tea/core/lexer/recovery.rb +32 -0
- data/lib/milk_tea/core/lexer/strings.rb +167 -0
- data/lib/milk_tea/core/lexer/symbols.rb +71 -0
- data/lib/milk_tea/core/lexer/trivia.rb +53 -0
- data/lib/milk_tea/core/lexer.rb +430 -0
- data/lib/milk_tea/core/lowering/artifacts.rb +26 -0
- data/lib/milk_tea/core/lowering/async/analysis.rb +245 -0
- data/lib/milk_tea/core/lowering/async/lowering.rb +1399 -0
- data/lib/milk_tea/core/lowering/async/normalization.rb +459 -0
- data/lib/milk_tea/core/lowering/async.rb +714 -0
- data/lib/milk_tea/core/lowering/block.rb +1052 -0
- data/lib/milk_tea/core/lowering/calls.rb +1565 -0
- data/lib/milk_tea/core/lowering/declarations.rb +214 -0
- data/lib/milk_tea/core/lowering/dyn.rb +206 -0
- data/lib/milk_tea/core/lowering/events.rb +1054 -0
- data/lib/milk_tea/core/lowering/expressions.rb +1645 -0
- data/lib/milk_tea/core/lowering/foreign_cstr.rb +206 -0
- data/lib/milk_tea/core/lowering/functions.rb +242 -0
- data/lib/milk_tea/core/lowering/loops.rb +1087 -0
- data/lib/milk_tea/core/lowering/lowering_context.rb +80 -0
- data/lib/milk_tea/core/lowering/proc.rb +419 -0
- data/lib/milk_tea/core/lowering/resolve.rb +2516 -0
- data/lib/milk_tea/core/lowering/scans.rb +220 -0
- data/lib/milk_tea/core/lowering/str_buffer.rb +125 -0
- data/lib/milk_tea/core/lowering/utils.rb +1453 -0
- data/lib/milk_tea/core/lowering.rb +378 -0
- data/lib/milk_tea/core/module_binder.rb +181 -0
- data/lib/milk_tea/core/module_loader/errors.rb +21 -0
- data/lib/milk_tea/core/module_loader.rb +479 -0
- data/lib/milk_tea/core/module_path_resolver.rb +153 -0
- data/lib/milk_tea/core/module_roots.rb +88 -0
- data/lib/milk_tea/core/parser/attributes.rb +71 -0
- data/lib/milk_tea/core/parser/blocks.rb +119 -0
- data/lib/milk_tea/core/parser/declarations.rb +749 -0
- data/lib/milk_tea/core/parser/expressions.rb +624 -0
- data/lib/milk_tea/core/parser/recovery.rb +131 -0
- data/lib/milk_tea/core/parser/statements.rb +756 -0
- data/lib/milk_tea/core/parser/types.rb +271 -0
- data/lib/milk_tea/core/parser.rb +400 -0
- data/lib/milk_tea/core/prelude_installer.rb +29 -0
- data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +917 -0
- data/lib/milk_tea/core/pretty_printer/base_formatter.rb +87 -0
- data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +300 -0
- data/lib/milk_tea/core/pretty_printer.rb +17 -0
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +314 -0
- data/lib/milk_tea/core/semantic_analyzer/attributes.rb +184 -0
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +992 -0
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1735 -0
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +355 -0
- data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +155 -0
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +354 -0
- data/lib/milk_tea/core/semantic_analyzer/generics.rb +383 -0
- data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +78 -0
- data/lib/milk_tea/core/semantic_analyzer/module_context.rb +35 -0
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +1438 -0
- data/lib/milk_tea/core/semantic_analyzer/nullability.rb +421 -0
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +1308 -0
- data/lib/milk_tea/core/semantic_analyzer/top_level.rb +588 -0
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +307 -0
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +851 -0
- data/lib/milk_tea/core/semantic_analyzer.rb +327 -0
- data/lib/milk_tea/core/token.rb +26 -0
- data/lib/milk_tea/core/token_stream.rb +30 -0
- data/lib/milk_tea/core/types/layout.rb +243 -0
- data/lib/milk_tea/core/types/predicates.rb +609 -0
- data/lib/milk_tea/core/types/registry.rb +83 -0
- data/lib/milk_tea/core/types/types.rb +1696 -0
- data/lib/milk_tea/core/types/visitor.rb +442 -0
- data/lib/milk_tea/core.rb +25 -0
- data/lib/milk_tea/dap/backends/lldb_dap.rb +158 -0
- data/lib/milk_tea/dap/protocol.rb +58 -0
- data/lib/milk_tea/dap/server/breakpoints.rb +66 -0
- data/lib/milk_tea/dap/server/debug_map.rb +291 -0
- data/lib/milk_tea/dap/server/handlers.rb +374 -0
- data/lib/milk_tea/dap/server/launch.rb +261 -0
- data/lib/milk_tea/dap/server/lldb_backend.rb +380 -0
- data/lib/milk_tea/dap/server/pause_diagnostics.rb +109 -0
- data/lib/milk_tea/dap/server/utilities.rb +160 -0
- data/lib/milk_tea/dap/server/wire.rb +55 -0
- data/lib/milk_tea/dap/server.rb +131 -0
- data/lib/milk_tea/dap/session.rb +152 -0
- data/lib/milk_tea/dap.rb +6 -0
- data/lib/milk_tea/lsp/dependency_resolution.rb +52 -0
- data/lib/milk_tea/lsp/diagnostics.rb +611 -0
- data/lib/milk_tea/lsp/protocol.rb +104 -0
- data/lib/milk_tea/lsp/server/call_hierarchy.rb +274 -0
- data/lib/milk_tea/lsp/server/code_actions.rb +446 -0
- data/lib/milk_tea/lsp/server/code_lens.rb +97 -0
- data/lib/milk_tea/lsp/server/completion.rb +1099 -0
- data/lib/milk_tea/lsp/server/configuration.rb +167 -0
- data/lib/milk_tea/lsp/server/debug_info.rb +45 -0
- data/lib/milk_tea/lsp/server/definition.rb +779 -0
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +239 -0
- data/lib/milk_tea/lsp/server/execute_command.rb +25 -0
- data/lib/milk_tea/lsp/server/folding_range.rb +153 -0
- data/lib/milk_tea/lsp/server/formatting.rb +575 -0
- data/lib/milk_tea/lsp/server/hover.rb +1465 -0
- data/lib/milk_tea/lsp/server/inlay_hints.rb +204 -0
- data/lib/milk_tea/lsp/server/lifecycle.rb +234 -0
- data/lib/milk_tea/lsp/server/linked_editing_range.rb +43 -0
- data/lib/milk_tea/lsp/server/on_type_formatting.rb +73 -0
- data/lib/milk_tea/lsp/server/progress.rb +47 -0
- data/lib/milk_tea/lsp/server/references.rb +433 -0
- data/lib/milk_tea/lsp/server/rename.rb +598 -0
- data/lib/milk_tea/lsp/server/selection_range.rb +130 -0
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +1745 -0
- data/lib/milk_tea/lsp/server/signature_help.rb +200 -0
- data/lib/milk_tea/lsp/server/text_documents.rb +125 -0
- data/lib/milk_tea/lsp/server/type_hierarchy.rb +167 -0
- data/lib/milk_tea/lsp/server/utilities.rb +520 -0
- data/lib/milk_tea/lsp/server.rb +415 -0
- data/lib/milk_tea/lsp/workspace/analysis.rb +209 -0
- data/lib/milk_tea/lsp/workspace/caches.rb +260 -0
- data/lib/milk_tea/lsp/workspace/collection.rb +98 -0
- data/lib/milk_tea/lsp/workspace/definition_index.rb +184 -0
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +282 -0
- data/lib/milk_tea/lsp/workspace/store.rb +154 -0
- data/lib/milk_tea/lsp/workspace/utilities.rb +490 -0
- data/lib/milk_tea/lsp/workspace.rb +127 -0
- data/lib/milk_tea/lsp.rb +13 -0
- data/lib/milk_tea/packages/atomic_write.rb +63 -0
- data/lib/milk_tea/packages/dependency_solver.rb +194 -0
- data/lib/milk_tea/packages/graph.rb +139 -0
- data/lib/milk_tea/packages/lock.rb +421 -0
- data/lib/milk_tea/packages/manager_cli.rb +485 -0
- data/lib/milk_tea/packages/manifest.rb +356 -0
- data/lib/milk_tea/packages/manifest_editor.rb +134 -0
- data/lib/milk_tea/packages/registry_metadata_provider.rb +34 -0
- data/lib/milk_tea/packages/registry_store.rb +420 -0
- data/lib/milk_tea/packages/services.rb +41 -0
- data/lib/milk_tea/packages/source_cache.rb +71 -0
- data/lib/milk_tea/packages/source_fetcher.rb +124 -0
- data/lib/milk_tea/packages/source_resolver.rb +389 -0
- data/lib/milk_tea/packages/version.rb +164 -0
- data/lib/milk_tea/packages.rb +16 -0
- data/lib/milk_tea/tooling/asset_pack.rb +141 -0
- data/lib/milk_tea/tooling/build.rb +1124 -0
- data/lib/milk_tea/tooling/build_cache.rb +240 -0
- data/lib/milk_tea/tooling/cli.rb +2688 -0
- data/lib/milk_tea/tooling/cst_formatter.rb +13 -0
- data/lib/milk_tea/tooling/debug_info_formatter.rb +456 -0
- data/lib/milk_tea/tooling/debug_map.rb +248 -0
- data/lib/milk_tea/tooling/docs_app.rb +369 -0
- data/lib/milk_tea/tooling/error_formatter.rb +86 -0
- data/lib/milk_tea/tooling/formatter.rb +787 -0
- data/lib/milk_tea/tooling/linter/doc_tags.rb +212 -0
- data/lib/milk_tea/tooling/linter/fix_engine.rb +237 -0
- data/lib/milk_tea/tooling/linter/flow_rules.rb +380 -0
- data/lib/milk_tea/tooling/linter/imports_platform.rb +841 -0
- data/lib/milk_tea/tooling/linter/release_rules.rb +744 -0
- data/lib/milk_tea/tooling/linter/reserved_names.rb +199 -0
- data/lib/milk_tea/tooling/linter/rules.rb +593 -0
- data/lib/milk_tea/tooling/linter/source_helpers.rb +407 -0
- data/lib/milk_tea/tooling/linter/trailing_comma.rb +139 -0
- data/lib/milk_tea/tooling/linter/visitors.rb +1286 -0
- data/lib/milk_tea/tooling/linter.rb +798 -0
- data/lib/milk_tea/tooling/project_scaffold.rb +82 -0
- data/lib/milk_tea/tooling/public/css/docs.css +166 -0
- data/lib/milk_tea/tooling/public/js/docs.js +94 -0
- data/lib/milk_tea/tooling/run.rb +408 -0
- data/lib/milk_tea/tooling/templates/wasm_shell.html +48 -0
- data/lib/milk_tea/tooling/toolchain_cli.rb +157 -0
- data/lib/milk_tea/tooling/views/404.erb +7 -0
- data/lib/milk_tea/tooling/views/index.erb +87 -0
- data/lib/milk_tea/tooling/views/layout.erb +69 -0
- data/lib/milk_tea/tooling/views/module.erb +97 -0
- data/lib/milk_tea/tooling/views/stdlib.erb +21 -0
- data/lib/milk_tea/tooling.rb +20 -0
- data/lib/milk_tea.rb +8 -0
- 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
|