yoda-language-server 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,72 @@
|
|
1
|
+
module Yoda
|
2
|
+
module Model
|
3
|
+
module Values
|
4
|
+
class ModuleValue < Base
|
5
|
+
attr_reader :registry, :namespace_object
|
6
|
+
|
7
|
+
# @param registry [Registry]
|
8
|
+
# @param namespace_object [::YARD::CodeObjects::NamespaceObject, ::YARD::CodeObjects::Proxy]
|
9
|
+
def initialize(registry, namespace_object)
|
10
|
+
fail ArgumentError, registry unless registry.is_a?(Registry)
|
11
|
+
fail ArgumentError, namespace_object unless namespace_object.is_a?(::YARD::CodeObjects::NamespaceObject) || namespace_object.is_a?(::YARD::CodeObjects::Proxy)
|
12
|
+
@registry = registry
|
13
|
+
@namespace_object = namespace_object
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Array<Functions::Base>]
|
17
|
+
def methods(visibility: nil)
|
18
|
+
return [] if namespace_object.type == :proxy
|
19
|
+
@methods ||= begin
|
20
|
+
opts = { scope: :class, visibility: visibility }.compact
|
21
|
+
class_methods = namespace_object.meths(opts).map { |meth| Functions::Method.new(meth) } + constructors
|
22
|
+
class_method_names = Set.new(class_methods.map(&:name))
|
23
|
+
parent_meths = parent_methods(visibility: visibility).reject { |m| class_method_names.include?(m.name) }
|
24
|
+
class_methods + parent_meths
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [String]
|
29
|
+
def path
|
30
|
+
"#{namespace.path}.#{namespace.type == :class ? 'class' : 'module'}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def namespace
|
34
|
+
namespace_object
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param [String]
|
38
|
+
def docstring
|
39
|
+
namespace.docstring
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Array<[String, Integer]>]
|
43
|
+
def defined_files
|
44
|
+
namespace.files
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# @return [Array<Functions::Constructor>]
|
50
|
+
def constructors
|
51
|
+
[] unless namespace_object.type == :class
|
52
|
+
[] if namespace.child(name: :new, scope: :class)
|
53
|
+
[namespace.child(name: :initialize, scope: :instance)].map do |method_object|
|
54
|
+
Functions::Constructor.new(method_object)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [Array<Functions::Base>]
|
59
|
+
def parent_methods(visibility: nil)
|
60
|
+
case namespace_object.type
|
61
|
+
when :class
|
62
|
+
InstanceValue.new(registry, registry.find_or_proxy('::Class')).methods(visibility: visibility)
|
63
|
+
when :module
|
64
|
+
InstanceValue.new(registry, registry.find_or_proxy('::Module')).methods(visibility: visibility)
|
65
|
+
else
|
66
|
+
[]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/yoda/parsing.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Yoda
|
2
|
+
module Parsing
|
3
|
+
require 'yoda/parsing/ast_traversable'
|
4
|
+
require 'yoda/parsing/comment_tokenizer'
|
5
|
+
require 'yoda/parsing/parser'
|
6
|
+
require 'yoda/parsing/source_analyzer'
|
7
|
+
require 'yoda/parsing/node_objects'
|
8
|
+
require 'yoda/parsing/location'
|
9
|
+
require 'yoda/parsing/scopes'
|
10
|
+
require 'yoda/parsing/source_cutter'
|
11
|
+
require 'yoda/parsing/range'
|
12
|
+
require 'yoda/parsing/query'
|
13
|
+
require 'yoda/parsing/type_parser'
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Yoda
|
2
|
+
module Parsing
|
3
|
+
module AstTraversable
|
4
|
+
# @param root_node [Array<::Parser::AST::Node>]
|
5
|
+
# @param current_location [Parser::Source::Map]
|
6
|
+
# @return [Array<::Parser::AST::Node>]
|
7
|
+
def calc_nodes_to_current_location(root_node, current_location)
|
8
|
+
nodes = [root_node]
|
9
|
+
node = root_node
|
10
|
+
while node && !node.children.empty?
|
11
|
+
node = node.children.find { |n| n.respond_to?(:location) && current_location.included?(n.location) }
|
12
|
+
nodes << node if node && node.is_a?(::Parser::AST::Node)
|
13
|
+
end
|
14
|
+
nodes
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
module Yoda
|
4
|
+
module Parsing
|
5
|
+
class CommentTokenizer
|
6
|
+
# @return [Sequence]
|
7
|
+
def parse(str)
|
8
|
+
Generator.new.apply(Tokenizer.new.parse(str))
|
9
|
+
end
|
10
|
+
|
11
|
+
class Tokenizer < Parslet::Parser
|
12
|
+
rule(:space) { match('\s').repeat(1) }
|
13
|
+
rule(:space?) { space.maybe }
|
14
|
+
|
15
|
+
rule(:comment_begin) { str('#') }
|
16
|
+
rule(:tag) { str('@') >> (str('!').maybe >> match('[a-zA-Z0-9_-]').repeat) }
|
17
|
+
|
18
|
+
rule(:name) { (sign.absent? >> match['[:graph:]']).repeat(1) }
|
19
|
+
rule(:sign) { match['\[\]<>,{}\(\)'] }
|
20
|
+
|
21
|
+
rule(:comment_token) { sign | name }
|
22
|
+
|
23
|
+
rule(:base) { comment_begin.maybe >> space? >> tag.maybe.as(:tag) >> space? >> (comment_token.as(:token) >> space?).repeat.as(:tokens) }
|
24
|
+
root :base
|
25
|
+
end
|
26
|
+
|
27
|
+
class Generator < Parslet::Transform
|
28
|
+
rule(token: simple(:token)) { token }
|
29
|
+
rule(tag: simple(:tag), tokens: sequence(:tokens)) { Sequence.new(tag: tag, tokens: tokens) }
|
30
|
+
rule(tag: simple(:tag), tokens: simple(:token)) { Sequence.new(tag: tag, tokens: [token]) }
|
31
|
+
end
|
32
|
+
|
33
|
+
class Sequence
|
34
|
+
# @type Parslet::Slice | nil
|
35
|
+
attr_reader :tag
|
36
|
+
|
37
|
+
# @param tag [Parslet::Slice, nil]
|
38
|
+
# @param tokens [Array<Parslet::Slice>]
|
39
|
+
def initialize(tag: nil, tokens: [])
|
40
|
+
fail ArgumentError, tag if tag && !tag.is_a?(Parslet::Slice)
|
41
|
+
fail ArgumentError, tokens unless tokens.all? { |token| token.is_a?(Parslet::Slice) }
|
42
|
+
|
43
|
+
@tag = tag
|
44
|
+
@tokens = tokens
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Array<Parslet::Slice>]
|
48
|
+
def all_tokens
|
49
|
+
@all_tokens ||= [@tag, *parameter_tokens].compact
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [Array<Parslet::Slice>]
|
53
|
+
def parameter_tokens
|
54
|
+
@tokens
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Yoda
|
2
|
+
module Parsing
|
3
|
+
class Location
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
# @todo Make this 0-indexed.
|
7
|
+
# @return [Integer] 0-indexed column number.
|
8
|
+
attr_reader :row
|
9
|
+
|
10
|
+
# @return [Integer] 0-indexed column number.
|
11
|
+
attr_reader :column
|
12
|
+
|
13
|
+
# @param row [Integer] 1-indexed row number.
|
14
|
+
# @param column [Integer] 0-indexed column number.
|
15
|
+
def initialize(row:, column:)
|
16
|
+
@row = row
|
17
|
+
@column = column
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param ast_location [Parser::Source::Map, Parser::Source::Range]
|
21
|
+
# @return [Location, nil]
|
22
|
+
def self.of_ast_location(ast_location)
|
23
|
+
return nil unless valid_location?(ast_location)
|
24
|
+
Location.new(row: ast_location.line, column: ast_location.column)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param line [Integer]
|
28
|
+
# @param character [Integer]
|
29
|
+
# @return [Location]
|
30
|
+
def self.of_language_server_protocol_position(line:, character:)
|
31
|
+
new(row: line + 1, column: character)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param location [Parser::Source::Range, Parser::Source::Map, Object]
|
35
|
+
def self.valid_location?(location)
|
36
|
+
return false if !location.is_a?(::Parser::Source::Range) && !location.is_a?(::Parser::Source::Map)
|
37
|
+
return false if location.is_a?(::Parser::Source::Map) && !location.expression
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param location [Parser::Source::Range, Parser::Source::Map]
|
42
|
+
def index_of(source)
|
43
|
+
(source.split("\n").slice(0, row - 1) || []).map(&:length).reduce(0, &:+) + column
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param location [Parser::Source::Range, Parser::Source::Map]
|
47
|
+
def included?(location)
|
48
|
+
return false unless self.class.valid_location?(location)
|
49
|
+
after_begin(location) && before_last(location)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param location [Parser::Source::Range, Parser::Source::Map]
|
53
|
+
def later_than?(location)
|
54
|
+
move(row: 0, column: -1).after_begin(location)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param location [Parser::Source::Range, Parser::Source::Map]
|
58
|
+
def after_begin(location)
|
59
|
+
return false unless self.class.valid_location?(location)
|
60
|
+
(location.line == row && location.column <= column) || location.line < row
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param location [Parser::Source::Range, Parser::Source::Map]
|
64
|
+
def before_last(location)
|
65
|
+
return false unless self.class.valid_location?(location)
|
66
|
+
(location.last_line == row && column <= location.last_column ) || row < location.last_line
|
67
|
+
end
|
68
|
+
|
69
|
+
# @param location [Parser::Source::Range, Parser::Source::Map]
|
70
|
+
# @return [{Symbol => Numerical}]
|
71
|
+
def offset_from_begin(location)
|
72
|
+
fail ArgumentError, location unless self.class.valid_location?(location)
|
73
|
+
{ line: row - location.line, column: column - location.column }
|
74
|
+
end
|
75
|
+
|
76
|
+
# @param row [Integer]
|
77
|
+
# @param column [Integer]
|
78
|
+
# @return [Location]
|
79
|
+
def move(row:, column:)
|
80
|
+
self.class.new(row: @row + row, column: @column + column)
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [{Symbol => Integer}]
|
84
|
+
def to_language_server_protocol_range
|
85
|
+
{ line: row - 1, character: column }
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_s
|
89
|
+
"(#{row}, #{column})"
|
90
|
+
end
|
91
|
+
|
92
|
+
# @param another [Location]
|
93
|
+
# @return [Integer]
|
94
|
+
def <=>(another)
|
95
|
+
return 0 if row == another.row && column == another.column
|
96
|
+
return 1 if (row == another.row && column >= another.column) || row > another.row
|
97
|
+
-1
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Yoda
|
2
|
+
module Parsing
|
3
|
+
module NodeObjects
|
4
|
+
require 'yoda/parsing/node_objects/const_node'
|
5
|
+
require 'yoda/parsing/node_objects/send_node'
|
6
|
+
require 'yoda/parsing/node_objects/method_definition'
|
7
|
+
require 'yoda/parsing/node_objects/namespace'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Yoda
|
2
|
+
module Parsing
|
3
|
+
module NodeObjects
|
4
|
+
class ConstNode
|
5
|
+
# @param node [::AST::Node]
|
6
|
+
attr_reader :node
|
7
|
+
|
8
|
+
# @param node [::AST::Node]
|
9
|
+
def initialize(node)
|
10
|
+
fail ArgumentError, node unless node.is_a?(::AST::Node) && node.type == :const
|
11
|
+
@node = node
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [ConstNode, nil]
|
15
|
+
def parent_const
|
16
|
+
node.children.first && node.children.first.type == :const ? ConstNode.new(node.children.first) : nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [true, false]
|
20
|
+
def absolute?
|
21
|
+
node.children.first == :cbase
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param location [Location]
|
25
|
+
# @return [true, false]
|
26
|
+
def just_after_separator?(location)
|
27
|
+
return false unless node.location.double_colon
|
28
|
+
location == Location.of_ast_location(node.location.double_colon.end)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Model::Path]
|
32
|
+
def to_path
|
33
|
+
Model::Path.new(to_s)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param base [String, Symbol, nil]
|
37
|
+
# @return [String]
|
38
|
+
def to_s(base = nil)
|
39
|
+
fail ArgumentError, base unless !base || base.is_a?(String) || base.is_a?(Symbol)
|
40
|
+
paths = []
|
41
|
+
looking_node = node
|
42
|
+
while true
|
43
|
+
return (base ? base.to_s + '::' : '') + paths.join('::') unless looking_node
|
44
|
+
return '::' + paths.join('::') if looking_node.type == :cbase
|
45
|
+
paths.unshift(looking_node.children[1])
|
46
|
+
looking_node = looking_node.children[0]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Yoda
|
2
|
+
module Parsing
|
3
|
+
module NodeObjects
|
4
|
+
class MethodDefinition
|
5
|
+
|
6
|
+
# @return [::Parser::AST::Node]
|
7
|
+
attr_reader :node
|
8
|
+
|
9
|
+
# @return [Namespace]
|
10
|
+
attr_reader :namespace
|
11
|
+
|
12
|
+
# @param node [::Parser::AST::Node]
|
13
|
+
# @param namespace [Namespace]
|
14
|
+
def initialize(node, namespace)
|
15
|
+
fail ArgumentError, node unless node.is_a?(::Parser::AST::Node)
|
16
|
+
fail ArgumentError, namespace unless namespace.is_a?(Namespace)
|
17
|
+
@node = node
|
18
|
+
@namespace = namespace
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Symbol]
|
22
|
+
def name
|
23
|
+
node.children[-3]
|
24
|
+
end
|
25
|
+
|
26
|
+
def arg_node
|
27
|
+
node.children[-2]
|
28
|
+
end
|
29
|
+
|
30
|
+
def body_node
|
31
|
+
node.children[-1]
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [String]
|
35
|
+
def full_name
|
36
|
+
"#{namespace.full_name}##{name}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [String]
|
40
|
+
def namespace_name
|
41
|
+
namespace.full_name
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Yoda
|
2
|
+
module Parsing
|
3
|
+
module NodeObjects
|
4
|
+
class Namespace
|
5
|
+
include AstTraversable
|
6
|
+
|
7
|
+
# @return [::Parser::AST::Node]
|
8
|
+
attr_reader :node
|
9
|
+
|
10
|
+
# @return [Namespace, nil]
|
11
|
+
attr_reader :parent
|
12
|
+
|
13
|
+
# @param node [::Parser::AST::Node]
|
14
|
+
# @param parent [Namespace, nil]
|
15
|
+
def initialize(node, parent = nil)
|
16
|
+
fail ArgumentError, node unless node.is_a?(::Parser::AST::Node)
|
17
|
+
fail ArgumentError, parent unless !parent || parent.is_a?(Namespace)
|
18
|
+
@node = node
|
19
|
+
@parent = parent
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [::Parser::AST::Node]
|
23
|
+
def body_node
|
24
|
+
return node if type == :root
|
25
|
+
return node.children[2] if type == :class
|
26
|
+
node.children[1]
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [::Parser::AST::Node, nil]
|
30
|
+
def const_node
|
31
|
+
%i(root sclass).include?(type) ? nil : node.children[0]
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Namespace]
|
35
|
+
def child_namespaces
|
36
|
+
@child_namespaces ||= child_nodes_of(body_node).select { |node| %i(module class sclass).include?(node.type) }.map { |node| self.class.new(node, self) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Wrappers::MethodNodeWrapper]
|
40
|
+
def child_methods
|
41
|
+
@child_methods ||= child_nodes_of(body_node).select { |node| %i(def defs).include?(node.type) }.map { |node| MethodDefinition.new(node, self) }
|
42
|
+
end
|
43
|
+
|
44
|
+
def type
|
45
|
+
@type ||= begin
|
46
|
+
return node.type if %i(module class sclass).include?(node.type)
|
47
|
+
:root
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [String]
|
52
|
+
def path
|
53
|
+
name = full_name
|
54
|
+
name == :root ? '' : name
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [true, false]
|
58
|
+
def root?
|
59
|
+
type == :root
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [String, Symbol]
|
63
|
+
def full_name
|
64
|
+
return :root if type == :root
|
65
|
+
parent_name = parent && !parent.root? ? parent.full_name : ''
|
66
|
+
const_node ? ConstNode.new(const_node).to_s(parent_name) : parent_name
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Array<String>]
|
70
|
+
def paths_from_root
|
71
|
+
if root?
|
72
|
+
[path]
|
73
|
+
else
|
74
|
+
parent ? parent.paths_from_root + [path] : ['', path]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param location [Location]
|
79
|
+
# @return [Namespace, nil]
|
80
|
+
def calc_current_location_namespace(location)
|
81
|
+
return nil unless location.included?(node.location)
|
82
|
+
including_child_namespace = child_namespaces.find { |namespace| location.included?(namespace.node.location) }
|
83
|
+
including_child_namespace ? including_child_namespace.calc_current_location_namespace(location) : self
|
84
|
+
end
|
85
|
+
|
86
|
+
# @param location [Location]
|
87
|
+
# @return [MethodNodeWrapper, nil]
|
88
|
+
def calc_current_location_method(location)
|
89
|
+
namespace = calc_current_location_namespace(location)
|
90
|
+
namespace && namespace.child_methods.find { |method| location.included?(method.node.location) }
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def child_nodes_of(node)
|
96
|
+
# @todo evaluate nodes in the namespace
|
97
|
+
return [] unless node
|
98
|
+
return node.children.map { |child| child_nodes_of(child) }.flatten.compact if node.type == :begin
|
99
|
+
[node]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|