mt-lang 0.3.8 → 0.3.10
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 +4 -4
- data/lib/milk_tea/base.rb +1 -2
- data/lib/milk_tea/bindings/bindgen/ast_parser.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/declaration.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/emitter.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/overrides.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/type_mapper.rb +51 -53
- data/lib/milk_tea/bindings/imported_bindings/generator.rb +7 -9
- data/lib/milk_tea/bindings/imported_bindings/method_source.rb +0 -2
- data/lib/milk_tea/bindings/imported_bindings/naming.rb +6 -8
- data/lib/milk_tea/bindings/imported_bindings.rb +0 -2
- data/lib/milk_tea/bindings/opengl_registry.rb +3 -7
- data/lib/milk_tea/bindings/steamworks.rb +12 -16
- data/lib/milk_tea/bindings/upstream_sources.rb +10 -14
- data/lib/milk_tea/bindings/vendored_box2d.rb +10 -12
- data/lib/milk_tea/bindings/vendored_cjson.rb +6 -8
- data/lib/milk_tea/bindings/vendored_flecs.rb +10 -12
- data/lib/milk_tea/bindings/vendored_glfw.rb +11 -13
- data/lib/milk_tea/bindings/vendored_libuv.rb +11 -13
- data/lib/milk_tea/bindings/vendored_pcre2.rb +11 -13
- data/lib/milk_tea/bindings/vendored_raylib.rb +6 -10
- data/lib/milk_tea/bindings/vendored_sdl3.rb +11 -13
- data/lib/milk_tea/bindings/vendored_steamworks.rb +1 -5
- data/lib/milk_tea/core/ast.rb +103 -45
- data/lib/milk_tea/core/async_runtime_installer.rb +0 -2
- data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -3
- data/lib/milk_tea/core/c_backend/aggregate_utils.rb +147 -84
- data/lib/milk_tea/core/c_backend/control_flow_emission.rb +394 -396
- data/lib/milk_tea/core/c_backend/expressions.rb +489 -476
- data/lib/milk_tea/core/c_backend/feature_detection.rb +446 -437
- data/lib/milk_tea/core/c_backend/format_helpers.rb +0 -2
- data/lib/milk_tea/core/c_backend/reachability.rb +339 -341
- data/lib/milk_tea/core/c_backend/reinterpret.rb +231 -217
- data/lib/milk_tea/core/c_backend/runtime_helpers.rb +531 -526
- data/lib/milk_tea/core/c_backend/statements.rb +528 -530
- data/lib/milk_tea/core/c_backend/type_collectors.rb +1344 -1346
- data/lib/milk_tea/core/c_backend/type_declaration.rb +215 -213
- data/lib/milk_tea/core/c_backend/type_system.rb +347 -349
- data/lib/milk_tea/core/c_backend.rb +17 -9
- data/lib/milk_tea/core/compatibility_helpers.rb +0 -2
- data/lib/milk_tea/core/compile_time/const_eval.rb +7 -12
- data/lib/milk_tea/core/compile_time.rb +32 -38
- data/lib/milk_tea/core/control_flow/builder.rb +3 -5
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +14 -17
- data/lib/milk_tea/core/control_flow/definite_assignment.rb +0 -1
- data/lib/milk_tea/core/ir.rb +10 -10
- data/lib/milk_tea/core/lexer/character_classes.rb +5 -7
- data/lib/milk_tea/core/lexer/format_strings.rb +7 -9
- data/lib/milk_tea/core/lexer/heredocs.rb +22 -22
- data/lib/milk_tea/core/lexer/indentation.rb +0 -2
- data/lib/milk_tea/core/lexer/numbers.rb +0 -2
- data/lib/milk_tea/core/lexer/recovery.rb +0 -2
- data/lib/milk_tea/core/lexer/strings.rb +0 -2
- data/lib/milk_tea/core/lexer/symbols.rb +0 -2
- data/lib/milk_tea/core/lexer/trivia.rb +0 -2
- data/lib/milk_tea/core/lexer.rb +0 -2
- data/lib/milk_tea/core/lowering/async/analysis.rb +0 -2
- data/lib/milk_tea/core/lowering/async/lowering.rb +1264 -1265
- data/lib/milk_tea/core/lowering/async/normalization.rb +0 -2
- data/lib/milk_tea/core/lowering/async.rb +627 -630
- data/lib/milk_tea/core/lowering/block.rb +413 -416
- data/lib/milk_tea/core/lowering/calls.rb +1381 -1384
- data/lib/milk_tea/core/lowering/declarations.rb +180 -183
- data/lib/milk_tea/core/lowering/dyn.rb +48 -50
- data/lib/milk_tea/core/lowering/events.rb +983 -985
- data/lib/milk_tea/core/lowering/expressions.rb +1513 -1518
- data/lib/milk_tea/core/lowering/foreign_cstr.rb +181 -184
- data/lib/milk_tea/core/lowering/functions.rb +185 -188
- data/lib/milk_tea/core/lowering/loops.rb +1028 -1031
- data/lib/milk_tea/core/lowering/proc.rb +363 -366
- data/lib/milk_tea/core/lowering/resolve.rb +2133 -2135
- data/lib/milk_tea/core/lowering/scans.rb +179 -181
- data/lib/milk_tea/core/lowering/str_buffer.rb +102 -105
- data/lib/milk_tea/core/lowering/utils.rb +1040 -1044
- data/lib/milk_tea/core/lowering.rb +5 -7
- data/lib/milk_tea/core/module_binder.rb +0 -2
- data/lib/milk_tea/core/module_loader/errors.rb +4 -2
- data/lib/milk_tea/core/module_loader.rb +113 -20
- data/lib/milk_tea/core/module_path_resolver.rb +0 -2
- data/lib/milk_tea/core/module_roots.rb +6 -8
- data/lib/milk_tea/core/parser/attributes.rb +0 -2
- data/lib/milk_tea/core/parser/blocks.rb +0 -2
- data/lib/milk_tea/core/parser/declarations.rb +0 -2
- data/lib/milk_tea/core/parser/expressions.rb +31 -14
- data/lib/milk_tea/core/parser/recovery.rb +0 -2
- data/lib/milk_tea/core/parser/statements.rb +0 -2
- data/lib/milk_tea/core/parser/types.rb +8 -10
- data/lib/milk_tea/core/parser.rb +1 -3
- data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +31 -33
- data/lib/milk_tea/core/pretty_printer/base_formatter.rb +0 -2
- data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/attributes.rb +14 -16
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -14
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +18 -21
- data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +0 -3
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +12 -15
- data/lib/milk_tea/core/semantic_analyzer/generics.rb +57 -59
- data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +5 -9
- data/lib/milk_tea/core/semantic_analyzer/nullability.rb +0 -3
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +35 -40
- data/lib/milk_tea/core/semantic_analyzer/top_level.rb +10 -12
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -6
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +102 -105
- data/lib/milk_tea/core/semantic_analyzer.rb +17 -8
- data/lib/milk_tea/core/types/layout.rb +21 -22
- data/lib/milk_tea/core/types/predicates.rb +0 -2
- data/lib/milk_tea/core/types/registry.rb +16 -18
- data/lib/milk_tea/core/types/visitor.rb +0 -4
- data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -2
- data/lib/milk_tea/dap/protocol.rb +1 -1
- data/lib/milk_tea/dap/server/breakpoints.rb +0 -2
- data/lib/milk_tea/dap/server/debug_map.rb +0 -2
- data/lib/milk_tea/dap/server/handlers.rb +0 -2
- data/lib/milk_tea/dap/server/launch.rb +0 -2
- data/lib/milk_tea/dap/server/lldb_backend.rb +8 -10
- data/lib/milk_tea/dap/server/pause_diagnostics.rb +14 -16
- data/lib/milk_tea/dap/server/utilities.rb +0 -2
- data/lib/milk_tea/dap/server/wire.rb +0 -2
- data/lib/milk_tea/dap/server.rb +0 -2
- data/lib/milk_tea/lsp/diagnostics.rb +16 -16
- data/lib/milk_tea/lsp/server/call_hierarchy.rb +11 -12
- data/lib/milk_tea/lsp/server/code_actions.rb +355 -357
- data/lib/milk_tea/lsp/server/code_lens.rb +23 -25
- data/lib/milk_tea/lsp/server/completion.rb +873 -875
- data/lib/milk_tea/lsp/server/configuration.rb +129 -131
- data/lib/milk_tea/lsp/server/debug_info.rb +0 -2
- data/lib/milk_tea/lsp/server/definition.rb +564 -565
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +191 -193
- data/lib/milk_tea/lsp/server/execute_command.rb +0 -2
- data/lib/milk_tea/lsp/server/folding_range.rb +0 -4
- data/lib/milk_tea/lsp/server/formatting.rb +478 -480
- data/lib/milk_tea/lsp/server/hover.rb +1282 -1284
- data/lib/milk_tea/lsp/server/inlay_hints.rb +179 -181
- data/lib/milk_tea/lsp/server/lifecycle.rb +192 -194
- data/lib/milk_tea/lsp/server/linked_editing_range.rb +0 -2
- data/lib/milk_tea/lsp/server/on_type_formatting.rb +0 -2
- data/lib/milk_tea/lsp/server/progress.rb +0 -2
- data/lib/milk_tea/lsp/server/references.rb +316 -318
- data/lib/milk_tea/lsp/server/rename.rb +445 -447
- data/lib/milk_tea/lsp/server/selection_range.rb +0 -4
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +1318 -1320
- data/lib/milk_tea/lsp/server/signature_help.rb +146 -148
- data/lib/milk_tea/lsp/server/text_documents.rb +99 -101
- data/lib/milk_tea/lsp/server/type_hierarchy.rb +2 -4
- data/lib/milk_tea/lsp/server/utilities.rb +397 -399
- data/lib/milk_tea/lsp/server.rb +0 -3
- data/lib/milk_tea/lsp/workspace/analysis.rb +40 -42
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +4 -10
- data/lib/milk_tea/lsp/workspace/utilities.rb +19 -19
- data/lib/milk_tea/packages/atomic_write.rb +4 -5
- data/lib/milk_tea/packages/dependency_solver.rb +15 -15
- data/lib/milk_tea/packages/lock.rb +4 -4
- data/lib/milk_tea/packages/manager_cli.rb +1 -1
- data/lib/milk_tea/packages/manifest.rb +3 -3
- data/lib/milk_tea/packages/registry_store.rb +4 -6
- data/lib/milk_tea/packages/services.rb +16 -16
- data/lib/milk_tea/packages/source_cache.rb +4 -6
- data/lib/milk_tea/packages/source_resolver.rb +44 -44
- data/lib/milk_tea/packages/version.rb +8 -8
- data/lib/milk_tea/tooling/build.rb +3 -7
- data/lib/milk_tea/tooling/build_cache.rb +0 -2
- data/lib/milk_tea/tooling/debug_info_formatter.rb +31 -33
- data/lib/milk_tea/tooling/debug_map.rb +8 -10
- data/lib/milk_tea/tooling/docs_app.rb +0 -2
- data/lib/milk_tea/tooling/linter/doc_tags.rb +25 -27
- data/lib/milk_tea/tooling/linter/fix_engine.rb +87 -24
- data/lib/milk_tea/tooling/linter/flow_rules.rb +44 -46
- data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -16
- data/lib/milk_tea/tooling/linter/release_rules.rb +3 -5
- data/lib/milk_tea/tooling/linter/reserved_names.rb +23 -25
- data/lib/milk_tea/tooling/linter/rules.rb +87 -89
- data/lib/milk_tea/tooling/linter/source_helpers.rb +40 -42
- data/lib/milk_tea/tooling/linter/trailing_comma.rb +17 -19
- data/lib/milk_tea/tooling/linter/visitors.rb +162 -50
- data/lib/milk_tea/tooling/linter.rb +0 -2
- data/lib/milk_tea/tooling/project_scaffold.rb +0 -2
- data/lib/milk_tea/tooling/run.rb +0 -2
- data/lib/milk_tea/tooling/toolchain_cli.rb +0 -2
- data/std/cli.mt +13 -32
- data/std/color.mt +28 -28
- data/std/encoding.mt +4 -4
- data/std/graph.mt +1 -2
- data/std/hash.mt +14 -14
- data/std/http/server.mt +3 -3
- data/std/input.mt +1 -1
- data/std/json.mt +1 -1
- data/std/linear_algebra.mt +6 -6
- data/std/net/mux.mt +1 -1
- data/std/noise.mt +23 -23
- data/std/parse.mt +2 -2
- data/std/process.mt +3 -4
- data/std/sparse_set.mt +1 -1
- data/std/steering.mt +5 -5
- data/std/str.mt +1 -1
- data/std/tween.mt +4 -4
- data/std/utility.mt +3 -3
- metadata +2 -2
|
@@ -4,8 +4,6 @@ module MilkTea
|
|
|
4
4
|
module LSP
|
|
5
5
|
class Server
|
|
6
6
|
module ServerHover
|
|
7
|
-
private
|
|
8
|
-
|
|
9
7
|
KEYWORD_HOVER_INFO = {
|
|
10
8
|
'size_of' => {
|
|
11
9
|
signature: 'size_of(Type) -> ptr_uint',
|
|
@@ -302,1627 +300,1627 @@ module MilkTea
|
|
|
302
300
|
},
|
|
303
301
|
}.freeze
|
|
304
302
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
|
|
315
|
-
token = context&.fetch(:token, nil)
|
|
316
|
-
token_kind = token&.type || :none
|
|
317
|
-
unless token&.type == :identifier
|
|
318
|
-
return nil if token.nil?
|
|
319
|
-
unless member_access_token?(context)
|
|
320
|
-
info = builtin_keyword_hover_info(token) ||
|
|
321
|
-
BUILTIN_CALL_HOVER_INFO[token.lexeme]&.slice(:signature, :docs)
|
|
322
|
-
if info
|
|
323
|
-
result_state = 'hit'
|
|
324
|
-
return {
|
|
325
|
-
contents: {
|
|
326
|
-
kind: 'markdown',
|
|
327
|
-
value: render_hover_markdown(info)
|
|
328
|
-
},
|
|
329
|
-
range: token_to_range(token)
|
|
330
|
-
}
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
result_state = 'not-identifier'
|
|
334
|
-
return nil
|
|
335
|
-
end
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
info = resolve_hover_info(uri, lsp_line, lsp_char, token: token, tokens: context[:tokens], token_index: context[:token_index], stages: stages)
|
|
339
|
-
return nil unless info
|
|
303
|
+
def handle_hover(params)
|
|
304
|
+
stages = new_perf_stages
|
|
305
|
+
total_start = stages ? monotonic_time : nil
|
|
306
|
+
uri = params['textDocument']['uri']
|
|
307
|
+
lsp_line = params['position']['line']
|
|
308
|
+
lsp_char = params['position']['character']
|
|
309
|
+
token_kind = 'none'
|
|
310
|
+
result_state = 'miss'
|
|
340
311
|
|
|
341
|
-
result = measure_perf_stage(stages, 'render') do
|
|
342
|
-
{
|
|
343
|
-
contents: {
|
|
344
|
-
kind: 'markdown',
|
|
345
|
-
value: render_hover_markdown(info)
|
|
346
|
-
},
|
|
347
|
-
range: token_to_range(token)
|
|
348
|
-
}
|
|
349
|
-
end
|
|
350
|
-
result_state = 'hit'
|
|
351
|
-
result
|
|
352
|
-
rescue StandardError => e
|
|
353
|
-
result_state = 'error'
|
|
354
|
-
warn "Error in hover handler: #{e.message}"
|
|
355
|
-
nil
|
|
356
|
-
ensure
|
|
357
|
-
log_request_stage_breakdown('textDocument/hover', total_start, uri: uri, stages: stages, summary: "token=#{token_kind} result=#{result_state}")
|
|
358
|
-
end
|
|
359
|
-
|
|
360
|
-
def resolve_hover_info(uri, lsp_line, lsp_char, token: nil, tokens: nil, token_index: nil, stages: nil)
|
|
361
|
-
if token.nil?
|
|
362
312
|
context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
|
|
363
|
-
|
|
313
|
+
token = context&.fetch(:token, nil)
|
|
314
|
+
token_kind = token&.type || :none
|
|
315
|
+
unless token&.type == :identifier
|
|
316
|
+
return nil if token.nil?
|
|
317
|
+
unless member_access_token?(context)
|
|
318
|
+
info = builtin_keyword_hover_info(token) ||
|
|
319
|
+
BUILTIN_CALL_HOVER_INFO[token.lexeme]&.slice(:signature, :docs)
|
|
320
|
+
if info
|
|
321
|
+
result_state = 'hit'
|
|
322
|
+
return {
|
|
323
|
+
contents: {
|
|
324
|
+
kind: 'markdown',
|
|
325
|
+
value: render_hover_markdown(info)
|
|
326
|
+
},
|
|
327
|
+
range: token_to_range(token)
|
|
328
|
+
}
|
|
329
|
+
end
|
|
364
330
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
331
|
+
result_state = 'not-identifier'
|
|
332
|
+
return nil
|
|
333
|
+
end
|
|
334
|
+
end
|
|
369
335
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
member_access_kw = token_index && keyword_member_access_token?(tokens, token_index)
|
|
373
|
-
return nil unless token&.type == :identifier || member_access_kw
|
|
336
|
+
info = resolve_hover_info(uri, lsp_line, lsp_char, token: token, tokens: context[:tokens], token_index: context[:token_index], stages: stages)
|
|
337
|
+
return nil unless info
|
|
374
338
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
source: hover_source_label_from_location(location),
|
|
383
|
-
source_uri: hover_source_uri_from_location(location),
|
|
384
|
-
source_line: hover_source_line_from_location(location),
|
|
339
|
+
result = measure_perf_stage(stages, 'render') do
|
|
340
|
+
{
|
|
341
|
+
contents: {
|
|
342
|
+
kind: 'markdown',
|
|
343
|
+
value: render_hover_markdown(info)
|
|
344
|
+
},
|
|
345
|
+
range: token_to_range(token)
|
|
385
346
|
}
|
|
386
347
|
end
|
|
348
|
+
result_state = 'hit'
|
|
349
|
+
result
|
|
350
|
+
rescue StandardError => e
|
|
351
|
+
result_state = 'error'
|
|
352
|
+
warn "Error in hover handler: #{e.message}"
|
|
353
|
+
nil
|
|
354
|
+
ensure
|
|
355
|
+
log_request_stage_breakdown('textDocument/hover', total_start, uri: uri, stages: stages, summary: "token=#{token_kind} result=#{result_state}")
|
|
387
356
|
end
|
|
388
357
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return {
|
|
394
|
-
signature: "module #{import_info[:module_name]}",
|
|
395
|
-
docs: nil,
|
|
396
|
-
source: hover_source_label_from_location(location),
|
|
397
|
-
source_uri: hover_source_uri_from_location(location),
|
|
398
|
-
source_line: hover_source_line_from_location(location),
|
|
399
|
-
}
|
|
400
|
-
end
|
|
401
|
-
end
|
|
358
|
+
def resolve_hover_info(uri, lsp_line, lsp_char, token: nil, tokens: nil, token_index: nil, stages: nil)
|
|
359
|
+
if token.nil?
|
|
360
|
+
context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
|
|
361
|
+
return nil unless context
|
|
402
362
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
363
|
+
token = context[:token]
|
|
364
|
+
tokens = context[:tokens]
|
|
365
|
+
token_index = context[:token_index]
|
|
366
|
+
end
|
|
407
367
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
368
|
+
tokens ||= @workspace.get_tokens(uri) || []
|
|
369
|
+
token_index = tokens.index(token) if token_index.nil?
|
|
370
|
+
member_access_kw = token_index && keyword_member_access_token?(tokens, token_index)
|
|
371
|
+
return nil unless token&.type == :identifier || member_access_kw
|
|
411
372
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
373
|
+
if token_index
|
|
374
|
+
module_info = module_declaration_info_at(tokens, token_index)
|
|
375
|
+
if module_info
|
|
376
|
+
location = module_definition_location(uri, module_info[:module_name])
|
|
377
|
+
return {
|
|
378
|
+
signature: "module #{module_info[:module_name]}",
|
|
379
|
+
docs: nil,
|
|
380
|
+
source: hover_source_label_from_location(location),
|
|
381
|
+
source_uri: hover_source_uri_from_location(location),
|
|
382
|
+
source_line: hover_source_line_from_location(location),
|
|
383
|
+
}
|
|
384
|
+
end
|
|
385
|
+
end
|
|
415
386
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
387
|
+
if token_index
|
|
388
|
+
import_info = import_path_info_at(tokens, token_index)
|
|
389
|
+
if import_info
|
|
390
|
+
location = module_definition_location(uri, import_info[:module_name])
|
|
391
|
+
return {
|
|
392
|
+
signature: "module #{import_info[:module_name]}",
|
|
393
|
+
docs: nil,
|
|
394
|
+
source: hover_source_label_from_location(location),
|
|
395
|
+
source_uri: hover_source_uri_from_location(location),
|
|
396
|
+
source_line: hover_source_line_from_location(location),
|
|
397
|
+
}
|
|
398
|
+
end
|
|
399
|
+
end
|
|
419
400
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
401
|
+
facts = measure_perf_stage(stages, 'facts') do
|
|
402
|
+
@workspace.get_facts(uri, allow_last_good_fallback: allow_hover_last_good_fallback?(uri))
|
|
403
|
+
end
|
|
404
|
+
return nil unless facts
|
|
423
405
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
source_location = nil
|
|
428
|
-
resolved_via_type_member = false
|
|
406
|
+
if token_index && field_declaration_token?(tokens, token_index)
|
|
407
|
+
return resolve_field_declaration_hover_info(uri, facts, tokens, token_index)
|
|
408
|
+
end
|
|
429
409
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
end
|
|
410
|
+
if token_index && named_argument_label_token?(tokens, token_index)
|
|
411
|
+
return resolve_named_argument_label_hover_info(uri, facts, tokens, token_index)
|
|
412
|
+
end
|
|
434
413
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
signature = for_binding_info[:signature]
|
|
414
|
+
if token_index && (member_hover = resolve_member_access_hover_info(uri, facts, tokens, token_index))
|
|
415
|
+
return member_hover
|
|
438
416
|
end
|
|
439
|
-
end
|
|
440
417
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (local_binding = resolve_as_binding_declaration_hover_binding(facts, name, lsp_line + 1, lsp_char + 1))
|
|
444
|
-
signature = value_hover_signature(local_binding)
|
|
445
|
-
end
|
|
418
|
+
if token_index && (enum_member_hover = resolve_enum_member_hover_info(uri, facts, tokens, token_index))
|
|
419
|
+
return enum_member_hover
|
|
446
420
|
end
|
|
447
|
-
end
|
|
448
421
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
422
|
+
name = token.lexeme
|
|
423
|
+
signature = nil
|
|
424
|
+
docs = nil
|
|
425
|
+
source_location = nil
|
|
426
|
+
resolved_via_type_member = false
|
|
427
|
+
|
|
428
|
+
if (binding = method_binding_at_token(facts, token))
|
|
429
|
+
signature = method_signature(binding)
|
|
430
|
+
source_location = module_member_binding_location(uri, facts.module_name, name, binding)
|
|
452
431
|
end
|
|
453
|
-
end
|
|
454
432
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
signature = "function #{name}(#{params_str}) -> #{binding.type.return_type}"
|
|
459
|
-
elsif (binding = facts.interfaces[name])
|
|
460
|
-
signature = interface_signature(binding)
|
|
461
|
-
source_location = module_member_definition_location(uri, binding.module_name, name)
|
|
462
|
-
elsif facts.types.key?(name)
|
|
463
|
-
type = facts.types[name]
|
|
464
|
-
signature = type_hover_signature(name, type)
|
|
465
|
-
docs ||= BUILTIN_TYPE_DOCS[name]
|
|
466
|
-
elsif !name.include?(".") && (nested = find_nested_type_by_short_name(facts, name))
|
|
467
|
-
signature = type_hover_signature(name, nested)
|
|
468
|
-
docs ||= BUILTIN_TYPE_DOCS[name]
|
|
469
|
-
elsif (binding = facts.values[name])
|
|
470
|
-
signature = value_hover_signature(binding)
|
|
471
|
-
elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (member_info = find_member_in_types(facts, name))
|
|
472
|
-
type, member, value = member_info
|
|
473
|
-
signature = value ? "#{type.name}.#{member} = #{value}" : "#{type.name}.#{member}"
|
|
474
|
-
resolved_via_type_member = true
|
|
475
|
-
elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (arm_sig = find_variant_arm_in_types(facts, name))
|
|
476
|
-
signature = arm_sig
|
|
477
|
-
resolved_via_type_member = true
|
|
478
|
-
elsif (import_binding = facts.imports[name])
|
|
479
|
-
signature = "module #{import_binding.name}"
|
|
480
|
-
source_location = module_definition_location(uri, import_binding.name)
|
|
481
|
-
elsif (attr_binding = facts.attributes[name])
|
|
482
|
-
targets = attr_binding.targets.map(&:to_s).join(", ")
|
|
483
|
-
params_str = attr_binding.params.map { |p| "#{p.name}: #{p.type}" }.join(", ")
|
|
484
|
-
signature = "attribute [#{targets}] #{name}(#{params_str})"
|
|
485
|
-
source_location ||= module_definition_location(uri, facts.module_name)
|
|
486
|
-
else
|
|
487
|
-
dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
|
|
488
|
-
dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
|
|
489
|
-
if dot_receiver && (module_binding = facts.imports[dot_receiver])
|
|
490
|
-
if (fn = module_binding.functions[name])
|
|
491
|
-
params_str = format_params(fn.type.params)
|
|
492
|
-
signature = "function #{name}(#{params_str}) -> #{fn.type.return_type}"
|
|
493
|
-
source_location = module_member_binding_location(uri, module_binding.name, name, fn)
|
|
494
|
-
elsif (val = module_binding.values[name])
|
|
495
|
-
signature = value_hover_signature(val)
|
|
496
|
-
elsif module_binding.types.key?(name)
|
|
497
|
-
signature = "type #{name}"
|
|
498
|
-
docs ||= BUILTIN_TYPE_DOCS[name]
|
|
499
|
-
elsif (binding = module_binding.interfaces[name])
|
|
500
|
-
signature = interface_signature(binding)
|
|
501
|
-
source_location = module_member_definition_location(uri, module_binding.name, name)
|
|
433
|
+
unless signature
|
|
434
|
+
if token_index && (for_binding_info = resolve_for_binding_hover_info(tokens, token_index))
|
|
435
|
+
signature = for_binding_info[:signature]
|
|
502
436
|
end
|
|
437
|
+
end
|
|
503
438
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
439
|
+
unless signature
|
|
440
|
+
if token_index && match_arm_binding_token?(tokens, token_index)
|
|
441
|
+
if (local_binding = resolve_as_binding_declaration_hover_binding(facts, name, lsp_line + 1, lsp_char + 1))
|
|
442
|
+
signature = value_hover_signature(local_binding)
|
|
443
|
+
end
|
|
507
444
|
end
|
|
508
445
|
end
|
|
509
446
|
|
|
510
447
|
unless signature
|
|
511
|
-
if (
|
|
512
|
-
signature =
|
|
513
|
-
source_location = module_member_binding_location(uri, type_method[:module_name], name, type_method[:binding])
|
|
514
|
-
source_location ||= module_member_definition_location(uri, type_method[:module_name], name)
|
|
515
|
-
source_location ||= module_definition_location(uri, type_method[:module_name])
|
|
448
|
+
if (local_binding = resolve_local_hover_binding(facts, name, lsp_line + 1, lsp_char + 1))
|
|
449
|
+
signature = value_hover_signature(local_binding)
|
|
516
450
|
end
|
|
517
451
|
end
|
|
518
452
|
|
|
519
453
|
unless signature
|
|
520
|
-
if
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
454
|
+
if (binding = facts.functions[name])
|
|
455
|
+
params_str = format_params(binding.type.params)
|
|
456
|
+
signature = "function #{name}(#{params_str}) -> #{binding.type.return_type}"
|
|
457
|
+
elsif (binding = facts.interfaces[name])
|
|
458
|
+
signature = interface_signature(binding)
|
|
459
|
+
source_location = module_member_definition_location(uri, binding.module_name, name)
|
|
460
|
+
elsif facts.types.key?(name)
|
|
461
|
+
type = facts.types[name]
|
|
462
|
+
signature = type_hover_signature(name, type)
|
|
463
|
+
docs ||= BUILTIN_TYPE_DOCS[name]
|
|
464
|
+
elsif !name.include?(".") && (nested = find_nested_type_by_short_name(facts, name))
|
|
465
|
+
signature = type_hover_signature(name, nested)
|
|
466
|
+
docs ||= BUILTIN_TYPE_DOCS[name]
|
|
467
|
+
elsif (binding = facts.values[name])
|
|
468
|
+
signature = value_hover_signature(binding)
|
|
469
|
+
elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (member_info = find_member_in_types(facts, name))
|
|
470
|
+
type, member, value = member_info
|
|
471
|
+
signature = value ? "#{type.name}.#{member} = #{value}" : "#{type.name}.#{member}"
|
|
472
|
+
resolved_via_type_member = true
|
|
473
|
+
elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (arm_sig = find_variant_arm_in_types(facts, name))
|
|
474
|
+
signature = arm_sig
|
|
475
|
+
resolved_via_type_member = true
|
|
476
|
+
elsif (import_binding = facts.imports[name])
|
|
477
|
+
signature = "module #{import_binding.name}"
|
|
478
|
+
source_location = module_definition_location(uri, import_binding.name)
|
|
479
|
+
elsif (attr_binding = facts.attributes[name])
|
|
480
|
+
targets = attr_binding.targets.map(&:to_s).join(", ")
|
|
481
|
+
params_str = attr_binding.params.map { |p| "#{p.name}: #{p.type}" }.join(", ")
|
|
482
|
+
signature = "attribute [#{targets}] #{name}(#{params_str})"
|
|
483
|
+
source_location ||= module_definition_location(uri, facts.module_name)
|
|
484
|
+
else
|
|
485
|
+
dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
|
|
486
|
+
dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
|
|
487
|
+
if dot_receiver && (module_binding = facts.imports[dot_receiver])
|
|
488
|
+
if (fn = module_binding.functions[name])
|
|
489
|
+
params_str = format_params(fn.type.params)
|
|
490
|
+
signature = "function #{name}(#{params_str}) -> #{fn.type.return_type}"
|
|
491
|
+
source_location = module_member_binding_location(uri, module_binding.name, name, fn)
|
|
492
|
+
elsif (val = module_binding.values[name])
|
|
493
|
+
signature = value_hover_signature(val)
|
|
494
|
+
elsif module_binding.types.key?(name)
|
|
495
|
+
signature = "type #{name}"
|
|
496
|
+
docs ||= BUILTIN_TYPE_DOCS[name]
|
|
497
|
+
elsif (binding = module_binding.interfaces[name])
|
|
498
|
+
signature = interface_signature(binding)
|
|
499
|
+
source_location = module_member_definition_location(uri, module_binding.name, name)
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
if signature
|
|
503
|
+
source_location ||= module_member_definition_location(uri, module_binding.name, name)
|
|
504
|
+
source_location ||= module_definition_location(uri, module_binding.name)
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
unless signature
|
|
509
|
+
if (type_method = resolve_static_type_receiver_method(facts, dot_receiver, dot_receiver_path, name))
|
|
510
|
+
signature = method_signature(type_method[:binding])
|
|
511
|
+
source_location = module_member_binding_location(uri, type_method[:module_name], name, type_method[:binding])
|
|
512
|
+
source_location ||= module_member_definition_location(uri, type_method[:module_name], name)
|
|
513
|
+
source_location ||= module_definition_location(uri, type_method[:module_name])
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
unless signature
|
|
518
|
+
if dot_receiver
|
|
519
|
+
receiver_name = dot_receiver
|
|
520
|
+
receiver_binding = resolve_local_hover_binding(facts, receiver_name, lsp_line + 1, lsp_char + 1) ||
|
|
521
|
+
facts.values[receiver_name] ||
|
|
522
|
+
facts.functions[receiver_name]
|
|
523
|
+
if receiver_binding && receiver_binding.type
|
|
524
|
+
receiver_type = receiver_binding.respond_to?(:storage_type) ? receiver_binding.storage_type : receiver_binding.type
|
|
525
|
+
methods = methods_for_receiver_type(facts, receiver_type)
|
|
526
|
+
if (method_binding = methods[name])
|
|
527
|
+
signature = method_signature(method_binding)
|
|
528
|
+
else
|
|
529
|
+
type_base = receiver_type.to_s[/^([A-Za-z_]+)/, 1]
|
|
530
|
+
if type_base && (method_sigs = BUILTIN_TYPE_METHOD_SIGNATURES[type_base])
|
|
531
|
+
signature = method_sigs[name]
|
|
532
|
+
end
|
|
534
533
|
end
|
|
535
534
|
end
|
|
536
535
|
end
|
|
537
536
|
end
|
|
538
|
-
end
|
|
539
537
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
538
|
+
unless signature
|
|
539
|
+
if token_index && (builtin_info = builtin_hover_info(name, tokens, token_index))
|
|
540
|
+
signature = builtin_info[:signature]
|
|
541
|
+
docs = builtin_info[:docs]
|
|
542
|
+
end
|
|
544
543
|
end
|
|
545
|
-
end
|
|
546
544
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
545
|
+
unless signature
|
|
546
|
+
if token_index && tokens && parameter_declaration_token?(tokens, token_index)
|
|
547
|
+
signature = resolve_lexical_local_hover_signature(uri, name, tokens[token_index])
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
unless signature
|
|
552
|
+
if token_index && tokens && attribute_target_token?(tokens, token_index)
|
|
553
|
+
signature = "attribute target #{name}"
|
|
554
|
+
end
|
|
550
555
|
end
|
|
551
|
-
end
|
|
552
556
|
|
|
553
|
-
unless signature
|
|
554
|
-
if token_index && tokens && attribute_target_token?(tokens, token_index)
|
|
555
|
-
signature = "attribute target #{name}"
|
|
556
557
|
end
|
|
558
|
+
|
|
559
|
+
return nil unless signature
|
|
557
560
|
end
|
|
558
561
|
|
|
562
|
+
definition_entry = if source_location
|
|
563
|
+
measure_perf_stage(stages, 'definition_entry') { hover_definition_entry_from_location(source_location) }
|
|
564
|
+
elsif resolved_via_type_member
|
|
565
|
+
nil
|
|
566
|
+
else
|
|
567
|
+
measure_perf_stage(stages, 'global_definition') do
|
|
568
|
+
@workspace.find_definition_token_global(
|
|
569
|
+
name,
|
|
570
|
+
preferred_uri: uri,
|
|
571
|
+
before_line: lsp_line + 1,
|
|
572
|
+
before_char: lsp_char + 1,
|
|
573
|
+
)
|
|
574
|
+
end
|
|
559
575
|
end
|
|
560
576
|
|
|
561
|
-
|
|
577
|
+
source_uri = hover_source_uri_for_definition(definition_entry) || hover_source_uri_from_location(source_location)
|
|
578
|
+
source_line = hover_source_line_for_definition(definition_entry) || hover_source_line_from_location(source_location)
|
|
579
|
+
|
|
580
|
+
{
|
|
581
|
+
signature: signature,
|
|
582
|
+
docs: docs || hover_doc_comment_for_definition(definition_entry),
|
|
583
|
+
doc_comment: hover_doc_comment_data_for_definition(definition_entry),
|
|
584
|
+
source: hover_source_label_for_definition(definition_entry) || hover_source_label_from_location(source_location),
|
|
585
|
+
source_uri: source_uri,
|
|
586
|
+
source_line: source_line,
|
|
587
|
+
}
|
|
562
588
|
end
|
|
563
589
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
else
|
|
569
|
-
measure_perf_stage(stages, 'global_definition') do
|
|
570
|
-
@workspace.find_definition_token_global(
|
|
571
|
-
name,
|
|
572
|
-
preferred_uri: uri,
|
|
573
|
-
before_line: lsp_line + 1,
|
|
574
|
-
before_char: lsp_char + 1,
|
|
575
|
-
)
|
|
576
|
-
end
|
|
577
|
-
end
|
|
590
|
+
def token_context_at(uri, lsp_line, lsp_char)
|
|
591
|
+
tokens = @workspace.get_tokens(uri) || []
|
|
592
|
+
interpolation_context = fstring_interpolation_token_context(tokens, lsp_line, lsp_char)
|
|
593
|
+
return interpolation_context if interpolation_context
|
|
578
594
|
|
|
579
|
-
|
|
580
|
-
|
|
595
|
+
token = @workspace.find_token_at(uri, lsp_line, lsp_char)
|
|
596
|
+
return nil unless token
|
|
581
597
|
|
|
582
|
-
|
|
583
|
-
signature: signature,
|
|
584
|
-
docs: docs || hover_doc_comment_for_definition(definition_entry),
|
|
585
|
-
doc_comment: hover_doc_comment_data_for_definition(definition_entry),
|
|
586
|
-
source: hover_source_label_for_definition(definition_entry) || hover_source_label_from_location(source_location),
|
|
587
|
-
source_uri: source_uri,
|
|
588
|
-
source_line: source_line,
|
|
589
|
-
}
|
|
590
|
-
end
|
|
598
|
+
return nil if embedded_heredoc_or_format_heredoc_token?(token)
|
|
591
599
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
return nil unless token
|
|
600
|
+
{
|
|
601
|
+
token: token,
|
|
602
|
+
tokens: tokens,
|
|
603
|
+
token_index: tokens.index(token),
|
|
604
|
+
}
|
|
605
|
+
end
|
|
599
606
|
|
|
600
|
-
|
|
607
|
+
def embedded_heredoc_or_format_heredoc_token?(token)
|
|
608
|
+
return false unless [:string, :cstring, :fstring].include?(token.type)
|
|
601
609
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
tokens: tokens,
|
|
605
|
-
token_index: tokens.index(token),
|
|
606
|
-
}
|
|
607
|
-
end
|
|
610
|
+
tag = token.lexeme[/\A(?:f|c)?<<-([A-Za-z_][A-Za-z0-9_]*)[ \t]*\n/, 1]
|
|
611
|
+
return false if tag.nil?
|
|
608
612
|
|
|
609
|
-
|
|
610
|
-
|
|
613
|
+
%w[GLSL VERT FRAG COMP JSON JSONC SQL HTML].include?(tag)
|
|
614
|
+
end
|
|
611
615
|
|
|
612
|
-
|
|
613
|
-
|
|
616
|
+
def fstring_interpolation_token_context(tokens, lsp_line, lsp_char)
|
|
617
|
+
target_line = lsp_line + 1
|
|
618
|
+
target_char = lsp_char + 1
|
|
614
619
|
|
|
615
|
-
|
|
616
|
-
|
|
620
|
+
fstring_token = tokens.find do |token|
|
|
621
|
+
next false unless token.type == :fstring
|
|
617
622
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
623
|
+
token_contains_position?(token, target_line, target_char)
|
|
624
|
+
end
|
|
625
|
+
return nil unless fstring_token
|
|
621
626
|
|
|
622
|
-
|
|
623
|
-
|
|
627
|
+
Array(fstring_token.literal).each do |part|
|
|
628
|
+
next unless part[:kind] == :expr
|
|
629
|
+
next unless part[:line] == target_line
|
|
624
630
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
631
|
+
expression_tokens = interpolation_expression_tokens(part)
|
|
632
|
+
token = expression_tokens.find { |candidate| token_contains_position?(candidate, target_line, target_char) }
|
|
633
|
+
next unless token
|
|
628
634
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
635
|
+
return {
|
|
636
|
+
token: token,
|
|
637
|
+
tokens: expression_tokens,
|
|
638
|
+
token_index: expression_tokens.index(token),
|
|
639
|
+
}
|
|
640
|
+
end
|
|
632
641
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
next unless token
|
|
642
|
+
nil
|
|
643
|
+
end
|
|
636
644
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
645
|
+
def interpolation_expression_tokens(part)
|
|
646
|
+
source = part[:source]
|
|
647
|
+
return [] if source.nil? || source.strip.empty?
|
|
648
|
+
|
|
649
|
+
MilkTea::Lexer.new(source).lex
|
|
650
|
+
.reject { |token| [:newline, :indent, :dedent, :eof].include?(token.type) }
|
|
651
|
+
.map do |token|
|
|
652
|
+
adjusted_line = part[:line] + token.line - 1
|
|
653
|
+
adjusted_column = token.line == 1 ? (part[:column] + token.column - 1) : token.column
|
|
654
|
+
|
|
655
|
+
token.with(
|
|
656
|
+
line: adjusted_line,
|
|
657
|
+
column: adjusted_column,
|
|
658
|
+
start_offset: nil,
|
|
659
|
+
end_offset: nil,
|
|
660
|
+
leading_trivia: [].freeze,
|
|
661
|
+
trailing_trivia: [].freeze,
|
|
662
|
+
)
|
|
663
|
+
end
|
|
664
|
+
rescue MilkTea::LexError
|
|
665
|
+
[]
|
|
642
666
|
end
|
|
643
667
|
|
|
644
|
-
|
|
645
|
-
|
|
668
|
+
def token_contains_position?(token, target_line, target_char)
|
|
669
|
+
segments = token.lexeme.split("\n", -1)
|
|
670
|
+
end_line = token.line + segments.length - 1
|
|
671
|
+
return false if target_line < token.line || target_line > end_line
|
|
646
672
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
MilkTea::Lexer.new(source).lex
|
|
652
|
-
.reject { |token| [:newline, :indent, :dedent, :eof].include?(token.type) }
|
|
653
|
-
.map do |token|
|
|
654
|
-
adjusted_line = part[:line] + token.line - 1
|
|
655
|
-
adjusted_column = token.line == 1 ? (part[:column] + token.column - 1) : token.column
|
|
656
|
-
|
|
657
|
-
token.with(
|
|
658
|
-
line: adjusted_line,
|
|
659
|
-
column: adjusted_column,
|
|
660
|
-
start_offset: nil,
|
|
661
|
-
end_offset: nil,
|
|
662
|
-
leading_trivia: [].freeze,
|
|
663
|
-
trailing_trivia: [].freeze,
|
|
664
|
-
)
|
|
665
|
-
end
|
|
666
|
-
rescue MilkTea::LexError
|
|
667
|
-
[]
|
|
668
|
-
end
|
|
673
|
+
if segments.length == 1
|
|
674
|
+
return token.column <= target_char && target_char < (token.column + segments.first.length)
|
|
675
|
+
end
|
|
669
676
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
return false if target_line < token.line || target_line > end_line
|
|
677
|
+
if target_line == token.line
|
|
678
|
+
return token.column <= target_char && target_char <= (token.column + segments.first.length - 1)
|
|
679
|
+
end
|
|
674
680
|
|
|
675
|
-
|
|
676
|
-
return token.column <= target_char && target_char < (token.column + segments.first.length)
|
|
681
|
+
target_char <= segments.fetch(target_line - token.line).length
|
|
677
682
|
end
|
|
678
683
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
end
|
|
684
|
+
def render_hover_markdown(info)
|
|
685
|
+
lines = []
|
|
682
686
|
|
|
683
|
-
|
|
684
|
-
|
|
687
|
+
signature = info[:signature].to_s
|
|
688
|
+
shortened, modules = shorten_qualified_types(signature)
|
|
685
689
|
|
|
686
|
-
|
|
687
|
-
|
|
690
|
+
lines << "```milk-tea"
|
|
691
|
+
lines << shortened
|
|
692
|
+
lines << "```"
|
|
688
693
|
|
|
689
|
-
|
|
690
|
-
|
|
694
|
+
unless modules.empty?
|
|
695
|
+
prefix = 'From'
|
|
696
|
+
lines << "*#{prefix} #{modules.join(', ')}*"
|
|
697
|
+
end
|
|
691
698
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
699
|
+
rendered_doc_comment = false
|
|
700
|
+
if info[:doc_comment].is_a?(Hash)
|
|
701
|
+
rendered_doc_comment = append_structured_doc_comment_markdown(lines, info[:doc_comment])
|
|
702
|
+
end
|
|
695
703
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
704
|
+
docs = info[:docs].to_s.strip
|
|
705
|
+
unless rendered_doc_comment || docs.empty?
|
|
706
|
+
lines << ""
|
|
707
|
+
lines << docs
|
|
708
|
+
end
|
|
700
709
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
710
|
+
source_uri = info[:source_uri]
|
|
711
|
+
source_line = info[:source_line]
|
|
712
|
+
source_label = info[:source].to_s.strip
|
|
713
|
+
unless source_label.empty?
|
|
714
|
+
lines << ""
|
|
715
|
+
if source_uri && source_line
|
|
716
|
+
link_uri = "#{source_uri}#L#{source_line}"
|
|
717
|
+
lines << "Defined at: [#{source_label}](#{link_uri})"
|
|
718
|
+
else
|
|
719
|
+
lines << "Defined at: #{source_label}"
|
|
720
|
+
end
|
|
721
|
+
end
|
|
705
722
|
|
|
706
|
-
|
|
707
|
-
unless rendered_doc_comment || docs.empty?
|
|
708
|
-
lines << ""
|
|
709
|
-
lines << docs
|
|
723
|
+
lines.join("\n")
|
|
710
724
|
end
|
|
711
725
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
lines << "Defined at: [#{source_label}](#{link_uri})"
|
|
720
|
-
else
|
|
721
|
-
lines << "Defined at: #{source_label}"
|
|
726
|
+
def shorten_qualified_types(signature)
|
|
727
|
+
modules = []
|
|
728
|
+
shortened = signature.gsub(/\b([a-z_][\w]*(?:\.[a-z_][\w]*)*\.)([A-Z]\w*(?:\[[^\]]*\])?(?:\s*\|\s*(?:[a-z_][\w]*(?:\.[a-z_][\w]*)*\.)?[A-Z]\w*(?:\[[^\]]*\])?)*)\b/) do
|
|
729
|
+
prefix = $1
|
|
730
|
+
mod_name = prefix.delete_suffix('.')
|
|
731
|
+
modules << mod_name unless modules.include?(mod_name)
|
|
732
|
+
$2
|
|
722
733
|
end
|
|
734
|
+
[shortened, modules]
|
|
723
735
|
end
|
|
724
736
|
|
|
725
|
-
lines
|
|
726
|
-
|
|
737
|
+
def append_structured_doc_comment_markdown(lines, doc_comment)
|
|
738
|
+
body = doc_comment[:body_markdown].to_s.strip
|
|
739
|
+
tags = doc_comment.fetch(:tags, {})
|
|
740
|
+
params = Array(tags[:params]).reject { |entry| entry[:name].to_s.strip.empty? }
|
|
741
|
+
returns = tags[:returns]
|
|
742
|
+
throws = Array(tags[:throws]).reject { |entry| entry[:text].to_s.strip.empty? }
|
|
743
|
+
see_also = Array(tags[:see]).reject { |entry| entry[:text].to_s.strip.empty? }
|
|
727
744
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
$2
|
|
735
|
-
end
|
|
736
|
-
[shortened, modules]
|
|
737
|
-
end
|
|
745
|
+
wrote = false
|
|
746
|
+
unless body.empty?
|
|
747
|
+
lines << ""
|
|
748
|
+
lines << body
|
|
749
|
+
wrote = true
|
|
750
|
+
end
|
|
738
751
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
lines << "- `#{entry[:name]}`"
|
|
761
|
-
else
|
|
762
|
-
lines << "- `#{entry[:name]}`: #{description}"
|
|
752
|
+
unless params.empty?
|
|
753
|
+
lines << ""
|
|
754
|
+
lines << "**Parameters**"
|
|
755
|
+
params.each do |entry|
|
|
756
|
+
description = entry[:text].to_s.strip
|
|
757
|
+
if description.empty?
|
|
758
|
+
lines << "- `#{entry[:name]}`"
|
|
759
|
+
else
|
|
760
|
+
lines << "- `#{entry[:name]}`: #{description}"
|
|
761
|
+
end
|
|
762
|
+
end
|
|
763
|
+
wrote = true
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
if returns
|
|
767
|
+
description = returns[:text].to_s.strip
|
|
768
|
+
unless description.empty?
|
|
769
|
+
lines << ""
|
|
770
|
+
lines << "**Returns**"
|
|
771
|
+
lines << description
|
|
772
|
+
wrote = true
|
|
763
773
|
end
|
|
764
774
|
end
|
|
765
|
-
wrote = true
|
|
766
|
-
end
|
|
767
775
|
|
|
768
|
-
|
|
769
|
-
description = returns[:text].to_s.strip
|
|
770
|
-
unless description.empty?
|
|
776
|
+
unless throws.empty?
|
|
771
777
|
lines << ""
|
|
772
|
-
lines << "**
|
|
773
|
-
|
|
778
|
+
lines << "**Throws**"
|
|
779
|
+
throws.each do |entry|
|
|
780
|
+
lines << "- #{entry[:text]}"
|
|
781
|
+
end
|
|
774
782
|
wrote = true
|
|
775
783
|
end
|
|
776
|
-
end
|
|
777
784
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
785
|
+
unless see_also.empty?
|
|
786
|
+
lines << ""
|
|
787
|
+
lines << "**See Also**"
|
|
788
|
+
see_also.each do |entry|
|
|
789
|
+
lines << "- #{entry[:text]}"
|
|
790
|
+
end
|
|
791
|
+
wrote = true
|
|
783
792
|
end
|
|
784
|
-
wrote = true
|
|
785
|
-
end
|
|
786
793
|
|
|
787
|
-
|
|
788
|
-
lines << ""
|
|
789
|
-
lines << "**See Also**"
|
|
790
|
-
see_also.each do |entry|
|
|
791
|
-
lines << "- #{entry[:text]}"
|
|
792
|
-
end
|
|
793
|
-
wrote = true
|
|
794
|
+
wrote
|
|
794
795
|
end
|
|
795
796
|
|
|
796
|
-
|
|
797
|
-
|
|
797
|
+
def hover_doc_comment_for_definition(definition_entry)
|
|
798
|
+
return nil unless definition_entry
|
|
798
799
|
|
|
799
|
-
|
|
800
|
-
|
|
800
|
+
@workspace.doc_comment_for_definition(definition_entry[:uri], definition_entry[:token])
|
|
801
|
+
end
|
|
801
802
|
|
|
802
|
-
|
|
803
|
-
|
|
803
|
+
def hover_doc_comment_data_for_definition(definition_entry)
|
|
804
|
+
return nil unless definition_entry
|
|
804
805
|
|
|
805
|
-
|
|
806
|
-
|
|
806
|
+
@workspace.doc_comment_data_for_definition(definition_entry[:uri], definition_entry[:token])
|
|
807
|
+
end
|
|
807
808
|
|
|
808
|
-
|
|
809
|
-
|
|
809
|
+
def signature_help_doc_comment_for_call(uri, name, lsp_line, lsp_char)
|
|
810
|
+
definition_entry = @workspace.find_definition_token_global(
|
|
811
|
+
name,
|
|
812
|
+
preferred_uri: uri,
|
|
813
|
+
before_line: lsp_line + 1,
|
|
814
|
+
before_char: lsp_char + 1,
|
|
815
|
+
)
|
|
816
|
+
return nil unless definition_entry
|
|
810
817
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
name,
|
|
814
|
-
preferred_uri: uri,
|
|
815
|
-
before_line: lsp_line + 1,
|
|
816
|
-
before_char: lsp_char + 1,
|
|
817
|
-
)
|
|
818
|
-
return nil unless definition_entry
|
|
818
|
+
@workspace.doc_comment_data_for_definition(definition_entry[:uri], definition_entry[:token])
|
|
819
|
+
end
|
|
819
820
|
|
|
820
|
-
|
|
821
|
-
|
|
821
|
+
def signature_help_markdown_for_doc_comment(doc_comment)
|
|
822
|
+
return '' unless doc_comment.is_a?(Hash)
|
|
822
823
|
|
|
823
|
-
|
|
824
|
-
|
|
824
|
+
lines = []
|
|
825
|
+
body = doc_comment[:body_markdown].to_s.strip
|
|
826
|
+
lines << body unless body.empty?
|
|
825
827
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
828
|
+
returns = doc_tag_return_description(doc_comment)
|
|
829
|
+
unless returns.empty?
|
|
830
|
+
lines << '' unless lines.empty?
|
|
831
|
+
lines << "**Returns**"
|
|
832
|
+
lines << returns
|
|
833
|
+
end
|
|
829
834
|
|
|
830
|
-
|
|
831
|
-
unless returns.empty?
|
|
832
|
-
lines << '' unless lines.empty?
|
|
833
|
-
lines << "**Returns**"
|
|
834
|
-
lines << returns
|
|
835
|
+
lines.join("\n")
|
|
835
836
|
end
|
|
836
837
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
def doc_tag_param_descriptions(doc_comment)
|
|
841
|
-
return {} unless doc_comment.is_a?(Hash)
|
|
838
|
+
def doc_tag_param_descriptions(doc_comment)
|
|
839
|
+
return {} unless doc_comment.is_a?(Hash)
|
|
842
840
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
841
|
+
Array(doc_comment.dig(:tags, :params)).each_with_object({}) do |entry, docs|
|
|
842
|
+
name = entry[:name].to_s
|
|
843
|
+
next if name.empty?
|
|
846
844
|
|
|
847
|
-
|
|
848
|
-
|
|
845
|
+
text = entry[:text].to_s.strip
|
|
846
|
+
next if text.empty?
|
|
849
847
|
|
|
850
|
-
|
|
848
|
+
docs[name] = text
|
|
849
|
+
end
|
|
851
850
|
end
|
|
852
|
-
end
|
|
853
851
|
|
|
854
|
-
|
|
855
|
-
|
|
852
|
+
def doc_tag_return_description(doc_comment)
|
|
853
|
+
return '' unless doc_comment.is_a?(Hash)
|
|
856
854
|
|
|
857
|
-
|
|
858
|
-
|
|
855
|
+
doc_comment.dig(:tags, :returns, :text).to_s.strip
|
|
856
|
+
end
|
|
859
857
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
858
|
+
def completion_function_documentation(uri, name, cache:)
|
|
859
|
+
key = [uri, name]
|
|
860
|
+
return cache[key] if cache.key?(key)
|
|
863
861
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
862
|
+
definition_entry = @workspace.find_definition_token_global(name, preferred_uri: uri)
|
|
863
|
+
unless definition_entry
|
|
864
|
+
cache[key] = ''
|
|
865
|
+
return ''
|
|
866
|
+
end
|
|
869
867
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
868
|
+
doc_comment = @workspace.doc_comment_data_for_definition(definition_entry[:uri], definition_entry[:token])
|
|
869
|
+
cache[key] = signature_help_markdown_for_doc_comment(doc_comment)
|
|
870
|
+
end
|
|
873
871
|
|
|
874
|
-
|
|
875
|
-
|
|
872
|
+
def hover_source_label_for_definition(definition_entry)
|
|
873
|
+
return nil unless definition_entry
|
|
876
874
|
|
|
877
|
-
|
|
878
|
-
|
|
875
|
+
hover_source_label(definition_entry[:uri], definition_entry[:token].line)
|
|
876
|
+
end
|
|
879
877
|
|
|
880
|
-
|
|
881
|
-
|
|
878
|
+
def hover_source_uri_for_definition(definition_entry)
|
|
879
|
+
return nil unless definition_entry
|
|
882
880
|
|
|
883
|
-
|
|
884
|
-
|
|
881
|
+
definition_entry[:uri]
|
|
882
|
+
end
|
|
885
883
|
|
|
886
|
-
|
|
887
|
-
|
|
884
|
+
def hover_source_line_for_definition(definition_entry)
|
|
885
|
+
return nil unless definition_entry
|
|
888
886
|
|
|
889
|
-
|
|
890
|
-
|
|
887
|
+
definition_entry[:token].line
|
|
888
|
+
end
|
|
891
889
|
|
|
892
|
-
|
|
893
|
-
|
|
890
|
+
def hover_source_label_from_location(location)
|
|
891
|
+
return nil unless location
|
|
894
892
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
893
|
+
line = location.dig(:range, :start, :line)
|
|
894
|
+
hover_source_label(location[:uri], (line || 0) + 1)
|
|
895
|
+
end
|
|
898
896
|
|
|
899
|
-
|
|
900
|
-
|
|
897
|
+
def hover_source_uri_from_location(location)
|
|
898
|
+
return nil unless location
|
|
901
899
|
|
|
902
|
-
|
|
903
|
-
|
|
900
|
+
location[:uri]
|
|
901
|
+
end
|
|
904
902
|
|
|
905
|
-
|
|
906
|
-
|
|
903
|
+
def hover_source_line_from_location(location)
|
|
904
|
+
return nil unless location
|
|
907
905
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
906
|
+
line = location.dig(:range, :start, :line)
|
|
907
|
+
(line || 0) + 1
|
|
908
|
+
end
|
|
911
909
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
910
|
+
def hover_source_label(uri, line)
|
|
911
|
+
path = uri_to_path(uri)
|
|
912
|
+
return nil unless path
|
|
913
|
+
|
|
914
|
+
display = path
|
|
915
|
+
if @root_uri
|
|
916
|
+
root_path = uri_to_path(@root_uri)
|
|
917
|
+
if root_path
|
|
918
|
+
begin
|
|
919
|
+
relative = Pathname.new(path).relative_path_from(Pathname.new(root_path)).to_s
|
|
920
|
+
display = relative unless relative.start_with?('..')
|
|
921
|
+
rescue StandardError
|
|
922
|
+
display = path
|
|
923
|
+
end
|
|
925
924
|
end
|
|
926
925
|
end
|
|
927
|
-
end
|
|
928
|
-
|
|
929
|
-
"#{display}:#{line}"
|
|
930
|
-
end
|
|
931
|
-
|
|
932
|
-
def hover_definition_entry_from_location(location)
|
|
933
|
-
return nil unless location
|
|
934
926
|
|
|
935
|
-
|
|
936
|
-
|
|
927
|
+
"#{display}:#{line}"
|
|
928
|
+
end
|
|
937
929
|
|
|
938
|
-
|
|
939
|
-
|
|
930
|
+
def hover_definition_entry_from_location(location)
|
|
931
|
+
return nil unless location
|
|
940
932
|
|
|
941
|
-
|
|
942
|
-
|
|
933
|
+
start = location.dig(:range, :start)
|
|
934
|
+
return nil unless start
|
|
943
935
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
end
|
|
936
|
+
token = @workspace.find_token_at(location[:uri], start[:line], start[:character])
|
|
937
|
+
return nil unless token
|
|
947
938
|
|
|
948
|
-
|
|
949
|
-
method_lines = binding.methods.values.map do |method|
|
|
950
|
-
" #{interface_method_signature(method)}"
|
|
939
|
+
{ uri: location[:uri], token: token }
|
|
951
940
|
end
|
|
952
941
|
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
def interface_method_signature(binding)
|
|
957
|
-
keyword = binding.kind == :editable ? 'editable function' : 'function'
|
|
958
|
-
keyword = "async #{keyword}" if binding.async
|
|
959
|
-
"#{keyword} #{binding.name}(#{format_params(binding.params)}) -> #{binding.return_type}"
|
|
960
|
-
end
|
|
942
|
+
def format_params(params)
|
|
943
|
+
params.map { |p| "#{p.name}: #{p.type}" }.join(', ')
|
|
944
|
+
end
|
|
961
945
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
946
|
+
def interface_signature(binding)
|
|
947
|
+
method_lines = binding.methods.values.map do |method|
|
|
948
|
+
" #{interface_method_signature(method)}"
|
|
949
|
+
end
|
|
965
950
|
|
|
966
|
-
|
|
967
|
-
|
|
951
|
+
(["interface #{binding.name}"] + method_lines).join("\n")
|
|
952
|
+
end
|
|
968
953
|
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
954
|
+
def interface_method_signature(binding)
|
|
955
|
+
keyword = binding.kind == :editable ? 'editable function' : 'function'
|
|
956
|
+
keyword = "async #{keyword}" if binding.async
|
|
957
|
+
"#{keyword} #{binding.name}(#{format_params(binding.params)}) -> #{binding.return_type}"
|
|
958
|
+
end
|
|
972
959
|
|
|
973
|
-
|
|
974
|
-
|
|
960
|
+
def resolve_dot_receiver_value_type(facts, receiver_name, line, char)
|
|
961
|
+
local_type = resolve_local_hover_type(facts, receiver_name, line, char)
|
|
962
|
+
return local_type if local_type
|
|
975
963
|
|
|
976
|
-
|
|
977
|
-
facts,
|
|
978
|
-
chain[:segments].first[:name],
|
|
979
|
-
chain[:line],
|
|
980
|
-
chain[:char],
|
|
981
|
-
)
|
|
982
|
-
unless current_type
|
|
983
|
-
first_name = chain[:segments].first[:name]
|
|
984
|
-
current_type = facts.types[first_name]
|
|
964
|
+
facts.values[receiver_name]&.type
|
|
985
965
|
end
|
|
986
|
-
return nil unless current_type
|
|
987
966
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
967
|
+
def resolve_member_access_hover_info(current_uri, facts, tokens, token_index)
|
|
968
|
+
chain = member_access_chain_at(tokens, token_index)
|
|
969
|
+
return nil unless chain
|
|
970
|
+
|
|
971
|
+
hovered_segment = chain[:segments].find { |segment| segment[:token_index] == token_index }
|
|
972
|
+
return nil unless hovered_segment && hovered_segment[:position].positive?
|
|
973
|
+
|
|
974
|
+
current_type = resolve_dot_receiver_value_type(
|
|
975
|
+
facts,
|
|
976
|
+
chain[:segments].first[:name],
|
|
977
|
+
chain[:line],
|
|
978
|
+
chain[:char],
|
|
979
|
+
)
|
|
980
|
+
unless current_type
|
|
981
|
+
first_name = chain[:segments].first[:name]
|
|
982
|
+
current_type = facts.types[first_name]
|
|
983
|
+
end
|
|
984
|
+
return nil unless current_type
|
|
985
|
+
|
|
986
|
+
chain[:segments][1..hovered_segment[:position]].each do |segment|
|
|
987
|
+
field_receiver_type = project_field_receiver_type_for_completion(current_type, facts)
|
|
988
|
+
if field_receiver_type.respond_to?(:field) && (field_type = field_receiver_type.field(segment[:name]))
|
|
989
|
+
source_location = field_definition_location(current_uri, field_receiver_type, segment[:name])
|
|
990
|
+
|
|
991
|
+
if segment[:token_index] == token_index
|
|
992
|
+
definition_entry = hover_definition_entry_from_location(source_location)
|
|
993
|
+
return {
|
|
994
|
+
signature: field_hover_signature(segment[:name], field_type),
|
|
995
|
+
docs: hover_doc_comment_for_definition(definition_entry),
|
|
996
|
+
source: hover_source_label_from_location(source_location),
|
|
997
|
+
source_uri: hover_source_uri_from_location(source_location),
|
|
998
|
+
source_line: hover_source_line_from_location(source_location),
|
|
999
|
+
}
|
|
1000
|
+
end
|
|
992
1001
|
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
return {
|
|
996
|
-
signature: field_hover_signature(segment[:name], field_type),
|
|
997
|
-
docs: hover_doc_comment_for_definition(definition_entry),
|
|
998
|
-
source: hover_source_label_from_location(source_location),
|
|
999
|
-
source_uri: hover_source_uri_from_location(source_location),
|
|
1000
|
-
source_line: hover_source_line_from_location(source_location),
|
|
1001
|
-
}
|
|
1002
|
+
current_type = field_type
|
|
1003
|
+
next
|
|
1002
1004
|
end
|
|
1003
1005
|
|
|
1004
|
-
current_type =
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
}
|
|
1006
|
+
if current_type.respond_to?(:nested_types) && (nested = current_type.nested_types[segment[:name]])
|
|
1007
|
+
if segment[:token_index] == token_index
|
|
1008
|
+
return {
|
|
1009
|
+
signature: type_hover_signature(segment[:name], nested),
|
|
1010
|
+
docs: BUILTIN_TYPE_DOCS[segment[:name]],
|
|
1011
|
+
}
|
|
1012
|
+
end
|
|
1013
|
+
current_type = nested
|
|
1014
|
+
next
|
|
1014
1015
|
end
|
|
1015
|
-
current_type = nested
|
|
1016
|
-
next
|
|
1017
|
-
end
|
|
1018
1016
|
|
|
1019
|
-
|
|
1017
|
+
next unless segment[:token_index] == token_index
|
|
1020
1018
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1019
|
+
method_receiver_type = project_method_receiver_type_for_completion(current_type)
|
|
1020
|
+
method_info = member_method_info_for_receiver_type(facts, method_receiver_type, segment[:name])
|
|
1021
|
+
return nil unless method_info
|
|
1024
1022
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1023
|
+
source_location = module_member_binding_location(current_uri, method_info[:module_name], segment[:name], method_info[:binding])
|
|
1024
|
+
source_location ||= module_member_definition_location(current_uri, method_info[:module_name], segment[:name])
|
|
1025
|
+
definition_entry = hover_definition_entry_from_location(source_location)
|
|
1028
1026
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1027
|
+
return {
|
|
1028
|
+
signature: method_signature(method_info[:binding]),
|
|
1029
|
+
docs: hover_doc_comment_for_definition(definition_entry),
|
|
1030
|
+
source: hover_source_label_from_location(source_location),
|
|
1031
|
+
source_uri: hover_source_uri_from_location(source_location),
|
|
1032
|
+
source_line: hover_source_line_from_location(source_location),
|
|
1033
|
+
}
|
|
1034
|
+
end
|
|
1035
|
+
|
|
1036
|
+
nil
|
|
1036
1037
|
end
|
|
1037
1038
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1039
|
+
def member_method_info_for_receiver_type(facts, receiver_type, method_name)
|
|
1040
|
+
return nil unless receiver_type
|
|
1040
1041
|
|
|
1041
|
-
|
|
1042
|
-
return nil unless receiver_type
|
|
1042
|
+
dispatch_receiver_type = method_dispatch_receiver_type_for_completion(receiver_type)
|
|
1043
1043
|
|
|
1044
|
-
|
|
1044
|
+
if (binding = find_method_entry(facts.methods, receiver_type, method_name))
|
|
1045
|
+
return {
|
|
1046
|
+
binding: binding,
|
|
1047
|
+
module_name: facts.module_name,
|
|
1048
|
+
}
|
|
1049
|
+
end
|
|
1045
1050
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1051
|
+
if dispatch_receiver_type != receiver_type && (binding = find_method_entry(facts.methods, dispatch_receiver_type, method_name))
|
|
1052
|
+
return {
|
|
1053
|
+
binding: binding,
|
|
1054
|
+
module_name: facts.module_name,
|
|
1055
|
+
}
|
|
1056
|
+
end
|
|
1052
1057
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
binding
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1058
|
+
facts.imports.each_value do |module_binding|
|
|
1059
|
+
binding = find_method_entry(module_binding.methods, receiver_type, method_name)
|
|
1060
|
+
if binding.nil? && dispatch_receiver_type != receiver_type
|
|
1061
|
+
binding = find_method_entry(module_binding.methods, dispatch_receiver_type, method_name)
|
|
1062
|
+
end
|
|
1063
|
+
next unless binding
|
|
1059
1064
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1065
|
+
return {
|
|
1066
|
+
binding: binding,
|
|
1067
|
+
module_name: module_binding.name,
|
|
1068
|
+
}
|
|
1064
1069
|
end
|
|
1065
|
-
next unless binding
|
|
1066
1070
|
|
|
1067
|
-
|
|
1068
|
-
binding: binding,
|
|
1069
|
-
module_name: module_binding.name,
|
|
1070
|
-
}
|
|
1071
|
+
nil
|
|
1071
1072
|
end
|
|
1072
1073
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
def find_method_entry(methods_table, receiver_type, method_name)
|
|
1077
|
-
methods_table.fetch(receiver_type, {})[method_name] || methods_table.fetch(receiver_type, {})["static:#{method_name}"]
|
|
1078
|
-
end
|
|
1074
|
+
def find_method_entry(methods_table, receiver_type, method_name)
|
|
1075
|
+
methods_table.fetch(receiver_type, {})[method_name] || methods_table.fetch(receiver_type, {})["static:#{method_name}"]
|
|
1076
|
+
end
|
|
1079
1077
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1078
|
+
def resolve_enum_member_hover_info(current_uri, facts, tokens, token_index)
|
|
1079
|
+
member_info = resolve_enum_member_access_info(current_uri, facts, tokens, token_index)
|
|
1080
|
+
return nil unless member_info
|
|
1083
1081
|
|
|
1084
|
-
|
|
1085
|
-
|
|
1082
|
+
signature = "#{member_info[:member_name]}: #{member_info[:receiver_label]}"
|
|
1083
|
+
signature += " = #{member_info[:value_text]}" if member_info[:value_text]
|
|
1086
1084
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1085
|
+
{
|
|
1086
|
+
signature: signature,
|
|
1087
|
+
docs: nil,
|
|
1088
|
+
source: hover_source_label_from_location(member_info[:location]),
|
|
1089
|
+
source_uri: hover_source_uri_from_location(member_info[:location]),
|
|
1090
|
+
source_line: hover_source_line_from_location(member_info[:location]),
|
|
1091
|
+
}
|
|
1092
|
+
end
|
|
1095
1093
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1094
|
+
def resolve_enum_member_definition_location(current_uri, facts, tokens, token_index)
|
|
1095
|
+
resolve_enum_member_access_info(current_uri, facts, tokens, token_index)&.fetch(:location, nil)
|
|
1096
|
+
end
|
|
1099
1097
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1098
|
+
def resolve_enum_member_access_info(current_uri, facts, tokens, token_index)
|
|
1099
|
+
return nil unless type_name_member_access?(tokens, token_index, facts)
|
|
1102
1100
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1101
|
+
token = tokens[token_index]
|
|
1102
|
+
token_end_char = token.column - 1 + token.lexeme.length
|
|
1103
|
+
receiver_name = @workspace.find_dot_receiver(current_uri, token.line - 1, token_end_char)
|
|
1104
|
+
receiver_path = @workspace.find_dot_receiver_path(current_uri, token.line - 1, token_end_char)
|
|
1105
|
+
receiver_info = resolve_type_receiver_info(facts, receiver_name, receiver_path)
|
|
1106
|
+
return nil unless receiver_info
|
|
1109
1107
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1108
|
+
receiver_type = receiver_info[:type]
|
|
1109
|
+
return nil unless receiver_type.is_a?(Types::EnumBase)
|
|
1110
|
+
return nil unless receiver_type.member(token.lexeme)
|
|
1113
1111
|
|
|
1114
|
-
|
|
1112
|
+
owner_module_name = receiver_type.respond_to?(:module_name) ? receiver_type.module_name : receiver_info[:module_name]
|
|
1115
1113
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1114
|
+
{
|
|
1115
|
+
receiver_label: receiver_info[:label],
|
|
1116
|
+
member_name: token.lexeme,
|
|
1117
|
+
value_text: enum_member_value_text(current_uri, owner_module_name, receiver_type.name, token.lexeme),
|
|
1118
|
+
location: enum_member_definition_location(current_uri, owner_module_name, receiver_type.name, token.lexeme),
|
|
1119
|
+
}
|
|
1120
|
+
end
|
|
1123
1121
|
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1122
|
+
def resolve_field_declaration_hover_info(current_uri, facts, tokens, token_index)
|
|
1123
|
+
receiver_info = field_declaration_receiver_info(facts, tokens, token_index)
|
|
1124
|
+
return nil unless receiver_info
|
|
1127
1125
|
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1126
|
+
field_name = tokens[token_index].lexeme
|
|
1127
|
+
receiver_type = project_field_receiver_type_for_completion(receiver_info[:type], facts)
|
|
1128
|
+
return nil unless receiver_type.respond_to?(:field)
|
|
1131
1129
|
|
|
1132
|
-
|
|
1133
|
-
|
|
1130
|
+
field_type = receiver_type.field(field_name)
|
|
1131
|
+
return nil unless field_type
|
|
1134
1132
|
|
|
1135
|
-
|
|
1133
|
+
source_location = field_definition_location(current_uri, receiver_type, field_name)
|
|
1136
1134
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1135
|
+
{
|
|
1136
|
+
signature: field_hover_signature(field_name, field_type),
|
|
1137
|
+
docs: nil,
|
|
1138
|
+
source: hover_source_label_from_location(source_location),
|
|
1139
|
+
source_uri: hover_source_uri_from_location(source_location),
|
|
1140
|
+
source_line: hover_source_line_from_location(source_location),
|
|
1141
|
+
}
|
|
1142
|
+
end
|
|
1145
1143
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1144
|
+
def resolve_named_argument_label_hover_info(current_uri, facts, tokens, token_index)
|
|
1145
|
+
receiver_info = named_argument_label_receiver_info(facts, tokens, token_index)
|
|
1148
1146
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1147
|
+
field_name = tokens[token_index].lexeme
|
|
1148
|
+
if receiver_info
|
|
1149
|
+
receiver_type = project_field_receiver_type_for_completion(receiver_info[:type], facts)
|
|
1150
|
+
if receiver_type.respond_to?(:field)
|
|
1151
|
+
field_type = receiver_type.field(field_name)
|
|
1152
|
+
if field_type
|
|
1153
|
+
source_location = field_definition_location(current_uri, receiver_type, field_name)
|
|
1154
|
+
return {
|
|
1155
|
+
signature: field_hover_signature(field_name, field_type),
|
|
1156
|
+
docs: nil,
|
|
1157
|
+
source: hover_source_label_from_location(source_location),
|
|
1158
|
+
source_uri: hover_source_uri_from_location(source_location),
|
|
1159
|
+
source_line: hover_source_line_from_location(source_location),
|
|
1160
|
+
}
|
|
1161
|
+
end
|
|
1163
1162
|
end
|
|
1164
1163
|
end
|
|
1165
|
-
end
|
|
1166
1164
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1165
|
+
param_info = named_argument_parameter_info(facts, tokens, token_index)
|
|
1166
|
+
return nil unless param_info
|
|
1169
1167
|
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1168
|
+
{
|
|
1169
|
+
signature: param_info[:signature],
|
|
1170
|
+
docs: param_info[:docs],
|
|
1171
|
+
source: param_info[:source],
|
|
1172
|
+
source_uri: param_info[:source_uri],
|
|
1173
|
+
source_line: param_info[:source_line],
|
|
1174
|
+
}
|
|
1175
|
+
end
|
|
1178
1176
|
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1177
|
+
def named_argument_parameter_info(facts, tokens, token_index)
|
|
1178
|
+
receiver_name = named_argument_callee_name(tokens, token_index)
|
|
1179
|
+
return nil unless receiver_name
|
|
1182
1180
|
|
|
1183
|
-
|
|
1181
|
+
field_name = tokens[token_index].lexeme
|
|
1184
1182
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1183
|
+
if facts.functions.key?(receiver_name)
|
|
1184
|
+
func = facts.functions[receiver_name]
|
|
1185
|
+
func.type.params.each do |param|
|
|
1186
|
+
next unless param.name == field_name
|
|
1187
|
+
return named_argument_param_result(field_name, param, func.ast)
|
|
1188
|
+
end
|
|
1190
1189
|
end
|
|
1191
|
-
end
|
|
1192
1190
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1191
|
+
facts.methods.each_value do |methods|
|
|
1192
|
+
method = methods[receiver_name]
|
|
1193
|
+
next unless method
|
|
1194
|
+
method.type.params.each do |param|
|
|
1195
|
+
next unless param.name == field_name
|
|
1196
|
+
return named_argument_param_result(field_name, param, method.ast)
|
|
1197
|
+
end
|
|
1199
1198
|
end
|
|
1199
|
+
|
|
1200
|
+
nil
|
|
1200
1201
|
end
|
|
1201
1202
|
|
|
1202
|
-
|
|
1203
|
-
|
|
1203
|
+
def named_argument_param_result(field_name, param, callable_ast)
|
|
1204
|
+
param_ast = callable_ast.params.find { |p| p.name == field_name }
|
|
1205
|
+
source_location = param_ast ? ast_name_range(field_name, param_ast.line, param_ast.column) : nil
|
|
1206
|
+
doc_tags = callable_ast.respond_to?(:doc_comment) ? param_doc_for_name(callable_ast, field_name) : nil
|
|
1204
1207
|
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
source: hover_source_label_from_location(source_location),
|
|
1214
|
-
source_uri: hover_source_uri_from_location(source_location),
|
|
1215
|
-
source_line: hover_source_line_from_location(source_location),
|
|
1216
|
-
}
|
|
1217
|
-
end
|
|
1208
|
+
{
|
|
1209
|
+
signature: "#{field_name}: #{param.type}",
|
|
1210
|
+
docs: doc_tags,
|
|
1211
|
+
source: hover_source_label_from_location(source_location),
|
|
1212
|
+
source_uri: hover_source_uri_from_location(source_location),
|
|
1213
|
+
source_line: hover_source_line_from_location(source_location),
|
|
1214
|
+
}
|
|
1215
|
+
end
|
|
1218
1216
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1217
|
+
def param_doc_for_name(callable_ast, param_name)
|
|
1218
|
+
return nil unless callable_ast.respond_to?(:doc_comment)
|
|
1219
|
+
return nil unless callable_ast.doc_comment
|
|
1220
|
+
|
|
1221
|
+
lines = callable_ast.doc_comment.lines
|
|
1222
|
+
param_lines = []
|
|
1223
|
+
in_param = false
|
|
1224
|
+
lines.each do |line|
|
|
1225
|
+
if line =~ /@param\s+#{Regexp.escape(param_name)}\b/
|
|
1226
|
+
in_param = true
|
|
1227
|
+
param_lines << line.sub(/^\s*##\s*@param\s+#{Regexp.escape(param_name)}\s*/, "")
|
|
1228
|
+
next
|
|
1229
|
+
end
|
|
1230
|
+
if in_param
|
|
1231
|
+
if line =~ /@param\b/
|
|
1232
|
+
break
|
|
1233
|
+
end
|
|
1234
|
+
param_lines << line.sub(/^\s*##\s*/, "")
|
|
1235
1235
|
end
|
|
1236
|
-
param_lines << line.sub(/^\s*##\s*/, "")
|
|
1237
1236
|
end
|
|
1237
|
+
param_lines.join(" ").strip.empty? ? nil : param_lines.join(" ").strip
|
|
1238
1238
|
end
|
|
1239
|
-
param_lines.join(" ").strip.empty? ? nil : param_lines.join(" ").strip
|
|
1240
|
-
end
|
|
1241
1239
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1240
|
+
def named_argument_callee_name(tokens, token_index)
|
|
1241
|
+
opener_index = parameter_list_opener_index(tokens, token_index)
|
|
1242
|
+
return nil unless opener_index
|
|
1245
1243
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
tokens[head_index].lexeme
|
|
1251
|
-
end
|
|
1244
|
+
head_index = previous_non_trivia_token_index(tokens, opener_index)
|
|
1245
|
+
return nil unless head_index
|
|
1246
|
+
return nil unless tokens[head_index].type == :identifier
|
|
1252
1247
|
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
return nil unless token
|
|
1248
|
+
tokens[head_index].lexeme
|
|
1249
|
+
end
|
|
1256
1250
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1251
|
+
def field_declaration_receiver_info(facts, tokens, token_index)
|
|
1252
|
+
token = tokens[token_index]
|
|
1253
|
+
return nil unless token
|
|
1254
|
+
|
|
1255
|
+
i = token_index - 1
|
|
1256
|
+
while i >= 0
|
|
1257
|
+
current = tokens[i]
|
|
1258
|
+
i -= 1
|
|
1259
|
+
|
|
1260
|
+
next if [:newline, :indent, :dedent, :eof].include?(current.type)
|
|
1261
|
+
next if current.line == token.line
|
|
1262
|
+
next if current.column >= token.column
|
|
1263
|
+
|
|
1264
|
+
header_line_tokens = non_trivia_tokens_on_line(tokens, current.line)
|
|
1265
|
+
header = header_line_tokens.first
|
|
1266
|
+
type_index = 1
|
|
1267
|
+
if header&.type == :public
|
|
1268
|
+
header = header_line_tokens[1]
|
|
1269
|
+
type_index = 2
|
|
1270
|
+
end
|
|
1271
|
+
return nil unless [:struct, :union].include?(header&.type)
|
|
1261
1272
|
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
next if current.column >= token.column
|
|
1273
|
+
type_token = header_line_tokens[type_index]
|
|
1274
|
+
return nil unless type_token&.type == :identifier
|
|
1265
1275
|
|
|
1266
|
-
|
|
1267
|
-
header = header_line_tokens.first
|
|
1268
|
-
type_index = 1
|
|
1269
|
-
if header&.type == :public
|
|
1270
|
-
header = header_line_tokens[1]
|
|
1271
|
-
type_index = 2
|
|
1276
|
+
return resolve_type_receiver_info(facts, type_token.lexeme, type_token.lexeme)
|
|
1272
1277
|
end
|
|
1273
|
-
return nil unless [:struct, :union].include?(header&.type)
|
|
1274
|
-
|
|
1275
|
-
type_token = header_line_tokens[type_index]
|
|
1276
|
-
return nil unless type_token&.type == :identifier
|
|
1277
1278
|
|
|
1278
|
-
|
|
1279
|
+
nil
|
|
1279
1280
|
end
|
|
1280
1281
|
|
|
1281
|
-
|
|
1282
|
-
|
|
1282
|
+
def named_argument_label_receiver_info(facts, tokens, token_index)
|
|
1283
|
+
opener_index = parameter_list_opener_index(tokens, token_index)
|
|
1284
|
+
return nil unless opener_index
|
|
1283
1285
|
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
return nil unless opener_index
|
|
1286
|
+
head_index = previous_non_trivia_token_index(tokens, opener_index)
|
|
1287
|
+
return nil unless head_index
|
|
1287
1288
|
|
|
1288
|
-
|
|
1289
|
-
|
|
1289
|
+
if tokens[head_index].type == :rbracket
|
|
1290
|
+
lbracket_index = matching_opener_index(tokens, head_index)
|
|
1291
|
+
return nil unless lbracket_index
|
|
1290
1292
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1293
|
+
head_index = previous_non_trivia_token_index(tokens, lbracket_index)
|
|
1294
|
+
return nil unless head_index
|
|
1295
|
+
end
|
|
1294
1296
|
|
|
1295
|
-
|
|
1296
|
-
return nil unless
|
|
1297
|
-
end
|
|
1297
|
+
head = tokens[head_index]
|
|
1298
|
+
return nil unless head.type == :identifier
|
|
1298
1299
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1300
|
+
receiver_name = head.lexeme
|
|
1301
|
+
receiver_path = receiver_name
|
|
1301
1302
|
|
|
1302
|
-
|
|
1303
|
-
|
|
1303
|
+
dot_index = previous_non_trivia_token_index(tokens, head_index)
|
|
1304
|
+
if dot_index && tokens[dot_index].type == :dot
|
|
1305
|
+
module_index = previous_non_trivia_token_index(tokens, dot_index)
|
|
1306
|
+
return nil unless module_index && tokens[module_index].type == :identifier
|
|
1304
1307
|
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
module_index = previous_non_trivia_token_index(tokens, dot_index)
|
|
1308
|
-
return nil unless module_index && tokens[module_index].type == :identifier
|
|
1308
|
+
receiver_path = "#{tokens[module_index].lexeme}.#{receiver_name}"
|
|
1309
|
+
end
|
|
1309
1310
|
|
|
1310
|
-
|
|
1311
|
+
resolve_type_receiver_info(facts, receiver_name, receiver_path)
|
|
1311
1312
|
end
|
|
1312
1313
|
|
|
1313
|
-
|
|
1314
|
-
|
|
1314
|
+
def member_access_chain_at(tokens, token_index)
|
|
1315
|
+
token = tokens[token_index]
|
|
1316
|
+
return nil unless token&.type == :identifier
|
|
1315
1317
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
return nil unless token&.type == :identifier
|
|
1318
|
+
indices = [token_index]
|
|
1319
|
+
current_index = token_index
|
|
1319
1320
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1321
|
+
loop do
|
|
1322
|
+
dot_index = previous_non_trivia_token_index(tokens, current_index)
|
|
1323
|
+
break unless dot_index && tokens[dot_index].type == :dot && tokens[dot_index].line == token.line
|
|
1322
1324
|
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
break unless dot_index && tokens[dot_index].type == :dot && tokens[dot_index].line == token.line
|
|
1325
|
+
receiver_index = previous_non_trivia_token_index(tokens, dot_index)
|
|
1326
|
+
break unless receiver_index && tokens[receiver_index].type == :identifier && tokens[receiver_index].line == token.line
|
|
1326
1327
|
|
|
1327
|
-
|
|
1328
|
-
|
|
1328
|
+
indices.unshift(receiver_index)
|
|
1329
|
+
current_index = receiver_index
|
|
1330
|
+
end
|
|
1329
1331
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1332
|
+
current_index = token_index
|
|
1333
|
+
loop do
|
|
1334
|
+
dot_index = next_non_trivia_token_index(tokens, current_index + 1)
|
|
1335
|
+
break unless dot_index && tokens[dot_index].type == :dot && tokens[dot_index].line == token.line
|
|
1333
1336
|
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1337
|
+
member_index = next_non_trivia_token_index(tokens, dot_index + 1)
|
|
1338
|
+
break unless member_index && tokens[member_index].type == :identifier && tokens[member_index].line == token.line
|
|
1339
|
+
|
|
1340
|
+
indices << member_index
|
|
1341
|
+
current_index = member_index
|
|
1342
|
+
end
|
|
1338
1343
|
|
|
1339
|
-
|
|
1340
|
-
break unless member_index && tokens[member_index].type == :identifier && tokens[member_index].line == token.line
|
|
1344
|
+
return nil if indices.length < 2
|
|
1341
1345
|
|
|
1342
|
-
|
|
1343
|
-
|
|
1346
|
+
{
|
|
1347
|
+
line: token.line,
|
|
1348
|
+
char: token.column + token.lexeme.length,
|
|
1349
|
+
segments: indices.each_with_index.map do |index, position|
|
|
1350
|
+
{
|
|
1351
|
+
name: tokens[index].lexeme,
|
|
1352
|
+
token_index: index,
|
|
1353
|
+
position: position,
|
|
1354
|
+
}
|
|
1355
|
+
end,
|
|
1356
|
+
}
|
|
1344
1357
|
end
|
|
1345
1358
|
|
|
1346
|
-
|
|
1359
|
+
def method_binding_at_token(facts, token)
|
|
1360
|
+
facts.methods.each_value do |methods|
|
|
1361
|
+
methods.each_value do |binding|
|
|
1362
|
+
next unless binding.name == token.lexeme
|
|
1363
|
+
next unless binding.ast.is_a?(AST::MethodDef)
|
|
1364
|
+
next unless binding.ast.line == token.line
|
|
1365
|
+
next unless binding.ast.column == token.column
|
|
1347
1366
|
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
segments: indices.each_with_index.map do |index, position|
|
|
1352
|
-
{
|
|
1353
|
-
name: tokens[index].lexeme,
|
|
1354
|
-
token_index: index,
|
|
1355
|
-
position: position,
|
|
1356
|
-
}
|
|
1357
|
-
end,
|
|
1358
|
-
}
|
|
1359
|
-
end
|
|
1367
|
+
return binding
|
|
1368
|
+
end
|
|
1369
|
+
end
|
|
1360
1370
|
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
next unless binding.ast.line == token.line
|
|
1367
|
-
next unless binding.ast.respond_to?(:column) && binding.ast.column == token.column
|
|
1371
|
+
facts.interfaces.each_value do |interface_binding|
|
|
1372
|
+
interface_binding.methods.each_value do |method_binding|
|
|
1373
|
+
next unless method_binding.name == token.lexeme
|
|
1374
|
+
next unless method_binding.ast.line == token.line
|
|
1375
|
+
next unless method_binding.ast.column == token.column
|
|
1368
1376
|
|
|
1369
|
-
|
|
1377
|
+
return method_binding
|
|
1378
|
+
end
|
|
1370
1379
|
end
|
|
1380
|
+
|
|
1381
|
+
nil
|
|
1371
1382
|
end
|
|
1372
1383
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1384
|
+
def method_signature(binding)
|
|
1385
|
+
async_prefix = (binding.respond_to?(:async) && binding.async) || (binding.ast.respond_to?(:async) && binding.ast.async) ? 'async ' : ''
|
|
1386
|
+
if binding.respond_to?(:type) && binding.type
|
|
1387
|
+
params_str = format_params(binding.type.params)
|
|
1388
|
+
keyword = case binding.ast.kind
|
|
1389
|
+
when :editable
|
|
1390
|
+
"editable function"
|
|
1391
|
+
when :static
|
|
1392
|
+
"static function"
|
|
1393
|
+
else
|
|
1394
|
+
"function"
|
|
1395
|
+
end
|
|
1396
|
+
|
|
1397
|
+
"#{async_prefix}#{keyword} #{binding.name}(#{params_str}) -> #{binding.type.return_type}"
|
|
1398
|
+
else
|
|
1399
|
+
params_str = binding.params.map { |p| "#{p.name}: #{p.type}" }.join(', ')
|
|
1400
|
+
keyword = case binding.kind
|
|
1401
|
+
when :editable
|
|
1402
|
+
"editable function"
|
|
1403
|
+
when :static
|
|
1404
|
+
"static function"
|
|
1405
|
+
else
|
|
1406
|
+
"function"
|
|
1407
|
+
end
|
|
1378
1408
|
|
|
1379
|
-
|
|
1409
|
+
"#{async_prefix}#{keyword} #{binding.name}(#{params_str}) -> #{binding.return_type}"
|
|
1380
1410
|
end
|
|
1381
1411
|
end
|
|
1382
1412
|
|
|
1383
|
-
|
|
1384
|
-
|
|
1413
|
+
def type_hover_signature(name, type)
|
|
1414
|
+
rendered_type = type.to_s
|
|
1415
|
+
return "type #{name}" if rendered_type == name
|
|
1385
1416
|
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
if binding.respond_to?(:type) && binding.type
|
|
1389
|
-
params_str = format_params(binding.type.params)
|
|
1390
|
-
keyword = case binding.ast.kind
|
|
1391
|
-
when :editable
|
|
1392
|
-
"editable function"
|
|
1393
|
-
when :static
|
|
1394
|
-
"static function"
|
|
1395
|
-
else
|
|
1396
|
-
"function"
|
|
1397
|
-
end
|
|
1417
|
+
"type #{name} = #{rendered_type}"
|
|
1418
|
+
end
|
|
1398
1419
|
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
"static function"
|
|
1407
|
-
else
|
|
1408
|
-
"function"
|
|
1409
|
-
end
|
|
1420
|
+
def field_hover_signature(name, type)
|
|
1421
|
+
"field #{name}: #{type}"
|
|
1422
|
+
end
|
|
1423
|
+
|
|
1424
|
+
def find_nested_type_by_short_name(facts, short_name)
|
|
1425
|
+
matches = facts.types.keys.select { |k| k.to_s.end_with?(".#{short_name}") }
|
|
1426
|
+
return nil unless matches.length == 1
|
|
1410
1427
|
|
|
1411
|
-
|
|
1428
|
+
facts.types[matches.first]
|
|
1412
1429
|
end
|
|
1413
|
-
end
|
|
1414
1430
|
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1431
|
+
def find_member_in_types(facts, name)
|
|
1432
|
+
facts.types.reverse_each do |_key, type|
|
|
1433
|
+
next unless type.respond_to?(:members)
|
|
1418
1434
|
|
|
1419
|
-
|
|
1420
|
-
|
|
1435
|
+
member = type.members.find { |m| m == name }
|
|
1436
|
+
if member
|
|
1437
|
+
value = type.respond_to?(:member_value) ? type.member_value(name) : nil
|
|
1438
|
+
return [type, member, value]
|
|
1439
|
+
end
|
|
1440
|
+
end
|
|
1441
|
+
nil
|
|
1442
|
+
end
|
|
1421
1443
|
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1444
|
+
def find_variant_arm_in_types(facts, name)
|
|
1445
|
+
facts.types.reverse_each do |_key, type|
|
|
1446
|
+
arm = nil
|
|
1447
|
+
if type.respond_to?(:arms)
|
|
1448
|
+
arm = type.arms[name]
|
|
1449
|
+
elsif type.respond_to?(:arm_names) && type.arm_names.include?(name)
|
|
1450
|
+
arm = type.arm(name)
|
|
1451
|
+
end
|
|
1452
|
+
next unless arm
|
|
1425
1453
|
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1454
|
+
fields = arm.map { |fname, ftype| "#{fname}: #{ftype}" }.join(", ")
|
|
1455
|
+
field_str = fields.empty? ? "" : "(#{fields})"
|
|
1456
|
+
return "#{type.name}.#{name}#{field_str}"
|
|
1457
|
+
end
|
|
1458
|
+
nil
|
|
1459
|
+
end
|
|
1429
1460
|
|
|
1430
|
-
|
|
1431
|
-
|
|
1461
|
+
def builtin_hover_info(name, tokens, token_index)
|
|
1462
|
+
specialization_info = builtin_value_specialization_info(name, tokens, token_index)
|
|
1463
|
+
return specialization_info if specialization_info
|
|
1432
1464
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
next unless type.respond_to?(:members)
|
|
1465
|
+
specialized_call_info = builtin_specialized_call_hover_info(name, tokens, token_index)
|
|
1466
|
+
return specialized_call_info if specialized_call_info
|
|
1436
1467
|
|
|
1437
|
-
|
|
1438
|
-
if
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
end
|
|
1468
|
+
type_constructor_info = builtin_type_constructor_hover_info(name, tokens, token_index)
|
|
1469
|
+
return type_constructor_info if type_constructor_info
|
|
1470
|
+
|
|
1471
|
+
builtin_call_hover_info(name, tokens, token_index)
|
|
1442
1472
|
end
|
|
1443
|
-
nil
|
|
1444
|
-
end
|
|
1445
1473
|
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
arm = nil
|
|
1449
|
-
if type.respond_to?(:arms)
|
|
1450
|
-
arm = type.arms[name]
|
|
1451
|
-
elsif type.respond_to?(:arm_names) && type.arm_names.include?(name)
|
|
1452
|
-
arm = type.arm(name)
|
|
1453
|
-
end
|
|
1454
|
-
next unless arm
|
|
1474
|
+
def parameter_declaration_token?(tokens, index)
|
|
1475
|
+
return false unless index && tokens[index]&.type == :identifier
|
|
1455
1476
|
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
return
|
|
1477
|
+
prev = previous_non_trivia_token_index(tokens, index)
|
|
1478
|
+
return false unless prev
|
|
1479
|
+
return false unless [:lparen, :comma].include?(tokens[prev].type)
|
|
1480
|
+
|
|
1481
|
+
nxt = next_non_trivia_token_index(tokens, index + 1)
|
|
1482
|
+
nxt && tokens[nxt].type == :colon
|
|
1459
1483
|
end
|
|
1460
|
-
nil
|
|
1461
|
-
end
|
|
1462
1484
|
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
return specialization_info if specialization_info
|
|
1485
|
+
def attribute_target_token?(tokens, index)
|
|
1486
|
+
return false unless index && tokens[index]&.type == :identifier
|
|
1466
1487
|
|
|
1467
|
-
|
|
1468
|
-
|
|
1488
|
+
prev = previous_non_trivia_token_index(tokens, index)
|
|
1489
|
+
return false unless prev && [:lbracket, :comma].include?(tokens[prev].type)
|
|
1469
1490
|
|
|
1470
|
-
|
|
1471
|
-
|
|
1491
|
+
after = next_non_trivia_token_index(tokens, index + 1)
|
|
1492
|
+
return false unless after && [:rbracket, :comma].include?(tokens[after].type)
|
|
1472
1493
|
|
|
1473
|
-
|
|
1474
|
-
|
|
1494
|
+
true
|
|
1495
|
+
end
|
|
1475
1496
|
|
|
1476
|
-
|
|
1477
|
-
|
|
1497
|
+
def call_argument_token?(tokens, index)
|
|
1498
|
+
return false unless index && tokens[index]&.type == :identifier
|
|
1478
1499
|
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
return false unless [:lparen, :comma].include?(tokens[prev].type)
|
|
1500
|
+
prev = previous_non_trivia_token_index(tokens, index)
|
|
1501
|
+
return false unless prev && [:lparen, :comma].include?(tokens[prev].type)
|
|
1482
1502
|
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1503
|
+
nxt = next_non_trivia_token_index(tokens, index + 1)
|
|
1504
|
+
!nxt || ![:colon, :rbracket, :comma].include?(tokens[nxt].type)
|
|
1505
|
+
end
|
|
1486
1506
|
|
|
1487
|
-
|
|
1488
|
-
|
|
1507
|
+
def builtin_in_member_access_context?(tokens, token_index)
|
|
1508
|
+
prev_index = previous_non_trivia_token_index(tokens, token_index)
|
|
1509
|
+
prev_index && tokens[prev_index].type == :dot
|
|
1510
|
+
end
|
|
1489
1511
|
|
|
1490
|
-
|
|
1491
|
-
|
|
1512
|
+
def member_access_token?(context)
|
|
1513
|
+
tokens = context[:tokens]
|
|
1514
|
+
token_index = context[:token_index]
|
|
1515
|
+
return false unless tokens && token_index
|
|
1516
|
+
prev = previous_non_trivia_token_index(tokens, token_index)
|
|
1517
|
+
prev && tokens[prev].type == :dot
|
|
1518
|
+
end
|
|
1492
1519
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1520
|
+
def keyword_member_access_token?(tokens, token_index)
|
|
1521
|
+
return false unless tokens && token_index
|
|
1522
|
+
tok = tokens[token_index]
|
|
1523
|
+
return false unless tok && tok.type != :identifier
|
|
1524
|
+
prev = previous_non_trivia_token_index(tokens, token_index)
|
|
1525
|
+
prev && tokens[prev].type == :dot
|
|
1526
|
+
end
|
|
1495
1527
|
|
|
1496
|
-
|
|
1497
|
-
|
|
1528
|
+
def builtin_value_specialization_info(name, tokens, token_index)
|
|
1529
|
+
return nil unless %w[zero default reinterpret].include?(name)
|
|
1498
1530
|
|
|
1499
|
-
|
|
1500
|
-
return false unless index && tokens[index]&.type == :identifier
|
|
1531
|
+
return nil if builtin_in_member_access_context?(tokens, token_index)
|
|
1501
1532
|
|
|
1502
|
-
|
|
1503
|
-
|
|
1533
|
+
lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
|
|
1534
|
+
return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
|
|
1504
1535
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
end
|
|
1536
|
+
rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
|
|
1537
|
+
return nil unless rbracket_index
|
|
1508
1538
|
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
end
|
|
1539
|
+
specialization = render_builtin_specialization(tokens[token_index..rbracket_index])
|
|
1540
|
+
target_type = render_builtin_specialization(tokens[(lbracket_index + 1)...rbracket_index])
|
|
1541
|
+
return nil if target_type.empty?
|
|
1513
1542
|
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1543
|
+
docs = case name
|
|
1544
|
+
when 'zero'
|
|
1545
|
+
'`zero[T]` returns the raw zero-initialized value for `T`. It is a value form, not a callable.'
|
|
1546
|
+
when 'default'
|
|
1547
|
+
'`default[T]` returns the semantic default value for `T` and requires an accessible zero-argument associated function `T.default()` that returns `T`. It is a value form, not a callable.'
|
|
1548
|
+
when 'reinterpret'
|
|
1549
|
+
'`reinterpret[T](value)` bit-casts a value to `T`; it requires `unsafe` and compatible concrete sized types.'
|
|
1550
|
+
end
|
|
1521
1551
|
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1552
|
+
{
|
|
1553
|
+
signature: if name == 'reinterpret'
|
|
1554
|
+
"builtin #{specialization}(value) -> #{target_type}"
|
|
1555
|
+
else
|
|
1556
|
+
"builtin #{specialization} -> #{target_type}"
|
|
1557
|
+
end,
|
|
1558
|
+
docs: docs,
|
|
1559
|
+
}
|
|
1560
|
+
end
|
|
1529
1561
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
else
|
|
1558
|
-
"builtin #{specialization} -> #{target_type}"
|
|
1559
|
-
end,
|
|
1560
|
-
docs: docs,
|
|
1561
|
-
}
|
|
1562
|
-
end
|
|
1562
|
+
def builtin_type_constructor_hover_info(name, tokens, token_index)
|
|
1563
|
+
return nil unless %w[array span Option Result SoA str_buffer ref ptr const_ptr own Task atomic simd].include?(name)
|
|
1564
|
+
|
|
1565
|
+
lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
|
|
1566
|
+
return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
|
|
1567
|
+
|
|
1568
|
+
rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
|
|
1569
|
+
return nil unless rbracket_index
|
|
1570
|
+
|
|
1571
|
+
specialization = render_builtin_specialization(tokens[token_index..rbracket_index])
|
|
1572
|
+
after_bracket_index = next_non_trivia_token_index(tokens, rbracket_index + 1)
|
|
1573
|
+
|
|
1574
|
+
if after_bracket_index && tokens[after_bracket_index].type == :lparen
|
|
1575
|
+
docs = case name
|
|
1576
|
+
when 'array'
|
|
1577
|
+
'`array[T, N](...)` constructs a fixed-length array value of type `array[T, N]`.'
|
|
1578
|
+
when 'span'
|
|
1579
|
+
'`span[T](data = ..., len = ...)` constructs a span view over contiguous `T` storage.'
|
|
1580
|
+
when 'SoA'
|
|
1581
|
+
'`SoA[T, N](...)` constructs a Struct-of-Arrays value with `N` elements of type `T`. Fields are stored in separate contiguous arrays.'
|
|
1582
|
+
when 'simd'
|
|
1583
|
+
'`simd[T, N](...)` constructs a SIMD vector value with `N` lanes of type `T`. Lanes are stored in a single vector register.'
|
|
1584
|
+
when 'Option'
|
|
1585
|
+
'`Option[T]` is a built-in optional type with arms `some(value: T)` and `none`.'
|
|
1586
|
+
when 'Result'
|
|
1587
|
+
'`Result[T, E]` is a built-in result type with arms `success(value: T)` and `failure(error: E)`.'
|
|
1588
|
+
end
|
|
1563
1589
|
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1590
|
+
return {
|
|
1591
|
+
signature: case name
|
|
1592
|
+
when 'array'
|
|
1593
|
+
"builtin #{specialization}(...) -> #{specialization}"
|
|
1594
|
+
when 'span'
|
|
1595
|
+
"builtin #{specialization}(data = ..., len = ...) -> #{specialization}"
|
|
1596
|
+
when 'SoA'
|
|
1597
|
+
"builtin #{specialization}(...) -> #{specialization}"
|
|
1598
|
+
when 'simd'
|
|
1599
|
+
"builtin #{specialization}(...) -> #{specialization}"
|
|
1600
|
+
when 'Option'
|
|
1601
|
+
"builtin #{specialization}(some: value = ...) / #{specialization}(none:)"
|
|
1602
|
+
when 'Result'
|
|
1603
|
+
"builtin #{specialization}(success: value = ...) / #{specialization}(failure: error = ...)"
|
|
1604
|
+
end,
|
|
1605
|
+
docs: docs,
|
|
1606
|
+
}
|
|
1607
|
+
end
|
|
1608
|
+
|
|
1609
|
+
docs = case name
|
|
1610
|
+
when 'array'
|
|
1611
|
+
'`array[T, N]` is the built-in fixed-length array type.'
|
|
1612
|
+
when 'span'
|
|
1613
|
+
'`span[T]` is the built-in non-owning contiguous view type.'
|
|
1614
|
+
when 'SoA'
|
|
1615
|
+
'`SoA[T, N]` is the built-in Struct-of-Arrays type. Each struct field is stored in a separate contiguous array of `N` elements, improving SIMD/cache behavior for parallel field access.'
|
|
1616
|
+
when 'simd'
|
|
1617
|
+
'`simd[T, N]` is the built-in SIMD vector type. Fixed-width vector of `N` numeric lanes. Supports component-wise arithmetic, lane access via `[i]`, and explicit aligned/unaligned load/store.'
|
|
1618
|
+
when 'Option'
|
|
1619
|
+
'`Option[T]` is the built-in optional value type with `some(value = ...)` and `none` arms.'
|
|
1620
|
+
when 'Result'
|
|
1621
|
+
'`Result[T, E]` is the built-in success/failure type with `success(value = ...)` and `failure(error = ...)` arms.'
|
|
1622
|
+
when 'str_buffer'
|
|
1623
|
+
'`str_buffer[N]` is a fixed-capacity mutable UTF-8 text buffer. Methods: `assign`, `append`, `assign_format`, `append_format`, `clear`, `len`, `as_str`, `as_cstr`.'
|
|
1624
|
+
when 'ref'
|
|
1625
|
+
'`ref[T]` is a non-null borrow reference. Auto-dereferences for member access and method calls. Cannot be stored in module-level variables, constants, or nested containers.'
|
|
1626
|
+
when 'ptr'
|
|
1627
|
+
'`ptr[T]` is a raw mutable pointer. Indexing, dereference, and arithmetic require `unsafe`. Nullable via `ptr[T]?`.'
|
|
1628
|
+
when 'const_ptr'
|
|
1629
|
+
'`const_ptr[T]` is a read-only pointer. Does not require `unsafe` for dereference.'
|
|
1630
|
+
when 'own'
|
|
1631
|
+
'`own[T]` is an owning heap pointer. Auto-dereferences like `ref`. Storable, returnable, and nullable. Allocated via `heap.must_alloc[T](count)`.'
|
|
1632
|
+
when 'Task'
|
|
1633
|
+
'`Task[T]` is an async task future. Returned by `async function`. Use `await` to unwrap, or `aio.wait`/`aio.run` to drive.'
|
|
1634
|
+
when 'atomic'
|
|
1635
|
+
'`atomic[T]` is an atomic value for lock-free concurrent access. `T` must be a primitive integer or `bool`. Methods: `load`, `store`, `add`, `sub`, `exchange`.'
|
|
1636
|
+
end
|
|
1637
|
+
|
|
1638
|
+
{
|
|
1639
|
+
signature: "builtin type #{specialization}",
|
|
1607
1640
|
docs: docs,
|
|
1608
1641
|
}
|
|
1609
1642
|
end
|
|
1610
1643
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
'`array[T, N]` is the built-in fixed-length array type.'
|
|
1614
|
-
when 'span'
|
|
1615
|
-
'`span[T]` is the built-in non-owning contiguous view type.'
|
|
1616
|
-
when 'SoA'
|
|
1617
|
-
'`SoA[T, N]` is the built-in Struct-of-Arrays type. Each struct field is stored in a separate contiguous array of `N` elements, improving SIMD/cache behavior for parallel field access.'
|
|
1618
|
-
when 'simd'
|
|
1619
|
-
'`simd[T, N]` is the built-in SIMD vector type. Fixed-width vector of `N` numeric lanes. Supports component-wise arithmetic, lane access via `[i]`, and explicit aligned/unaligned load/store.'
|
|
1620
|
-
when 'Option'
|
|
1621
|
-
'`Option[T]` is the built-in optional value type with `some(value = ...)` and `none` arms.'
|
|
1622
|
-
when 'Result'
|
|
1623
|
-
'`Result[T, E]` is the built-in success/failure type with `success(value = ...)` and `failure(error = ...)` arms.'
|
|
1624
|
-
when 'str_buffer'
|
|
1625
|
-
'`str_buffer[N]` is a fixed-capacity mutable UTF-8 text buffer. Methods: `assign`, `append`, `assign_format`, `append_format`, `clear`, `len`, `as_str`, `as_cstr`.'
|
|
1626
|
-
when 'ref'
|
|
1627
|
-
'`ref[T]` is a non-null borrow reference. Auto-dereferences for member access and method calls. Cannot be stored in module-level variables, constants, or nested containers.'
|
|
1628
|
-
when 'ptr'
|
|
1629
|
-
'`ptr[T]` is a raw mutable pointer. Indexing, dereference, and arithmetic require `unsafe`. Nullable via `ptr[T]?`.'
|
|
1630
|
-
when 'const_ptr'
|
|
1631
|
-
'`const_ptr[T]` is a read-only pointer. Does not require `unsafe` for dereference.'
|
|
1632
|
-
when 'own'
|
|
1633
|
-
'`own[T]` is an owning heap pointer. Auto-dereferences like `ref`. Storable, returnable, and nullable. Allocated via `heap.must_alloc[T](count)`.'
|
|
1634
|
-
when 'Task'
|
|
1635
|
-
'`Task[T]` is an async task future. Returned by `async function`. Use `await` to unwrap, or `aio.wait`/`aio.run` to drive.'
|
|
1636
|
-
when 'atomic'
|
|
1637
|
-
'`atomic[T]` is an atomic value for lock-free concurrent access. `T` must be a primitive integer or `bool`. Methods: `load`, `store`, `add`, `sub`, `exchange`.'
|
|
1638
|
-
end
|
|
1644
|
+
def builtin_specialized_call_hover_info(name, tokens, token_index)
|
|
1645
|
+
return nil unless BUILTIN_ASSOCIATED_HOOK_NAMES.include?(name) || name == 'attribute_arg'
|
|
1639
1646
|
|
|
1640
|
-
|
|
1641
|
-
signature: "builtin type #{specialization}",
|
|
1642
|
-
docs: docs,
|
|
1643
|
-
}
|
|
1644
|
-
end
|
|
1647
|
+
return nil if builtin_in_member_access_context?(tokens, token_index)
|
|
1645
1648
|
|
|
1646
|
-
|
|
1647
|
-
|
|
1649
|
+
lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
|
|
1650
|
+
return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
|
|
1648
1651
|
|
|
1649
|
-
|
|
1652
|
+
rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
|
|
1653
|
+
return nil unless rbracket_index
|
|
1650
1654
|
|
|
1651
|
-
|
|
1652
|
-
|
|
1655
|
+
after_bracket_index = next_non_trivia_token_index(tokens, rbracket_index + 1)
|
|
1656
|
+
return nil unless after_bracket_index && tokens[after_bracket_index].type == :lparen
|
|
1653
1657
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1658
|
+
specialization = render_builtin_specialization(tokens[token_index..rbracket_index])
|
|
1659
|
+
if name == 'attribute_arg'
|
|
1660
|
+
target_type = render_builtin_specialization(tokens[(lbracket_index + 1)...rbracket_index])
|
|
1661
|
+
return nil if target_type.empty?
|
|
1656
1662
|
|
|
1657
|
-
|
|
1658
|
-
|
|
1663
|
+
return {
|
|
1664
|
+
signature: "builtin #{specialization}(attribute, param_name) -> #{target_type}",
|
|
1665
|
+
docs: '`attribute_arg[T](attribute, param_name)` returns the compile-time argument value for the named attribute parameter; `T` must exactly match the declared parameter type.'
|
|
1666
|
+
}
|
|
1667
|
+
end
|
|
1659
1668
|
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1669
|
+
docs = case name
|
|
1670
|
+
when 'hash'
|
|
1671
|
+
'`hash[T](value)` lowers to `T.hash(value: const_ptr[T]) -> uint` after borrowing safe lvalues or forwarding existing refs and pointers.'
|
|
1672
|
+
when 'equal'
|
|
1673
|
+
'`equal[T](left, right)` lowers to `T.equal(left: const_ptr[T], right: const_ptr[T]) -> bool` after borrowing safe lvalues or forwarding existing refs and pointers.'
|
|
1674
|
+
when 'order'
|
|
1675
|
+
'`order[T](left, right)` lowers to `T.order(left: const_ptr[T], right: const_ptr[T]) -> int` after borrowing safe lvalues or forwarding existing refs and pointers.'
|
|
1676
|
+
end
|
|
1664
1677
|
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1678
|
+
signature = case name
|
|
1679
|
+
when 'hash'
|
|
1680
|
+
"builtin #{specialization}(value) -> uint"
|
|
1681
|
+
when 'equal'
|
|
1682
|
+
"builtin #{specialization}(left, right) -> bool"
|
|
1683
|
+
when 'order'
|
|
1684
|
+
"builtin #{specialization}(left, right) -> int"
|
|
1685
|
+
end
|
|
1686
|
+
|
|
1687
|
+
{
|
|
1688
|
+
signature: signature,
|
|
1689
|
+
docs: docs,
|
|
1668
1690
|
}
|
|
1669
1691
|
end
|
|
1670
1692
|
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
when 'equal'
|
|
1675
|
-
'`equal[T](left, right)` lowers to `T.equal(left: const_ptr[T], right: const_ptr[T]) -> bool` after borrowing safe lvalues or forwarding existing refs and pointers.'
|
|
1676
|
-
when 'order'
|
|
1677
|
-
'`order[T](left, right)` lowers to `T.order(left: const_ptr[T], right: const_ptr[T]) -> int` after borrowing safe lvalues or forwarding existing refs and pointers.'
|
|
1678
|
-
end
|
|
1679
|
-
|
|
1680
|
-
signature = case name
|
|
1681
|
-
when 'hash'
|
|
1682
|
-
"builtin #{specialization}(value) -> uint"
|
|
1683
|
-
when 'equal'
|
|
1684
|
-
"builtin #{specialization}(left, right) -> bool"
|
|
1685
|
-
when 'order'
|
|
1686
|
-
"builtin #{specialization}(left, right) -> int"
|
|
1687
|
-
end
|
|
1688
|
-
|
|
1689
|
-
{
|
|
1690
|
-
signature: signature,
|
|
1691
|
-
docs: docs,
|
|
1692
|
-
}
|
|
1693
|
-
end
|
|
1694
|
-
|
|
1695
|
-
def builtin_call_hover_info(name, tokens, token_index)
|
|
1696
|
-
info = BUILTIN_CALL_HOVER_INFO[name]
|
|
1697
|
-
return nil unless info
|
|
1693
|
+
def builtin_call_hover_info(name, tokens, token_index)
|
|
1694
|
+
info = BUILTIN_CALL_HOVER_INFO[name]
|
|
1695
|
+
return nil unless info
|
|
1698
1696
|
|
|
1699
|
-
|
|
1697
|
+
return nil if builtin_in_member_access_context?(tokens, token_index)
|
|
1700
1698
|
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1699
|
+
next_index = next_non_trivia_token_index(tokens, token_index + 1)
|
|
1700
|
+
return nil unless next_index
|
|
1701
|
+
next_type = tokens[next_index].type
|
|
1702
|
+
return nil unless next_type == :lparen || next_type == :lbracket
|
|
1705
1703
|
|
|
1706
|
-
|
|
1707
|
-
|
|
1704
|
+
info
|
|
1705
|
+
end
|
|
1708
1706
|
|
|
1709
|
-
|
|
1710
|
-
|
|
1707
|
+
def builtin_keyword_hover_info(token)
|
|
1708
|
+
return nil unless token
|
|
1711
1709
|
|
|
1712
|
-
|
|
1713
|
-
|
|
1710
|
+
info = KEYWORD_HOVER_INFO[token.lexeme]
|
|
1711
|
+
return info if info && [:size_of, :align_of, :offset_of].include?(token.type)
|
|
1714
1712
|
|
|
1715
|
-
|
|
1716
|
-
|
|
1713
|
+
LANGUAGE_KEYWORD_HOVER_INFO[token.lexeme]
|
|
1714
|
+
end
|
|
1717
1715
|
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1716
|
+
def render_builtin_specialization(tokens)
|
|
1717
|
+
Array(tokens).map(&:lexeme).join.gsub(',', ', ')
|
|
1718
|
+
end
|
|
1721
1719
|
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1720
|
+
def value_hover_signature(binding)
|
|
1721
|
+
case binding.kind
|
|
1722
|
+
when :const
|
|
1723
|
+
"const #{binding.name}: #{binding.type} (immutable)"
|
|
1724
|
+
when :var
|
|
1725
|
+
"var #{binding.name}: #{binding.type} (mutable)"
|
|
1726
|
+
when :let
|
|
1727
|
+
"let #{binding.name}: #{binding.type} (immutable)"
|
|
1728
|
+
when :param
|
|
1729
|
+
"parameter #{binding.name}: #{binding.type} (immutable)"
|
|
1730
|
+
when :local
|
|
1731
|
+
suffix = binding.mutable ? 'mutable' : 'immutable'
|
|
1732
|
+
"local #{binding.name}: #{binding.type} (#{suffix})"
|
|
1733
|
+
else
|
|
1734
|
+
"#{binding.name}: #{binding.type}"
|
|
1735
|
+
end
|
|
1737
1736
|
end
|
|
1738
|
-
end
|
|
1739
1737
|
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1738
|
+
def resolve_local_hover_binding(facts, name, line, char)
|
|
1739
|
+
declared_binding = declared_generic_local_hover_binding(facts, name, line)
|
|
1740
|
+
return declared_binding if declared_binding
|
|
1743
1741
|
|
|
1744
|
-
|
|
1745
|
-
|
|
1742
|
+
frame = enclosing_completion_frame(facts, line)
|
|
1743
|
+
return nil unless frame
|
|
1746
1744
|
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1745
|
+
snapshot = latest_completion_snapshot(frame, line, char)
|
|
1746
|
+
binding = snapshot&.bindings&.dig(name)
|
|
1747
|
+
return binding if binding
|
|
1750
1748
|
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1749
|
+
future_snapshot = same_line_future_completion_snapshot(frame, line, char)
|
|
1750
|
+
future_snapshot&.bindings&.dig(name)
|
|
1751
|
+
end
|
|
1754
1752
|
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1753
|
+
def resolve_as_binding_declaration_hover_binding(facts, name, line, char)
|
|
1754
|
+
frame = enclosing_completion_frame(facts, line)
|
|
1755
|
+
return nil unless frame
|
|
1758
1756
|
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1757
|
+
Array(frame.snapshots).each do |snapshot|
|
|
1758
|
+
next if snapshot.line < line
|
|
1759
|
+
next if snapshot.line == line && snapshot.column <= char
|
|
1762
1760
|
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1761
|
+
binding = snapshot.bindings[name]
|
|
1762
|
+
return binding if binding
|
|
1763
|
+
end
|
|
1766
1764
|
|
|
1767
|
-
|
|
1768
|
-
|
|
1765
|
+
nil
|
|
1766
|
+
end
|
|
1769
1767
|
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1768
|
+
def resolve_local_hover_type(facts, name, line, char)
|
|
1769
|
+
resolve_local_hover_binding(facts, name, line, char)&.type
|
|
1770
|
+
end
|
|
1773
1771
|
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1772
|
+
def declared_generic_local_hover_binding(facts, name, line)
|
|
1773
|
+
binding = generic_function_binding_for_line(facts, line)
|
|
1774
|
+
return nil unless binding
|
|
1777
1775
|
|
|
1778
|
-
|
|
1779
|
-
|
|
1776
|
+
binding.body_params.find { |param| param.name == name }
|
|
1777
|
+
end
|
|
1780
1778
|
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1779
|
+
def enclosing_completion_frame(facts, line)
|
|
1780
|
+
frames = Array(facts.local_completion_frames)
|
|
1781
|
+
containing = frames.select { |frame| frame.start_line && frame.end_line && frame.start_line <= line && line <= frame.end_line }
|
|
1782
|
+
containing.min_by { |frame| frame.end_line - frame.start_line }
|
|
1783
|
+
end
|
|
1786
1784
|
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1785
|
+
def latest_completion_snapshot(frame, line, char)
|
|
1786
|
+
snapshots = Array(frame.snapshots)
|
|
1787
|
+
snapshots.reverse_each do |snapshot|
|
|
1788
|
+
next if snapshot.line > line
|
|
1789
|
+
next if snapshot.line == line && snapshot.column > char
|
|
1792
1790
|
|
|
1793
|
-
|
|
1791
|
+
return snapshot
|
|
1792
|
+
end
|
|
1793
|
+
nil
|
|
1794
1794
|
end
|
|
1795
|
-
nil
|
|
1796
|
-
end
|
|
1797
1795
|
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1796
|
+
def same_line_future_completion_snapshot(frame, line, char)
|
|
1797
|
+
snapshots = Array(frame.snapshots)
|
|
1798
|
+
snapshots.each do |snapshot|
|
|
1799
|
+
next unless snapshot.line == line
|
|
1800
|
+
next if snapshot.column <= char
|
|
1803
1801
|
|
|
1804
|
-
|
|
1802
|
+
return snapshot
|
|
1803
|
+
end
|
|
1804
|
+
nil
|
|
1805
1805
|
end
|
|
1806
|
-
nil
|
|
1807
|
-
end
|
|
1808
1806
|
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1807
|
+
def resolve_for_binding_hover_info(tokens, token_index)
|
|
1808
|
+
tok = tokens[token_index]
|
|
1809
|
+
return nil unless tok&.type == :identifier
|
|
1812
1810
|
|
|
1813
|
-
|
|
1814
|
-
|
|
1811
|
+
binding_info = for_binding_context_at(tokens, token_index)
|
|
1812
|
+
return nil unless binding_info
|
|
1815
1813
|
|
|
1816
|
-
|
|
1817
|
-
|
|
1814
|
+
binding_name = binding_info[:name]
|
|
1815
|
+
iterable_text = binding_info[:iterable_text] || "collection"
|
|
1818
1816
|
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1817
|
+
{
|
|
1818
|
+
signature: "for binding #{binding_name} (iterating over #{iterable_text})",
|
|
1819
|
+
docs: nil,
|
|
1820
|
+
}
|
|
1821
|
+
end
|
|
1824
1822
|
|
|
1825
|
-
|
|
1826
|
-
|
|
1823
|
+
def for_binding_context_at(tokens, token_index)
|
|
1824
|
+
return nil unless token_index
|
|
1827
1825
|
|
|
1828
|
-
|
|
1829
|
-
|
|
1826
|
+
i = token_index - 1
|
|
1827
|
+
passed_in = false
|
|
1830
1828
|
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1829
|
+
while i >= 0
|
|
1830
|
+
current = tokens[i]
|
|
1831
|
+
break if current.type == :newline && current.line != tokens[token_index].line
|
|
1834
1832
|
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1833
|
+
if current.type == :identifier
|
|
1834
|
+
case current.lexeme
|
|
1835
|
+
when "in"
|
|
1836
|
+
passed_in = true
|
|
1837
|
+
when "for"
|
|
1838
|
+
if passed_in
|
|
1839
|
+
ie = token_index + 1
|
|
1840
|
+
while ie < tokens.length
|
|
1841
|
+
nt = tokens[ie]
|
|
1842
|
+
break if nt.type == :newline || nt.type == :colon
|
|
1845
1843
|
|
|
1846
|
-
|
|
1844
|
+
ie += 1
|
|
1845
|
+
end
|
|
1846
|
+
iterable_text = tokens[(token_index + 1)...ie].map(&:lexeme).join(" ")
|
|
1847
|
+
iterable_text = iterable_text.gsub(/\s+/, " ").strip
|
|
1848
|
+
return {
|
|
1849
|
+
name: tokens[token_index].lexeme,
|
|
1850
|
+
iterable_text: iterable_text.empty? ? nil : iterable_text,
|
|
1851
|
+
}
|
|
1847
1852
|
end
|
|
1848
|
-
iterable_text = tokens[(token_index + 1)...ie].map(&:lexeme).join(" ")
|
|
1849
|
-
iterable_text = iterable_text.gsub(/\s+/, " ").strip
|
|
1850
|
-
return {
|
|
1851
|
-
name: tokens[token_index].lexeme,
|
|
1852
|
-
iterable_text: iterable_text.empty? ? nil : iterable_text,
|
|
1853
|
-
}
|
|
1854
1853
|
end
|
|
1855
1854
|
end
|
|
1855
|
+
|
|
1856
|
+
i -= 1
|
|
1856
1857
|
end
|
|
1857
1858
|
|
|
1858
|
-
|
|
1859
|
+
nil
|
|
1859
1860
|
end
|
|
1860
1861
|
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
when "(" then kind = :param
|
|
1885
|
-
when "," then kind = :param
|
|
1862
|
+
def resolve_lexical_local_hover_signature(definition_uri, name, definition_token)
|
|
1863
|
+
kind = nil
|
|
1864
|
+
type_str = nil
|
|
1865
|
+
|
|
1866
|
+
tokens = @workspace.get_tokens(definition_uri)
|
|
1867
|
+
if tokens
|
|
1868
|
+
def_index = tokens.index(definition_token)
|
|
1869
|
+
if def_index
|
|
1870
|
+
prev = previous_non_trivia_token_index(tokens, def_index)
|
|
1871
|
+
if prev
|
|
1872
|
+
case tokens[prev].lexeme
|
|
1873
|
+
when "let" then kind = :let
|
|
1874
|
+
when "var" then kind = :var
|
|
1875
|
+
when "const" then kind = :const
|
|
1876
|
+
when "struct" then kind = :struct_type
|
|
1877
|
+
when "function", "async", "external", "foreign" then kind = :function
|
|
1878
|
+
when "enum" then kind = :enum_type
|
|
1879
|
+
when "flags" then kind = :flags_type
|
|
1880
|
+
when "union" then kind = :union_type
|
|
1881
|
+
when "variant" then kind = :variant_type
|
|
1882
|
+
when "(" then kind = :param
|
|
1883
|
+
when "," then kind = :param
|
|
1884
|
+
end
|
|
1886
1885
|
end
|
|
1887
|
-
end
|
|
1888
1886
|
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1887
|
+
if kind
|
|
1888
|
+
next_idx = next_non_trivia_token_index(tokens, def_index + 1)
|
|
1889
|
+
if next_idx && tokens[next_idx].type == :colon
|
|
1890
|
+
type_start = next_non_trivia_token_index(tokens, next_idx + 1)
|
|
1891
|
+
if type_start && tokens[type_start].type == :identifier
|
|
1892
|
+
type_str = tokens[type_start].lexeme
|
|
1893
|
+
type_end = type_start
|
|
1894
|
+
loop do
|
|
1895
|
+
next_tok_idx = next_non_trivia_token_index(tokens, type_end + 1)
|
|
1896
|
+
break unless next_tok_idx && %i[identifier lbracket rbracket integer comma].include?(tokens[next_tok_idx].type)
|
|
1897
|
+
|
|
1898
|
+
type_str += tokens[next_tok_idx].lexeme
|
|
1899
|
+
type_end = next_tok_idx
|
|
1900
|
+
break if tokens[type_end].type == :equal
|
|
1901
|
+
end
|
|
1902
|
+
type_str = type_str.sub(/\s*=.*/, "").strip
|
|
1903
1903
|
end
|
|
1904
|
-
type_str = type_str.sub(/\s*=.*/, "").strip
|
|
1905
1904
|
end
|
|
1906
1905
|
end
|
|
1907
1906
|
end
|
|
1908
1907
|
end
|
|
1909
|
-
end
|
|
1910
1908
|
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1909
|
+
kind ||= :let
|
|
1910
|
+
unless %i[let var const param].include?(kind)
|
|
1911
|
+
kind = kind.to_s.sub(/_type$/, "")
|
|
1912
|
+
return "#{kind} #{name}"
|
|
1913
|
+
end
|
|
1916
1914
|
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1915
|
+
display_kind = kind == :param ? "parameter" : kind.to_s
|
|
1916
|
+
mutability = kind == :var ? "mutable" : "immutable"
|
|
1917
|
+
if type_str && !type_str.empty?
|
|
1918
|
+
"#{display_kind} #{name}: #{type_str} (#{mutability})"
|
|
1919
|
+
else
|
|
1920
|
+
"#{kind} #{name} (#{mutability})"
|
|
1921
|
+
end
|
|
1923
1922
|
end
|
|
1924
1923
|
end
|
|
1925
|
-
end
|
|
1926
1924
|
end
|
|
1927
1925
|
end
|
|
1928
1926
|
end
|