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.
Files changed (171) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +78 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +85 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/client/atom/main.js +27 -0
  13. data/client/vscode/.gitignore +4 -0
  14. data/client/vscode/.vscode/launch.json +28 -0
  15. data/client/vscode/.vscode/settings.json +9 -0
  16. data/client/vscode/.vscode/tasks.json +20 -0
  17. data/client/vscode/.vscodeignore +8 -0
  18. data/client/vscode/CHANGELOG.md +7 -0
  19. data/client/vscode/README.md +65 -0
  20. data/client/vscode/package-lock.json +2688 -0
  21. data/client/vscode/package.json +39 -0
  22. data/client/vscode/src/extension.ts +42 -0
  23. data/client/vscode/src/test/extension.test.ts +22 -0
  24. data/client/vscode/src/test/index.ts +22 -0
  25. data/client/vscode/tsconfig.json +16 -0
  26. data/client/vscode/vsc-extension-quickstart.md +33 -0
  27. data/exe/yoda +27 -0
  28. data/lib/yoda.rb +11 -0
  29. data/lib/yoda/evaluation.rb +9 -0
  30. data/lib/yoda/evaluation/code_completion.rb +65 -0
  31. data/lib/yoda/evaluation/code_completion/base_provider.rb +57 -0
  32. data/lib/yoda/evaluation/code_completion/const_provider.rb +90 -0
  33. data/lib/yoda/evaluation/code_completion/method_provider.rb +82 -0
  34. data/lib/yoda/evaluation/code_completion/variable_provider.rb +18 -0
  35. data/lib/yoda/evaluation/comment_completion.rb +70 -0
  36. data/lib/yoda/evaluation/comment_completion/base_provider.rb +64 -0
  37. data/lib/yoda/evaluation/comment_completion/param_provider.rb +18 -0
  38. data/lib/yoda/evaluation/comment_completion/tag_provider.rb +41 -0
  39. data/lib/yoda/evaluation/comment_completion/type_provider.rb +58 -0
  40. data/lib/yoda/evaluation/current_node_explain.rb +70 -0
  41. data/lib/yoda/evaluation/evaluator.rb +103 -0
  42. data/lib/yoda/evaluation/signature_discovery.rb +83 -0
  43. data/lib/yoda/model.rb +12 -0
  44. data/lib/yoda/model/completion_item.rb +56 -0
  45. data/lib/yoda/model/descriptions.rb +10 -0
  46. data/lib/yoda/model/descriptions/base.rb +26 -0
  47. data/lib/yoda/model/descriptions/function_description.rb +40 -0
  48. data/lib/yoda/model/descriptions/value_description.rb +33 -0
  49. data/lib/yoda/model/descriptions/word_description.rb +32 -0
  50. data/lib/yoda/model/function_signatures.rb +13 -0
  51. data/lib/yoda/model/function_signatures/base.rb +68 -0
  52. data/lib/yoda/model/function_signatures/constructor.rb +70 -0
  53. data/lib/yoda/model/function_signatures/formatter.rb +82 -0
  54. data/lib/yoda/model/function_signatures/method.rb +67 -0
  55. data/lib/yoda/model/function_signatures/overload.rb +79 -0
  56. data/lib/yoda/model/function_signatures/parameter_list.rb +108 -0
  57. data/lib/yoda/model/function_signatures/type_builder.rb +101 -0
  58. data/lib/yoda/model/node_signature.rb +28 -0
  59. data/lib/yoda/model/path.rb +96 -0
  60. data/lib/yoda/model/scoped_path.rb +44 -0
  61. data/lib/yoda/model/types.rb +84 -0
  62. data/lib/yoda/model/types/any_type.rb +32 -0
  63. data/lib/yoda/model/types/base.rb +37 -0
  64. data/lib/yoda/model/types/duck_type.rb +41 -0
  65. data/lib/yoda/model/types/function_type.rb +174 -0
  66. data/lib/yoda/model/types/generic_type.rb +66 -0
  67. data/lib/yoda/model/types/instance_type.rb +42 -0
  68. data/lib/yoda/model/types/module_type.rb +42 -0
  69. data/lib/yoda/model/types/sequence_type.rb +53 -0
  70. data/lib/yoda/model/types/union_type.rb +56 -0
  71. data/lib/yoda/model/types/unknown_type.rb +40 -0
  72. data/lib/yoda/model/types/value_type.rb +58 -0
  73. data/lib/yoda/model/values.rb +9 -0
  74. data/lib/yoda/model/values/base.rb +32 -0
  75. data/lib/yoda/model/values/instance_value.rb +65 -0
  76. data/lib/yoda/model/values/module_value.rb +72 -0
  77. data/lib/yoda/parsing.rb +15 -0
  78. data/lib/yoda/parsing/ast_traversable.rb +18 -0
  79. data/lib/yoda/parsing/comment_tokenizer.rb +59 -0
  80. data/lib/yoda/parsing/location.rb +101 -0
  81. data/lib/yoda/parsing/node_objects.rb +10 -0
  82. data/lib/yoda/parsing/node_objects/const_node.rb +52 -0
  83. data/lib/yoda/parsing/node_objects/method_definition.rb +46 -0
  84. data/lib/yoda/parsing/node_objects/namespace.rb +104 -0
  85. data/lib/yoda/parsing/node_objects/send_node.rb +72 -0
  86. data/lib/yoda/parsing/parser.rb +27 -0
  87. data/lib/yoda/parsing/query.rb +11 -0
  88. data/lib/yoda/parsing/query/current_comment_query.rb +80 -0
  89. data/lib/yoda/parsing/query/current_comment_token_query.rb +153 -0
  90. data/lib/yoda/parsing/query/current_commenting_node_query.rb +68 -0
  91. data/lib/yoda/parsing/query/current_location_node_query.rb +51 -0
  92. data/lib/yoda/parsing/query/current_node_comment_query.rb +40 -0
  93. data/lib/yoda/parsing/range.rb +41 -0
  94. data/lib/yoda/parsing/scopes.rb +15 -0
  95. data/lib/yoda/parsing/scopes/base.rb +78 -0
  96. data/lib/yoda/parsing/scopes/builder.rb +60 -0
  97. data/lib/yoda/parsing/scopes/class_definition.rb +47 -0
  98. data/lib/yoda/parsing/scopes/meta_class_definition.rb +44 -0
  99. data/lib/yoda/parsing/scopes/meta_method_definition.rb +70 -0
  100. data/lib/yoda/parsing/scopes/method_definition.rb +69 -0
  101. data/lib/yoda/parsing/scopes/module_definition.rb +36 -0
  102. data/lib/yoda/parsing/scopes/root.rb +25 -0
  103. data/lib/yoda/parsing/source_analyzer.rb +59 -0
  104. data/lib/yoda/parsing/source_cutter.rb +231 -0
  105. data/lib/yoda/parsing/type_parser.rb +141 -0
  106. data/lib/yoda/runner.rb +6 -0
  107. data/lib/yoda/runner/infer.rb +50 -0
  108. data/lib/yoda/runner/setup.rb +26 -0
  109. data/lib/yoda/server.rb +191 -0
  110. data/lib/yoda/server/client_info.rb +98 -0
  111. data/lib/yoda/server/completion_provider.rb +78 -0
  112. data/lib/yoda/server/definition_provider.rb +36 -0
  113. data/lib/yoda/server/deserializer.rb +27 -0
  114. data/lib/yoda/server/hover_provider.rb +38 -0
  115. data/lib/yoda/server/signature_provider.rb +46 -0
  116. data/lib/yoda/store.rb +13 -0
  117. data/lib/yoda/store/actions.rb +10 -0
  118. data/lib/yoda/store/actions/import_core_library.rb +30 -0
  119. data/lib/yoda/store/actions/import_gems.rb +91 -0
  120. data/lib/yoda/store/actions/read_file.rb +36 -0
  121. data/lib/yoda/store/actions/read_project_files.rb +29 -0
  122. data/lib/yoda/store/adapters.rb +14 -0
  123. data/lib/yoda/store/adapters/base.rb +58 -0
  124. data/lib/yoda/store/adapters/leveldb_adapter.rb +80 -0
  125. data/lib/yoda/store/adapters/lmdb_adapter.rb +113 -0
  126. data/lib/yoda/store/objects.rb +46 -0
  127. data/lib/yoda/store/objects/addressable.rb +25 -0
  128. data/lib/yoda/store/objects/base.rb +116 -0
  129. data/lib/yoda/store/objects/class_object.rb +51 -0
  130. data/lib/yoda/store/objects/merger.rb +94 -0
  131. data/lib/yoda/store/objects/meta_class_object.rb +41 -0
  132. data/lib/yoda/store/objects/method_object.rb +94 -0
  133. data/lib/yoda/store/objects/module_object.rb +11 -0
  134. data/lib/yoda/store/objects/namespace_object.rb +67 -0
  135. data/lib/yoda/store/objects/overload.rb +51 -0
  136. data/lib/yoda/store/objects/patch.rb +46 -0
  137. data/lib/yoda/store/objects/patch_set.rb +80 -0
  138. data/lib/yoda/store/objects/tag.rb +62 -0
  139. data/lib/yoda/store/objects/value_object.rb +45 -0
  140. data/lib/yoda/store/project.rb +159 -0
  141. data/lib/yoda/store/query.rb +12 -0
  142. data/lib/yoda/store/query/associators.rb +10 -0
  143. data/lib/yoda/store/query/associators/associate_ancestors.rb +103 -0
  144. data/lib/yoda/store/query/associators/associate_methods.rb +38 -0
  145. data/lib/yoda/store/query/base.rb +16 -0
  146. data/lib/yoda/store/query/find_constant.rb +150 -0
  147. data/lib/yoda/store/query/find_meta_class.rb +18 -0
  148. data/lib/yoda/store/query/find_method.rb +74 -0
  149. data/lib/yoda/store/query/find_signature.rb +43 -0
  150. data/lib/yoda/store/registry.rb +67 -0
  151. data/lib/yoda/store/yard_importer.rb +260 -0
  152. data/lib/yoda/typing.rb +10 -0
  153. data/lib/yoda/typing/context.rb +96 -0
  154. data/lib/yoda/typing/environment.rb +35 -0
  155. data/lib/yoda/typing/evaluator.rb +256 -0
  156. data/lib/yoda/typing/lexical_scope.rb +26 -0
  157. data/lib/yoda/typing/relation.rb +15 -0
  158. data/lib/yoda/typing/traces.rb +9 -0
  159. data/lib/yoda/typing/traces/base.rb +26 -0
  160. data/lib/yoda/typing/traces/normal.rb +22 -0
  161. data/lib/yoda/typing/traces/send.rb +26 -0
  162. data/lib/yoda/version.rb +3 -0
  163. data/lib/yoda/yard_extensions.rb +11 -0
  164. data/lib/yoda/yard_extensions/sig_directive.rb +40 -0
  165. data/lib/yoda/yard_extensions/type_tag.rb +10 -0
  166. data/package.json +76 -0
  167. data/scripts/benchmark.rb +6 -0
  168. data/scripts/build_core_index.sh +16 -0
  169. data/yarn.lock +13 -0
  170. data/yoda-language-server.gemspec +40 -0
  171. metadata +424 -0
@@ -0,0 +1,72 @@
1
+ module Yoda
2
+ module Parsing
3
+ module NodeObjects
4
+ class SendNode
5
+ attr_reader :node
6
+
7
+ # @param node [::Parser::AST::Node]
8
+ def initialize(node)
9
+ fail ArgumentError, node unless node.is_a?(::Parser::AST::Node)
10
+ @node = node
11
+ end
12
+
13
+ # @return [true, false]
14
+ def on_selector?(location)
15
+ node.location.selector ? selector_range.include?(location) : false
16
+ end
17
+
18
+ # @param location [Location]
19
+ # @return [true, false]
20
+ def on_dot?(location)
21
+ node.location.dot ? dot_range.include?(location) : false
22
+ end
23
+
24
+ # @param location [Location]
25
+ # @return [true, false]
26
+ def on_parameter?(location)
27
+ parameter_range.include?(location)
28
+ end
29
+
30
+ # @return [Range]
31
+ def parameter_range
32
+ @parameter_range ||=
33
+ Range.new(
34
+ Location.of_ast_location(node.location.selector.end),
35
+ Location.of_ast_location(node.location.expression.end).move(row: 0, column: -1),
36
+ )
37
+ end
38
+
39
+ # @return [Range]
40
+ def selector_range
41
+ @selector_range ||= Range.of_ast_location(node.location.selector)
42
+ end
43
+
44
+ # @return [Range, nil]
45
+ def dot_range
46
+ @dot_range ||= node.location.dot && Range.of_ast_location(node.location.dot)
47
+ end
48
+
49
+ # @return [Location, nil]
50
+ def next_location_to_dot
51
+ node.location.dot && Range.of_ast_location(node.location.dot).end_location
52
+ end
53
+
54
+ # @return [Parser::AST::Node, nil]
55
+ def receiver_node
56
+ node && node.children[0]
57
+ end
58
+
59
+ # @return [String]
60
+ def selector_name
61
+ node.children[1].to_s
62
+ end
63
+
64
+ # @param location [Location]
65
+ # @return Integer
66
+ def offset_in_selector(location)
67
+ location.offset_from_begin(node.location.selector)[:column]
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,27 @@
1
+ require 'parser/current'
2
+
3
+ module Yoda
4
+ module Parsing
5
+ class Parser
6
+ # @param string [String]
7
+ # @return [::Parser::AST::Node]
8
+ def parse(string)
9
+ ::Parser::CurrentRuby.parse(string)
10
+ end
11
+
12
+ # @param string [String]
13
+ # @return [(::Parser::AST::Node, Array<::Parser::Source::Comment>)]
14
+ def parse_with_comments(string)
15
+ ::Parser::CurrentRuby.parse_with_comments(string)
16
+ end
17
+
18
+ # @param string [String]
19
+ # @return [(::Parser::AST::Node, Array<::Parser::Source::Comment>), nil]
20
+ def parse_with_comments_if_valid(string)
21
+ parse_with_comments(source)
22
+ rescue ::Parser::SyntaxError
23
+ nil
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ module Yoda
2
+ module Parsing
3
+ module Query
4
+ require 'yoda/parsing/query/current_comment_query'
5
+ require 'yoda/parsing/query/current_comment_token_query'
6
+ require 'yoda/parsing/query/current_commenting_node_query'
7
+ require 'yoda/parsing/query/current_location_node_query'
8
+ require 'yoda/parsing/query/current_node_comment_query'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,80 @@
1
+ module Yoda
2
+ module Parsing
3
+ module Query
4
+ # Provides helper methods to find the current comment which means the comment on the current position.
5
+ class CurrentCommentQuery
6
+ attr_reader :comments, :location
7
+
8
+ # @param comments [Array<::Parser::Source::Comment>]
9
+ # @param location [Location] represents the current position.
10
+ def initialize(comments, location)
11
+ fail ArgumentError, comments unless comments.all? { |comment| comment.is_a?(::Parser::Source::Comment) }
12
+ fail ArgumentError, location unless location.is_a?(Location)
13
+ @comments = comments
14
+ @location = location
15
+ end
16
+
17
+ # The single line comment which the current position is on.
18
+ # @return [::Parser::Source::Comment, nil]
19
+ def current_comment
20
+ @current_comment ||= comments.find { |comment| location.included?(comment.location) }
21
+ end
22
+
23
+ # The multiple line comments which the current position is on.
24
+ # @return [Array<::Parser::Source::Comment>]
25
+ def current_comment_block
26
+ @current_comment_block ||= current_comment ? comment_blocks.find { |block| block.include?(current_comment) } : []
27
+ end
28
+
29
+ # The relative coordinates of the current position from the beginning position of the current comment.
30
+ # @return [Location]
31
+ def location_in_current_comment_block
32
+ relative_position(location)
33
+ end
34
+
35
+ # @return [Location]
36
+ def begin_point_of_current_comment_block
37
+ Location.new(row: current_comment_block.first.location.line, column: current_comment_block.first.location.column)
38
+ end
39
+
40
+ # @group Coordinate conversion
41
+
42
+ # Calculate relative position (the coordinates from the beginning point) from the relative position.
43
+ # @param position [Location]
44
+ def relative_position(position)
45
+ position.move(row: 1 - current_comment_block.first.location.line, column: - current_comment_block.first.location.column)
46
+ end
47
+
48
+ # Calculate absolute position from the relative position.
49
+ # @param position [Location]
50
+ def absolute_position(position)
51
+ position.move(row: current_comment_block.first.location.line - 1, column: current_comment_block.first.location.column)
52
+ end
53
+
54
+ # Calculate relative range from the relative range.
55
+ # @param range [Range]
56
+ def relative_range(range)
57
+ range.move(row: 1 - current_comment_block.first.location.line, column: - current_comment_block.first.location.column)
58
+ end
59
+
60
+ # Calculate absolute range from the relative range.
61
+ # @param range [Range]
62
+ def absolute_range(range)
63
+ range.move(row: current_comment_block.first.location.line - 1, column: current_comment_block.first.location.column)
64
+ end
65
+
66
+ # @return [String]
67
+ def current_comment_block_text
68
+ current_comment_block.map(&:text).join("\n")
69
+ end
70
+
71
+ private
72
+
73
+ # @return [Array<Array<::Parser::Source::Comment>>]
74
+ def comment_blocks
75
+ @comment_blocks ||= comments.chunk_while { |i, j| i.location.line + 1 == j.location.line }
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,153 @@
1
+ module Yoda
2
+ module Parsing
3
+ module Query
4
+ # Provides helper methods to find the current comment token (token on current position) and its kind.
5
+ class CurrentCommentTokenQuery
6
+ attr_reader :comment, :location_in_comment
7
+
8
+ # @param comment [String]
9
+ # @param location_in_comment [Location] represents relative coordinates of the current position from the beginning position of the current comment.
10
+ def initialize(comment, location_in_comment)
11
+ fail ArgumentError, comment unless comment.is_a?(String)
12
+ fail ArgumentError, location_in_comment unless location_in_comment.is_a?(Location)
13
+ @comment = comment
14
+ @location_in_comment = location_in_comment
15
+ end
16
+
17
+ # @return [String]
18
+ def current_line_comment
19
+ comment.split("\n")[location_in_comment.row - 1] || ''
20
+ end
21
+
22
+ # @return [Symbol]
23
+ def current_state
24
+ return :none unless inputting_line
25
+ inputting_line.current_state
26
+ end
27
+
28
+ # @return [String, nil]
29
+ def current_word
30
+ return nil unless inputting_line
31
+ inputting_line.current_token.to_s
32
+ end
33
+
34
+ # @return [Range, nil]
35
+ def current_range
36
+ return nil if !inputting_line || !inputting_line.current_range
37
+ start, last = inputting_line.current_range
38
+ Range.new(Location.new(row: location_in_comment.row, column: start), Location.new(row: location_in_comment.row, column: last))
39
+ end
40
+
41
+ # @return [true, false]
42
+ def at_sign?
43
+ inputting_line.at_sign?
44
+ end
45
+
46
+ private
47
+
48
+ # @return [CommentTokenizer::Sequence, nil]
49
+ def tokenize
50
+ return @tokenize if instance_variable_defined?(:@tokenized)
51
+ @tokenize = CommentTokenizer.new.parse(line_to_current_position)
52
+ rescue Parslet::ParseFailed
53
+ @tokenize = nil
54
+ end
55
+
56
+ # @return [String]
57
+ def line_to_current_position
58
+ current_line_comment.slice(0...location_in_comment.column)
59
+ end
60
+
61
+ # @return [InputtingLine, nil]
62
+ def inputting_line
63
+ return nil unless tokenize
64
+ @inputting_line ||= InputtingLine.new(tokenize, location_in_comment.column)
65
+ end
66
+
67
+ class InputtingLine
68
+ # @type CommentTokenizer::Sequence
69
+ attr_reader :token_sequence
70
+
71
+ # @type Integer
72
+ attr_reader :column
73
+
74
+ # @param token_sequence [CommentTokenizer::Sequence]
75
+ # @param column [Integer]
76
+ def initialize(token_sequence, column)
77
+ @token_sequence = token_sequence
78
+ @column = column
79
+ end
80
+
81
+ # @return [Parslet::Slice, nil]
82
+ def tag
83
+ token_sequence.tag
84
+ end
85
+
86
+ # @return [(Integer, Integer), nil]
87
+ def current_range
88
+ return nil unless current_token
89
+ [current_token.offset, current_token.offset + current_token.size]
90
+ end
91
+
92
+ # @return [Parslet::Slice, nil]
93
+ def current_token
94
+ @current_token ||= token_sequence.all_tokens.find { |token| token.offset <= column && column <= token.offset + token.size }
95
+ end
96
+
97
+ # @return [Symbol]
98
+ def current_state
99
+ @current_state ||= begin
100
+ if tag && %w(@type @!sig).include?(tag.to_s) && !on_tag?
101
+ :type_tag_type
102
+ elsif tag && token_sequence.parameter_tokens.empty?
103
+ :tag
104
+ elsif in_bracket?
105
+ :type
106
+ elsif at_parameter_name?
107
+ :param
108
+ else
109
+ :none
110
+ end
111
+ end
112
+ end
113
+
114
+ # @return [true, false]
115
+ def at_sign?
116
+ current_token &&
117
+ current_token.to_s.match?(/\A[{}.&\]\[\(\)<>]/) &&
118
+ column == current_token.offset + current_token.size
119
+ end
120
+
121
+ private
122
+
123
+ # @return [Boolean]
124
+ def on_tag?
125
+ tag && tag.offset <= column && column <= tag.offset + tag.size
126
+ end
127
+
128
+ # @return [Boolean]
129
+ def at_parameter_name?
130
+ case token_sequence.parameter_tokens.length
131
+ when 0
132
+ # TODO
133
+ false
134
+ when 1
135
+ tag && %w(@param).include?(tag.to_s)
136
+ else
137
+ false
138
+ end
139
+ end
140
+
141
+ # @return [Boolean]
142
+ def in_bracket?
143
+ token_sequence.parameter_tokens.reverse_each do |token|
144
+ return false if token.to_s == ']'
145
+ return true if token.to_s == '['
146
+ end
147
+ false
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,68 @@
1
+ module Yoda
2
+ module Parsing
3
+ module Query
4
+ # Provides helper methods to find the node whose comment include the current position (is the current comment).
5
+ class CurrentCommentingNodeQuery
6
+ attr_reader :ast, :comments, :location
7
+
8
+ # @param ast [::Parser::AST::Node]
9
+ # @param comments [Array<::Parser::Source::Comment>]
10
+ # @param location [Location] represents the current position.
11
+ def initialize(ast, comments, location)
12
+ fail ArgumentError, ast unless ast.is_a?(::Parser::AST::Node)
13
+ fail ArgumentError, comments unless comments.all? { |comment| comment.is_a?(::Parser::Source::Comment) }
14
+ fail ArgumentError, location unless location.is_a?(Location)
15
+ @ast = ast
16
+ @comments = comments
17
+ @location = location
18
+ end
19
+
20
+ # @return [Array<::Parser::Source::Comment>]
21
+ def current_commenting_node
22
+ @current_commenting_node ||= inverse_association[current_comment_query.current_comment_block]
23
+ end
24
+
25
+ # @return [NodeObjects::Namespace, nil]
26
+ def current_namespace
27
+ @current_namespace ||= namespace.calc_current_location_namespace(current_commenting_node_location)
28
+ end
29
+
30
+ # @return [NodeObjects::MethodDefition, nil]
31
+ def current_method_definition
32
+ @current_method_definition ||= namespace.calc_current_location_method(current_commenting_node_location)
33
+ end
34
+
35
+ private
36
+
37
+ def current_commenting_node_location
38
+ @current_commenting_node_location ||= Location.of_ast_location(current_commenting_node.location)
39
+ end
40
+
41
+ # @return [Namespace]
42
+ def namespace
43
+ @namespace ||= NodeObjects::Namespace.new(ast)
44
+ end
45
+
46
+ # @return [{::Parser::AST::Node => Array<::Parser::Source::Comment>}]
47
+ def association
48
+ @association ||= ::Parser::Source::Comment.associate(ast, comments)
49
+ end
50
+
51
+ # @return [{Array<::Parser::Source::Comment> => ::Parser::AST::Node}]
52
+ def inverse_association
53
+ @inverse_association ||= association.invert
54
+ end
55
+
56
+ # @return [{::Parser::Source::Map => Array<::Parser::Source::Comment>]
57
+ def location_association
58
+ @location_association ||= ::Parser::Source::Comment.associate_with_location(ast, comments)
59
+ end
60
+
61
+ # @return [CurrentCommentQuery]
62
+ def current_comment_query
63
+ @current_comment_query ||= CurrentCommentQuery.new(comments, location)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,51 @@
1
+ module Yoda
2
+ module Parsing
3
+ module Query
4
+ class CurrentLocationQuery
5
+ attr_reader :ast, :location
6
+
7
+ # @param ast [::Parser::AST::Node]
8
+ # @param location [Location]
9
+ def initialize(ast, location)
10
+ @ast = ast
11
+ @location = location
12
+ end
13
+
14
+ # @return [NodeObjects::Namespace, nil]
15
+ def current_namespace
16
+ @current_namespace ||= namespace.calc_current_location_namespace(location)
17
+ end
18
+
19
+ # @return [NodeObjects::MethodDefition, nil]
20
+ def current_method_definition
21
+ @current_method_definition ||= namespace.calc_current_location_method(location)
22
+ end
23
+
24
+ private
25
+
26
+ # @return [Namespace]
27
+ def namespace
28
+ @namespace ||= NodeObjects::Namespace.new(self.ast)
29
+ end
30
+
31
+ # @return [Array<::Parser::AST::Node>]
32
+ def nodes_to_current_location_from_root
33
+ @nodes_to_current_location ||= calc_nodes_to_current_location(ast, location)
34
+ end
35
+
36
+ # @param root_node [Array<::Parser::AST::Node>]
37
+ # @param current_location [Parser::Source::Map]
38
+ # @return [Array<::Parser::AST::Node>]
39
+ def calc_nodes_to_current_location(root_node, current_location)
40
+ nodes = []
41
+ node = root_node
42
+ while node && !node.children.empty?
43
+ nodes << node
44
+ node = node.children.find { |n| n.respond_to?(:location) && current_location.included?(n.location) }
45
+ end
46
+ nodes
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end