yoda-language-server 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.travis.yml +8 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +78 -0
- data/LICENSE.txt +21 -0
- data/README.md +85 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/client/atom/main.js +27 -0
- data/client/vscode/.gitignore +4 -0
- data/client/vscode/.vscode/launch.json +28 -0
- data/client/vscode/.vscode/settings.json +9 -0
- data/client/vscode/.vscode/tasks.json +20 -0
- data/client/vscode/.vscodeignore +8 -0
- data/client/vscode/CHANGELOG.md +7 -0
- data/client/vscode/README.md +65 -0
- data/client/vscode/package-lock.json +2688 -0
- data/client/vscode/package.json +39 -0
- data/client/vscode/src/extension.ts +42 -0
- data/client/vscode/src/test/extension.test.ts +22 -0
- data/client/vscode/src/test/index.ts +22 -0
- data/client/vscode/tsconfig.json +16 -0
- data/client/vscode/vsc-extension-quickstart.md +33 -0
- data/exe/yoda +27 -0
- data/lib/yoda.rb +11 -0
- data/lib/yoda/evaluation.rb +9 -0
- data/lib/yoda/evaluation/code_completion.rb +65 -0
- data/lib/yoda/evaluation/code_completion/base_provider.rb +57 -0
- data/lib/yoda/evaluation/code_completion/const_provider.rb +90 -0
- data/lib/yoda/evaluation/code_completion/method_provider.rb +82 -0
- data/lib/yoda/evaluation/code_completion/variable_provider.rb +18 -0
- data/lib/yoda/evaluation/comment_completion.rb +70 -0
- data/lib/yoda/evaluation/comment_completion/base_provider.rb +64 -0
- data/lib/yoda/evaluation/comment_completion/param_provider.rb +18 -0
- data/lib/yoda/evaluation/comment_completion/tag_provider.rb +41 -0
- data/lib/yoda/evaluation/comment_completion/type_provider.rb +58 -0
- data/lib/yoda/evaluation/current_node_explain.rb +70 -0
- data/lib/yoda/evaluation/evaluator.rb +103 -0
- data/lib/yoda/evaluation/signature_discovery.rb +83 -0
- data/lib/yoda/model.rb +12 -0
- data/lib/yoda/model/completion_item.rb +56 -0
- data/lib/yoda/model/descriptions.rb +10 -0
- data/lib/yoda/model/descriptions/base.rb +26 -0
- data/lib/yoda/model/descriptions/function_description.rb +40 -0
- data/lib/yoda/model/descriptions/value_description.rb +33 -0
- data/lib/yoda/model/descriptions/word_description.rb +32 -0
- data/lib/yoda/model/function_signatures.rb +13 -0
- data/lib/yoda/model/function_signatures/base.rb +68 -0
- data/lib/yoda/model/function_signatures/constructor.rb +70 -0
- data/lib/yoda/model/function_signatures/formatter.rb +82 -0
- data/lib/yoda/model/function_signatures/method.rb +67 -0
- data/lib/yoda/model/function_signatures/overload.rb +79 -0
- data/lib/yoda/model/function_signatures/parameter_list.rb +108 -0
- data/lib/yoda/model/function_signatures/type_builder.rb +101 -0
- data/lib/yoda/model/node_signature.rb +28 -0
- data/lib/yoda/model/path.rb +96 -0
- data/lib/yoda/model/scoped_path.rb +44 -0
- data/lib/yoda/model/types.rb +84 -0
- data/lib/yoda/model/types/any_type.rb +32 -0
- data/lib/yoda/model/types/base.rb +37 -0
- data/lib/yoda/model/types/duck_type.rb +41 -0
- data/lib/yoda/model/types/function_type.rb +174 -0
- data/lib/yoda/model/types/generic_type.rb +66 -0
- data/lib/yoda/model/types/instance_type.rb +42 -0
- data/lib/yoda/model/types/module_type.rb +42 -0
- data/lib/yoda/model/types/sequence_type.rb +53 -0
- data/lib/yoda/model/types/union_type.rb +56 -0
- data/lib/yoda/model/types/unknown_type.rb +40 -0
- data/lib/yoda/model/types/value_type.rb +58 -0
- data/lib/yoda/model/values.rb +9 -0
- data/lib/yoda/model/values/base.rb +32 -0
- data/lib/yoda/model/values/instance_value.rb +65 -0
- data/lib/yoda/model/values/module_value.rb +72 -0
- data/lib/yoda/parsing.rb +15 -0
- data/lib/yoda/parsing/ast_traversable.rb +18 -0
- data/lib/yoda/parsing/comment_tokenizer.rb +59 -0
- data/lib/yoda/parsing/location.rb +101 -0
- data/lib/yoda/parsing/node_objects.rb +10 -0
- data/lib/yoda/parsing/node_objects/const_node.rb +52 -0
- data/lib/yoda/parsing/node_objects/method_definition.rb +46 -0
- data/lib/yoda/parsing/node_objects/namespace.rb +104 -0
- data/lib/yoda/parsing/node_objects/send_node.rb +72 -0
- data/lib/yoda/parsing/parser.rb +27 -0
- data/lib/yoda/parsing/query.rb +11 -0
- data/lib/yoda/parsing/query/current_comment_query.rb +80 -0
- data/lib/yoda/parsing/query/current_comment_token_query.rb +153 -0
- data/lib/yoda/parsing/query/current_commenting_node_query.rb +68 -0
- data/lib/yoda/parsing/query/current_location_node_query.rb +51 -0
- data/lib/yoda/parsing/query/current_node_comment_query.rb +40 -0
- data/lib/yoda/parsing/range.rb +41 -0
- data/lib/yoda/parsing/scopes.rb +15 -0
- data/lib/yoda/parsing/scopes/base.rb +78 -0
- data/lib/yoda/parsing/scopes/builder.rb +60 -0
- data/lib/yoda/parsing/scopes/class_definition.rb +47 -0
- data/lib/yoda/parsing/scopes/meta_class_definition.rb +44 -0
- data/lib/yoda/parsing/scopes/meta_method_definition.rb +70 -0
- data/lib/yoda/parsing/scopes/method_definition.rb +69 -0
- data/lib/yoda/parsing/scopes/module_definition.rb +36 -0
- data/lib/yoda/parsing/scopes/root.rb +25 -0
- data/lib/yoda/parsing/source_analyzer.rb +59 -0
- data/lib/yoda/parsing/source_cutter.rb +231 -0
- data/lib/yoda/parsing/type_parser.rb +141 -0
- data/lib/yoda/runner.rb +6 -0
- data/lib/yoda/runner/infer.rb +50 -0
- data/lib/yoda/runner/setup.rb +26 -0
- data/lib/yoda/server.rb +191 -0
- data/lib/yoda/server/client_info.rb +98 -0
- data/lib/yoda/server/completion_provider.rb +78 -0
- data/lib/yoda/server/definition_provider.rb +36 -0
- data/lib/yoda/server/deserializer.rb +27 -0
- data/lib/yoda/server/hover_provider.rb +38 -0
- data/lib/yoda/server/signature_provider.rb +46 -0
- data/lib/yoda/store.rb +13 -0
- data/lib/yoda/store/actions.rb +10 -0
- data/lib/yoda/store/actions/import_core_library.rb +30 -0
- data/lib/yoda/store/actions/import_gems.rb +91 -0
- data/lib/yoda/store/actions/read_file.rb +36 -0
- data/lib/yoda/store/actions/read_project_files.rb +29 -0
- data/lib/yoda/store/adapters.rb +14 -0
- data/lib/yoda/store/adapters/base.rb +58 -0
- data/lib/yoda/store/adapters/leveldb_adapter.rb +80 -0
- data/lib/yoda/store/adapters/lmdb_adapter.rb +113 -0
- data/lib/yoda/store/objects.rb +46 -0
- data/lib/yoda/store/objects/addressable.rb +25 -0
- data/lib/yoda/store/objects/base.rb +116 -0
- data/lib/yoda/store/objects/class_object.rb +51 -0
- data/lib/yoda/store/objects/merger.rb +94 -0
- data/lib/yoda/store/objects/meta_class_object.rb +41 -0
- data/lib/yoda/store/objects/method_object.rb +94 -0
- data/lib/yoda/store/objects/module_object.rb +11 -0
- data/lib/yoda/store/objects/namespace_object.rb +67 -0
- data/lib/yoda/store/objects/overload.rb +51 -0
- data/lib/yoda/store/objects/patch.rb +46 -0
- data/lib/yoda/store/objects/patch_set.rb +80 -0
- data/lib/yoda/store/objects/tag.rb +62 -0
- data/lib/yoda/store/objects/value_object.rb +45 -0
- data/lib/yoda/store/project.rb +159 -0
- data/lib/yoda/store/query.rb +12 -0
- data/lib/yoda/store/query/associators.rb +10 -0
- data/lib/yoda/store/query/associators/associate_ancestors.rb +103 -0
- data/lib/yoda/store/query/associators/associate_methods.rb +38 -0
- data/lib/yoda/store/query/base.rb +16 -0
- data/lib/yoda/store/query/find_constant.rb +150 -0
- data/lib/yoda/store/query/find_meta_class.rb +18 -0
- data/lib/yoda/store/query/find_method.rb +74 -0
- data/lib/yoda/store/query/find_signature.rb +43 -0
- data/lib/yoda/store/registry.rb +67 -0
- data/lib/yoda/store/yard_importer.rb +260 -0
- data/lib/yoda/typing.rb +10 -0
- data/lib/yoda/typing/context.rb +96 -0
- data/lib/yoda/typing/environment.rb +35 -0
- data/lib/yoda/typing/evaluator.rb +256 -0
- data/lib/yoda/typing/lexical_scope.rb +26 -0
- data/lib/yoda/typing/relation.rb +15 -0
- data/lib/yoda/typing/traces.rb +9 -0
- data/lib/yoda/typing/traces/base.rb +26 -0
- data/lib/yoda/typing/traces/normal.rb +22 -0
- data/lib/yoda/typing/traces/send.rb +26 -0
- data/lib/yoda/version.rb +3 -0
- data/lib/yoda/yard_extensions.rb +11 -0
- data/lib/yoda/yard_extensions/sig_directive.rb +40 -0
- data/lib/yoda/yard_extensions/type_tag.rb +10 -0
- data/package.json +76 -0
- data/scripts/benchmark.rb +6 -0
- data/scripts/build_core_index.sh +16 -0
- data/yarn.lock +13 -0
- data/yoda-language-server.gemspec +40 -0
- metadata +424 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module Yoda
|
|
2
|
+
module Evaluation
|
|
3
|
+
class CodeCompletion
|
|
4
|
+
class MethodProvider < BaseProvider
|
|
5
|
+
# @return [true, false]
|
|
6
|
+
def providable?
|
|
7
|
+
!!(current_send)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @return [Array<Model::CompletionItem>]
|
|
11
|
+
def candidates
|
|
12
|
+
method_candidates.map do |method_candidate|
|
|
13
|
+
Model::CompletionItem.new(
|
|
14
|
+
description: Model::Descriptions::FunctionDescription.new(method_candidate),
|
|
15
|
+
range: substitution_range,
|
|
16
|
+
kind: :method,
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# @return [Range]
|
|
24
|
+
def substitution_range
|
|
25
|
+
return current_send.selector_range if current_send.on_selector?(location)
|
|
26
|
+
return Parsing::Range.new(current_send.next_location_to_dot, current_send.next_location_to_dot) if current_send.on_dot?(location)
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Array<Store::Objects::Method>]
|
|
31
|
+
def method_candidates
|
|
32
|
+
return [] unless providable?
|
|
33
|
+
receiver_values
|
|
34
|
+
.map { |value| Store::Query::FindSignature.new(registry).select(value, /\A#{Regexp.escape(index_word)}/, visibility: method_visibility_of_send_node(current_send)) }
|
|
35
|
+
.flatten
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @param send_node [Parsing::NodeObjects::SendNode]
|
|
39
|
+
# @return [Array<Symbol>]
|
|
40
|
+
def method_visibility_of_send_node(send_node)
|
|
41
|
+
if send_node.receiver_node
|
|
42
|
+
%i(public)
|
|
43
|
+
else
|
|
44
|
+
%i(public private protected)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Array<Store::Objects::Base>]
|
|
49
|
+
def receiver_values
|
|
50
|
+
@receiver_values ||= begin
|
|
51
|
+
if current_receiver_node
|
|
52
|
+
evaluator.calculate_values(current_receiver_node)
|
|
53
|
+
else
|
|
54
|
+
# implicit call for self
|
|
55
|
+
[evaluator.scope_constant]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [Parsing::NodeObjects::SendNode, nil]
|
|
61
|
+
def current_send
|
|
62
|
+
@current_send ||= begin
|
|
63
|
+
node = source_analyzer.nodes_to_current_location_from_root.last
|
|
64
|
+
return nil unless node.type == :send
|
|
65
|
+
Parsing::NodeObjects::SendNode.new(node)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [Parser::AST::Node, nil]
|
|
70
|
+
def current_receiver_node
|
|
71
|
+
current_send&.receiver_node
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @return [String, nil]
|
|
75
|
+
def index_word
|
|
76
|
+
return nil unless providable?
|
|
77
|
+
@index_word ||= current_send.on_selector?(location) ? current_send.selector_name.slice(0..current_send.offset_in_selector(location)) : ''
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Yoda
|
|
2
|
+
module Evaluation
|
|
3
|
+
class CodeCompletion
|
|
4
|
+
# WIP
|
|
5
|
+
class VariableProvider < BaseProvider
|
|
6
|
+
# @return [true, false]
|
|
7
|
+
def providable?
|
|
8
|
+
false
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @return [Array<Model::CompletionItem>]
|
|
12
|
+
def candidates
|
|
13
|
+
[]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Yoda
|
|
2
|
+
module Evaluation
|
|
3
|
+
class CommentCompletion
|
|
4
|
+
require 'yoda/evaluation/comment_completion/base_provider'
|
|
5
|
+
require 'yoda/evaluation/comment_completion/param_provider'
|
|
6
|
+
require 'yoda/evaluation/comment_completion/tag_provider'
|
|
7
|
+
require 'yoda/evaluation/comment_completion/type_provider'
|
|
8
|
+
|
|
9
|
+
# @type Store::Registry
|
|
10
|
+
attr_reader :registry
|
|
11
|
+
|
|
12
|
+
# @type ::Parser::AST::Node
|
|
13
|
+
attr_reader :ast
|
|
14
|
+
|
|
15
|
+
# @type Array<::Parser::Source::Comment>
|
|
16
|
+
attr_reader :comments
|
|
17
|
+
|
|
18
|
+
# @type Location
|
|
19
|
+
attr_reader :location
|
|
20
|
+
|
|
21
|
+
# @param registry [Store::Registry]
|
|
22
|
+
# @param ast [::Parser::AST::Node]
|
|
23
|
+
# @param comments [Array<::Parser::Source::Comment>]
|
|
24
|
+
# @param location [Location]
|
|
25
|
+
def initialize(registry, ast, comments, location)
|
|
26
|
+
@registry = registry
|
|
27
|
+
@ast = ast
|
|
28
|
+
@comments = comments
|
|
29
|
+
@location = location
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @return [true, false]
|
|
33
|
+
def available?
|
|
34
|
+
comment? && providers.any?(&:available?)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @return [Array<Model::CompletionItem>]
|
|
38
|
+
def candidates
|
|
39
|
+
available? ? providers.select(&:available?).map(&:candidates).flatten : []
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# @return [Array<CommentCompletion::BaseProvider>]
|
|
45
|
+
def providers
|
|
46
|
+
[param_provider, tag_provider, type_provider]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [ParamProvider]
|
|
50
|
+
def param_provider
|
|
51
|
+
@param_provider ||= ParamProvider.new(registry, ast, comments, location)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [TagProvider]
|
|
55
|
+
def tag_provider
|
|
56
|
+
@tag_provider ||= TagProvider.new(registry, ast, comments, location)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [TypeProvider]
|
|
60
|
+
def type_provider
|
|
61
|
+
@type_provider ||= TypeProvider.new(registry, ast, comments, location)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def comment?
|
|
65
|
+
return @is_comment if instance_variable_defined?(:@is_comment)
|
|
66
|
+
@is_comment = !!Parsing::Query::CurrentCommentQuery.new(comments, location).current_comment
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module Yoda
|
|
2
|
+
module Evaluation
|
|
3
|
+
class CommentCompletion
|
|
4
|
+
# @abstract
|
|
5
|
+
class BaseProvider
|
|
6
|
+
# @type Store::Registry
|
|
7
|
+
attr_reader :registry
|
|
8
|
+
|
|
9
|
+
# @type ::Parser::AST::Node
|
|
10
|
+
attr_reader :ast
|
|
11
|
+
|
|
12
|
+
# @type Array<::Parser::Source::Comment>
|
|
13
|
+
attr_reader :comments
|
|
14
|
+
|
|
15
|
+
# @type Location
|
|
16
|
+
attr_reader :location
|
|
17
|
+
|
|
18
|
+
# @param registry [Store::Registry]
|
|
19
|
+
# @param ast [::Parser::AST::Node]
|
|
20
|
+
# @param comments [Array<::Parser::Source::Comment>]
|
|
21
|
+
# @param location [Location]
|
|
22
|
+
def initialize(registry, ast, comments, location)
|
|
23
|
+
@registry = registry
|
|
24
|
+
@ast = ast
|
|
25
|
+
@comments = comments
|
|
26
|
+
@location = location
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @abstract
|
|
30
|
+
# @return [true, false]
|
|
31
|
+
def available?
|
|
32
|
+
fail NotImplementedError
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @abstract
|
|
36
|
+
# @return [Array<Model::CompletionItem>]
|
|
37
|
+
def candidates
|
|
38
|
+
fail NotImplementedError
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
# @return [Parsing::Query::CurrentCommentTokenQuery]
|
|
44
|
+
def current_comment_token_query
|
|
45
|
+
@current_comment_token_query ||=
|
|
46
|
+
Parsing::Query::CurrentCommentTokenQuery.new(
|
|
47
|
+
current_comment_query.current_comment_block_text,
|
|
48
|
+
current_comment_query.location_in_current_comment_block,
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @return [Parsing::Query::CurrentCommentQuery]
|
|
53
|
+
def current_comment_query
|
|
54
|
+
@current_comment_query ||= Parsing::Query::CurrentCommentQuery.new(comments, location)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @return [CurrentCommentingNodeQuery]
|
|
58
|
+
def current_commenting_node_query
|
|
59
|
+
Parsing::Query::CurrentCommentingNodeQuery.new(ast, comments, location)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Yoda
|
|
2
|
+
module Evaluation
|
|
3
|
+
class CommentCompletion
|
|
4
|
+
# @note WIP
|
|
5
|
+
class ParamProvider < BaseProvider
|
|
6
|
+
# @return [true, false]
|
|
7
|
+
def available?
|
|
8
|
+
current_comment_token_query.current_state == :param
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @return [Array<Model::CompletionItem>]
|
|
12
|
+
def candidates
|
|
13
|
+
[]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Yoda
|
|
2
|
+
module Evaluation
|
|
3
|
+
class CommentCompletion
|
|
4
|
+
class TagProvider < BaseProvider
|
|
5
|
+
# @return [true, false]
|
|
6
|
+
def available?
|
|
7
|
+
current_comment_token_query.current_state == :tag
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @return [Array<Model::CompletionItem>]
|
|
11
|
+
def candidates
|
|
12
|
+
description_candidates.map { |description| Model::CompletionItem.new(description: description, range: substitution_range) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
# @return [Array<Model::Descriptions::WordDescription>]
|
|
18
|
+
def description_candidates
|
|
19
|
+
return [] unless available?
|
|
20
|
+
tagnames.select { |tagname| tagname.start_with?(index_word) }.map { |obj| Model::Descriptions::WordDescription.new(obj) }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Parsing::Range, nil]
|
|
24
|
+
def substitution_range
|
|
25
|
+
return nil unless available?
|
|
26
|
+
current_comment_query.absolute_range(current_comment_token_query.current_range)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @return [String]
|
|
30
|
+
def index_word
|
|
31
|
+
current_comment_token_query.current_word
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @return [Array<String>]
|
|
35
|
+
def tagnames
|
|
36
|
+
@tagnames ||= YARD::Tags::Library.labels.map { |tag_symbol, label| "@#{tag_symbol}" }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Yoda
|
|
2
|
+
module Evaluation
|
|
3
|
+
class CommentCompletion
|
|
4
|
+
class TypeProvider < BaseProvider
|
|
5
|
+
# @return [true, false]
|
|
6
|
+
def available?
|
|
7
|
+
[:type, :type_tag_type].include?(current_comment_token_query.current_state)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @return [Array<Model::CompletionItem>]
|
|
11
|
+
def candidates
|
|
12
|
+
description_candidates.map { |description| Model::CompletionItem.new(description: description, range: substitution_range) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
# @return [Array<Model::Descriptions::Base>]
|
|
18
|
+
def description_candidates
|
|
19
|
+
return [] unless available?
|
|
20
|
+
scoped_path = Model::ScopedPath.new(lexical_scope(namespace), index_word)
|
|
21
|
+
Store::Query::FindConstant.new(registry).select_with_prefix(scoped_path).map { |obj| Model::Descriptions::ValueDescription.new(obj) }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [Parsing::Range, nil]
|
|
25
|
+
def substitution_range
|
|
26
|
+
return nil unless available?
|
|
27
|
+
# @todo Move this routine to Parsing module
|
|
28
|
+
if current_comment_token_query.current_range
|
|
29
|
+
range = current_comment_token_query.current_range.move(
|
|
30
|
+
row: current_comment_query.begin_point_of_current_comment_block.row - 1,
|
|
31
|
+
column: current_comment_query.begin_point_of_current_comment_block.column,
|
|
32
|
+
)
|
|
33
|
+
cut_point = current_comment_token_query.at_sign? ? 1 : (current_comment_token_query.current_word.rindex('::') || -2) + 2
|
|
34
|
+
Parsing::Range.new(range.begin_location.move(row: 0, column: cut_point), range.end_location)
|
|
35
|
+
else
|
|
36
|
+
Parsing::Range.new(location, location)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @return [String]
|
|
41
|
+
def index_word
|
|
42
|
+
current_comment_token_query.at_sign? ? '' : current_comment_token_query.current_word
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [Parsing::NodeObjects::Namespace, nil]
|
|
46
|
+
def namespace
|
|
47
|
+
current_commenting_node_query.current_namespace
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @param namespace [Parsing::NodeObjects::Namespace]
|
|
51
|
+
# @return [Array<Path>]
|
|
52
|
+
def lexical_scope(namespace)
|
|
53
|
+
namespace.paths_from_root.reverse.map { |name| Model::Path.build(name.empty? ? 'Object' : name.gsub(/\A::/, '')) }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Yoda
|
|
2
|
+
module Evaluation
|
|
3
|
+
class CurrentNodeExplain
|
|
4
|
+
# @return [Store::Registry]
|
|
5
|
+
attr_reader :registry
|
|
6
|
+
|
|
7
|
+
# @return [String]
|
|
8
|
+
attr_reader :source
|
|
9
|
+
|
|
10
|
+
# @return [Parsing::Location]
|
|
11
|
+
attr_reader :location
|
|
12
|
+
|
|
13
|
+
# @param registry [Store::Registry]
|
|
14
|
+
# @param source [String]
|
|
15
|
+
# @param location [Parsing::Location]
|
|
16
|
+
def initialize(registry, source, location)
|
|
17
|
+
@registry = registry
|
|
18
|
+
@source = source
|
|
19
|
+
@location = location
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [Model::NodeSignature, nil]
|
|
23
|
+
def current_node_signature
|
|
24
|
+
return nil if !valid? || !current_node_trace
|
|
25
|
+
@current_node_signature ||= Model::NodeSignature.new(current_node, current_node_trace)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [true, false]
|
|
29
|
+
def valid?
|
|
30
|
+
!!(current_node)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [Array<(String, Integer, Integer)>]
|
|
34
|
+
def defined_files
|
|
35
|
+
return [] if !valid? || !current_node_trace
|
|
36
|
+
case current_node.type
|
|
37
|
+
when :send
|
|
38
|
+
current_node_trace.functions.map { |function| function.primary_source }.compact
|
|
39
|
+
when :const
|
|
40
|
+
current_node_trace.values.map { |value| value.primary_source || value.sources.first }.compact
|
|
41
|
+
else
|
|
42
|
+
[]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# @return [Typing::Traces::Base, nil]
|
|
49
|
+
def current_node_trace
|
|
50
|
+
return nil unless valid?
|
|
51
|
+
@current_node_trace ||= evaluator.calculate_trace(current_node)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [Parser::AST::Node]
|
|
55
|
+
def current_node
|
|
56
|
+
analyzer.nodes_to_current_location_from_root.last
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [Evaluator]
|
|
60
|
+
def evaluator
|
|
61
|
+
@evaluator ||= Evaluator.from_ast(registry, analyzer.ast, location)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @return [SourceAnalyzer]
|
|
65
|
+
def analyzer
|
|
66
|
+
@analyzer ||= Parsing::SourceAnalyzer.from_source(source, location)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module Yoda
|
|
2
|
+
module Evaluation
|
|
3
|
+
class Evaluator
|
|
4
|
+
# @return [Parsing::Scopes::Base]
|
|
5
|
+
attr_reader :scope
|
|
6
|
+
|
|
7
|
+
# @return [Store::Registry]
|
|
8
|
+
attr_reader :registry
|
|
9
|
+
|
|
10
|
+
# @param registry [Store::Registry]
|
|
11
|
+
# @param ast [Parser::AST::Node]
|
|
12
|
+
# @param location [Parsing::Location]
|
|
13
|
+
# @return [Evaluator]
|
|
14
|
+
def self.from_ast(registry, ast, location)
|
|
15
|
+
from_root_scope(registry, Parsing::Scopes::Builder.new(ast).root_scope, location)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param registry [Store::Registry]
|
|
19
|
+
# @param root_scope [Parsing::Scopes::Root]
|
|
20
|
+
# @param location [Parsing::Location]
|
|
21
|
+
# @return [Evaluator]
|
|
22
|
+
def self.from_root_scope(registry, root_scope, location)
|
|
23
|
+
new(registry, root_scope.find_evaluation_root_scope(location) || root_scope)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @param registry [Store::Registry]
|
|
27
|
+
# @param scope [Parsing::Scopes::Base]
|
|
28
|
+
def initialize(registry, scope)
|
|
29
|
+
@registry = registry
|
|
30
|
+
@scope = scope
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @param code_node [::Parser::AST::Node]
|
|
34
|
+
# @return [Model::Types::Base, nil]
|
|
35
|
+
def calculate_type(code_node)
|
|
36
|
+
calculate_trace(code_node)&.type
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @param code_node [::Parser::AST::Node]
|
|
40
|
+
# @return [Array<Store::Objects::Base>]
|
|
41
|
+
def calculate_values(code_node)
|
|
42
|
+
trace = calculate_trace(code_node)
|
|
43
|
+
trace ? trace.values : []
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @param code_node [::Parser::AST::Node, nil]
|
|
47
|
+
# @return [Typing::Traces::Base, nil]
|
|
48
|
+
def calculate_trace(code_node)
|
|
49
|
+
return nil unless code_node
|
|
50
|
+
evaluate
|
|
51
|
+
evaluator.find_trace(code_node)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [Store::Objects::Base, nil]
|
|
55
|
+
def scope_constant
|
|
56
|
+
@scope_constant ||= begin
|
|
57
|
+
Store::Query::FindConstant.new(registry).find(scope.scope_name)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def evaluate
|
|
64
|
+
unless @evaluated
|
|
65
|
+
evaluator.process(scope.body_node)
|
|
66
|
+
@evaluated = true
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @return [Typing::Evaluator]
|
|
71
|
+
def evaluator
|
|
72
|
+
@evaluator ||= Typing::Evaluator.new(evaluation_context)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @return [Typing::Context]
|
|
76
|
+
def evaluation_context
|
|
77
|
+
@evaluation_context ||= begin
|
|
78
|
+
fail RuntimeError, "The namespace #{scope.scope_name} (#{scope}) is not registered" unless scope_constant
|
|
79
|
+
lexical_scope = Typing::LexicalScope.new(scope_constant, scope.ancestor_scopes)
|
|
80
|
+
context = Typing::Context.new(registry: registry, caller_object: receiver, lexical_scope: lexical_scope)
|
|
81
|
+
context.env.bind_method_parameters(current_method_signature) if current_method_signature
|
|
82
|
+
context
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @return [Model::FunctionSignatures::Base, nil]
|
|
87
|
+
def current_method_signature
|
|
88
|
+
return unless scope.kind == :method
|
|
89
|
+
@current_method_signature ||= Store::Query::FindSignature.new(registry).select(scope_constant, scope.name.to_s)&.first
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def receiver
|
|
93
|
+
@receiver ||= begin
|
|
94
|
+
if scope.kind == :method
|
|
95
|
+
Store::Query::FindConstant.new(registry).find(scope.scope_name)
|
|
96
|
+
else
|
|
97
|
+
Store::Query::FindMetaClass.new(registry).find(scope.scope_name)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|