holistic-ruby 0.1.1 → 0.1.4
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/README.md +1 -1
- data/lib/holistic/extensions/events.rb +9 -1
- data/lib/holistic/extensions/ruby/stdlib.rb +27 -13
- data/lib/holistic/language_server/requests/text_document/completion.rb +9 -7
- data/lib/holistic/language_server/requests/text_document/did_close.rb +1 -3
- data/lib/holistic/ruby/autocompletion/suggest.rb +32 -2
- data/lib/holistic/ruby/parser/constant_resolution.rb +54 -3
- data/lib/holistic/ruby/parser/live_editing/process_file_changed.rb +6 -3
- data/lib/holistic/ruby/parser/nesting_syntax.rb +1 -0
- data/lib/holistic/ruby/parser/program_visitor.rb +40 -24
- data/lib/holistic/ruby/parser.rb +8 -0
- data/lib/holistic/ruby/scope/kind.rb +6 -5
- data/lib/holistic/ruby/scope/record.rb +10 -6
- data/lib/holistic/ruby/type_inference/solve.rb +15 -4
- data/lib/holistic/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: abe4144d1f581c6151784152792604f799c0140d62c28f445f377f6039c40457
|
|
4
|
+
data.tar.gz: 6593b92046a8087f75c171280ae66401ff0bb1eb0f6dba9fa496df127bb39ee8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eb1f43eaa7f78c334da3f8d8f2fc782bfa662b94f8a5a6b5a8a24ab271cae26d62703bd722860dbecf637d9aae5d4595d1424257406d9d349f0d90a95ab702d4
|
|
7
|
+
data.tar.gz: f42ed13efc65779f8ef175c7127d03cf68bebd5df990a1744d714100efe639cad104b55592507d4737ecfa4d48e75d6b69da194a033f056740a16fde8bf3d65d
|
data/README.md
CHANGED
|
@@ -32,4 +32,4 @@
|
|
|
32
32
|
|
|
33
33
|
## Why is it a toy language server?
|
|
34
34
|
|
|
35
|
-
I use `holistic-ruby` on a daily basis in a
|
|
35
|
+
I use `holistic-ruby` on a daily basis while working in a fairly large Ruby codebase. It seems stable and speedy. But... I built it for myself and I'm the only one using it :smile:
|
|
@@ -5,6 +5,14 @@ class Holistic::Extensions::Events
|
|
|
5
5
|
resolve_method_call_known_scope: {
|
|
6
6
|
params: [:reference, :referenced_scope, :method_call_clue],
|
|
7
7
|
output: ::Holistic::Ruby::Scope::Record
|
|
8
|
+
},
|
|
9
|
+
class_scope_registered: {
|
|
10
|
+
params: [:class_scope, :location],
|
|
11
|
+
output: nil
|
|
12
|
+
},
|
|
13
|
+
lambda_scope_registered: {
|
|
14
|
+
params: [:lambda_scope, :location],
|
|
15
|
+
output: nil
|
|
8
16
|
}
|
|
9
17
|
}.freeze
|
|
10
18
|
|
|
@@ -30,7 +38,7 @@ class Holistic::Extensions::Events
|
|
|
30
38
|
|
|
31
39
|
result = @listeners[event].lazy.filter_map { |callback| callback.call(params) }.first
|
|
32
40
|
|
|
33
|
-
raise UnexpectedOutput, result if result.present? && !result.is_a?(expected_output)
|
|
41
|
+
raise UnexpectedOutput, result if expected_output.present? && result.present? && !result.is_a?(expected_output)
|
|
34
42
|
|
|
35
43
|
result
|
|
36
44
|
end
|
|
@@ -16,28 +16,42 @@ module Holistic::Extensions::Ruby
|
|
|
16
16
|
nil
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
RegisterClassConstructor = ->(application, params) do
|
|
20
|
+
class_scope, location = params[:class_scope], params[:location]
|
|
21
|
+
|
|
22
|
+
has_overridden_new_method = class_scope.children.find { _1.class_method? && _1.name == "new" }
|
|
23
|
+
|
|
24
|
+
unless has_overridden_new_method
|
|
25
|
+
::Holistic::Ruby::Scope::Register.call(
|
|
26
|
+
repository: application.scopes,
|
|
27
|
+
parent: class_scope,
|
|
28
|
+
kind: ::Holistic::Ruby::Scope::Kind::CLASS_METHOD,
|
|
29
|
+
name: "new",
|
|
30
|
+
location:
|
|
31
|
+
)
|
|
32
|
+
end
|
|
25
33
|
end
|
|
26
34
|
|
|
27
|
-
LAMBDA_METHODS = ["call", "curry"]
|
|
35
|
+
LAMBDA_METHODS = ["call", "curry"].freeze
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
RegisterLambdaMethods = ->(application, params) do
|
|
38
|
+
lambda_scope, location = params[:lambda_scope], params[:location]
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
LAMBDA_METHODS.each do |method_name|
|
|
41
|
+
::Holistic::Ruby::Scope::Register.call(
|
|
42
|
+
repository: application.scopes,
|
|
43
|
+
parent: lambda_scope,
|
|
44
|
+
kind: ::Holistic::Ruby::Scope::Kind::CLASS_METHOD,
|
|
45
|
+
name: method_name,
|
|
46
|
+
location:
|
|
47
|
+
)
|
|
34
48
|
end
|
|
35
49
|
end
|
|
36
50
|
|
|
37
51
|
def register(application)
|
|
38
52
|
application.extensions.bind(:resolve_method_call_known_scope, &ResolveClassConstructor.curry[application])
|
|
39
|
-
application.extensions.bind(:
|
|
40
|
-
application.extensions.bind(:
|
|
53
|
+
application.extensions.bind(:class_scope_registered, &RegisterClassConstructor.curry[application])
|
|
54
|
+
application.extensions.bind(:lambda_scope_registered, &RegisterLambdaMethods.curry[application])
|
|
41
55
|
end
|
|
42
56
|
end
|
|
43
57
|
end
|
|
@@ -19,10 +19,11 @@ module Holistic::LanguageServer
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
code = document.expand_code(cursor)
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
|
|
24
23
|
return request.respond_with(nil) if code.blank?
|
|
25
24
|
|
|
25
|
+
scope = request.application.scopes.find_inner_most_scope_by_cursor(cursor) || request.application.root_scope
|
|
26
|
+
|
|
26
27
|
suggestions = ::Holistic::Ruby::Autocompletion::Suggest.call(code:, scope:)
|
|
27
28
|
|
|
28
29
|
respond_with_suggestions(request, suggestions)
|
|
@@ -40,11 +41,12 @@ module Holistic::LanguageServer
|
|
|
40
41
|
|
|
41
42
|
module CompletionKind
|
|
42
43
|
FROM_SCOPE_TO_COMPLETION = {
|
|
43
|
-
::Holistic::Ruby::Scope::Kind::CLASS
|
|
44
|
-
::Holistic::Ruby::Scope::Kind::LAMBDA
|
|
45
|
-
::Holistic::Ruby::Scope::Kind::
|
|
46
|
-
::Holistic::Ruby::Scope::Kind::
|
|
47
|
-
::Holistic::Ruby::Scope::Kind::
|
|
44
|
+
::Holistic::Ruby::Scope::Kind::CLASS => Protocol::COMPLETION_ITEM_KIND_CLASS,
|
|
45
|
+
::Holistic::Ruby::Scope::Kind::LAMBDA => Protocol::COMPLETION_ITEM_KIND_FUNCTION,
|
|
46
|
+
::Holistic::Ruby::Scope::Kind::CLASS_METHOD => Protocol::COMPLETION_ITEM_KIND_METHOD,
|
|
47
|
+
::Holistic::Ruby::Scope::Kind::INSTANCE_METHOD => Protocol::COMPLETION_ITEM_KIND_METHOD,
|
|
48
|
+
::Holistic::Ruby::Scope::Kind::MODULE => Protocol::COMPLETION_ITEM_KIND_MODULE,
|
|
49
|
+
::Holistic::Ruby::Scope::Kind::ROOT => Protocol::COMPLETION_ITEM_KIND_MODULE
|
|
48
50
|
}.freeze
|
|
49
51
|
|
|
50
52
|
DEFAULT = Protocol::COMPLETION_ITEM_KIND_MODULE
|
|
@@ -7,9 +7,7 @@ module Holistic::LanguageServer
|
|
|
7
7
|
def call(request)
|
|
8
8
|
path = Format::FileUri.extract_path(request.message.param("textDocument", "uri"))
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if unsaved_document.present?
|
|
10
|
+
request.application.unsaved_documents.find(path)&.then do |unsaved_document|
|
|
13
11
|
request.application.unsaved_documents.delete(path)
|
|
14
12
|
|
|
15
13
|
if unsaved_document.has_unsaved_changes?
|
|
@@ -13,12 +13,42 @@ module Holistic::Ruby::Autocompletion
|
|
|
13
13
|
lookup_scope = lookup_scope.parent until lookup_scope.root?
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
if code.include?(".")
|
|
17
|
+
suggest_methods_from_scope(code:, scope: lookup_scope)
|
|
18
|
+
else
|
|
19
|
+
suggest_namespaces_from_scope(code:, scope: lookup_scope)
|
|
20
|
+
end
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
private
|
|
20
24
|
|
|
21
|
-
NonMethods = ->(scope) { !scope
|
|
25
|
+
NonMethods = ->(scope) { !Methods[scope] }
|
|
26
|
+
Methods = ->(scope) { scope.instance_method? || scope.class_method? }
|
|
27
|
+
|
|
28
|
+
# Payment. <--
|
|
29
|
+
# Payment::Notifications. <--
|
|
30
|
+
# current_user.a
|
|
31
|
+
def suggest_methods_from_scope(code:, scope:)
|
|
32
|
+
suggestions = []
|
|
33
|
+
|
|
34
|
+
partial_namespaces = code.split(/(::|\.)/).compact_blank
|
|
35
|
+
method_to_autocomplete = partial_namespaces.pop.then { _1 == "." ? "" : _1 }
|
|
36
|
+
namespaces_to_resolve = partial_namespaces.reject { _1 == "::" || _1 == "." }
|
|
37
|
+
|
|
38
|
+
namespaces_to_resolve.each do |namespace_name|
|
|
39
|
+
scope = resolve_scope(name: namespace_name, from_scope: scope)
|
|
40
|
+
|
|
41
|
+
return suggestions if scope.nil?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
scope.children.filter(&:class_method?).each do |method_scope|
|
|
45
|
+
if method_scope.name.start_with?(method_to_autocomplete)
|
|
46
|
+
suggestions << Suggestion.new(code: method_scope.name, kind: method_scope.kind)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
suggestions
|
|
51
|
+
end
|
|
22
52
|
|
|
23
53
|
def suggest_namespaces_from_scope(code:, scope:)
|
|
24
54
|
suggestions = []
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
module Holistic::Ruby::Parser
|
|
4
4
|
class ConstantResolution
|
|
5
|
-
|
|
5
|
+
module MethodRegistrationMode
|
|
6
|
+
INSTANCE_METHODS = :instance_methods
|
|
7
|
+
CLASS_METHODS = :class_methods
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
attr_reader :scope_repository, :scope, :method_registration_mode
|
|
6
11
|
|
|
7
12
|
def initialize(scope_repository:, root_scope:)
|
|
8
13
|
@scope_repository = scope_repository
|
|
9
14
|
@scope = root_scope
|
|
10
15
|
@constant_resolution_possibilities = ["::"]
|
|
16
|
+
@method_registration_mode = MethodRegistrationMode::INSTANCE_METHODS
|
|
11
17
|
end
|
|
12
18
|
|
|
13
19
|
def current
|
|
@@ -28,12 +34,17 @@ module Holistic::Ruby::Parser
|
|
|
28
34
|
)
|
|
29
35
|
end
|
|
30
36
|
|
|
37
|
+
registered_module_scope = @scope
|
|
38
|
+
|
|
31
39
|
@constant_resolution_possibilities.unshift(@scope.fully_qualified_name)
|
|
32
40
|
|
|
33
41
|
block.call
|
|
34
42
|
|
|
35
|
-
|
|
43
|
+
change_method_registration_mode_to_instance_methods!
|
|
36
44
|
@constant_resolution_possibilities.shift
|
|
45
|
+
@scope = starting_scope
|
|
46
|
+
|
|
47
|
+
registered_module_scope
|
|
37
48
|
end
|
|
38
49
|
|
|
39
50
|
def register_child_class(nesting:, location:, &block)
|
|
@@ -50,12 +61,52 @@ module Holistic::Ruby::Parser
|
|
|
50
61
|
)
|
|
51
62
|
end
|
|
52
63
|
|
|
64
|
+
registered_class_scope = @scope
|
|
65
|
+
|
|
53
66
|
@constant_resolution_possibilities.unshift(@scope.fully_qualified_name)
|
|
54
67
|
|
|
55
68
|
block.call
|
|
56
69
|
|
|
57
|
-
|
|
70
|
+
change_method_registration_mode_to_instance_methods!
|
|
58
71
|
@constant_resolution_possibilities.shift
|
|
72
|
+
@scope = starting_scope
|
|
73
|
+
|
|
74
|
+
registered_class_scope
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def register_child_method(nesting:, location:, kind:, &block)
|
|
78
|
+
starting_scope = @scope
|
|
79
|
+
|
|
80
|
+
nesting.each do |name|
|
|
81
|
+
@scope =
|
|
82
|
+
::Holistic::Ruby::Scope::Register.call(
|
|
83
|
+
repository: @scope_repository,
|
|
84
|
+
parent: @scope,
|
|
85
|
+
kind:,
|
|
86
|
+
name:,
|
|
87
|
+
location:
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
registered_method_scope = @scope
|
|
92
|
+
|
|
93
|
+
block.call
|
|
94
|
+
|
|
95
|
+
@scope = starting_scope
|
|
96
|
+
|
|
97
|
+
registered_method_scope
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def method_registration_class_methods?
|
|
101
|
+
method_registration_mode == MethodRegistrationMode::CLASS_METHODS
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def change_method_registration_mode_to_class_methods!
|
|
105
|
+
@method_registration_mode = MethodRegistrationMode::CLASS_METHODS
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def change_method_registration_mode_to_instance_methods!
|
|
109
|
+
@method_registration_mode = MethodRegistrationMode::INSTANCE_METHODS
|
|
59
110
|
end
|
|
60
111
|
end
|
|
61
112
|
end
|
|
@@ -5,7 +5,10 @@ module Holistic::Ruby::Parser
|
|
|
5
5
|
extend self
|
|
6
6
|
|
|
7
7
|
def call(application:, file:)
|
|
8
|
-
|
|
8
|
+
# TODO: do not build the AST twice
|
|
9
|
+
return unless HasValidSyntax[file:]
|
|
10
|
+
|
|
11
|
+
references_to_recalculate = identify_references_to_recalculate(application:, file:)
|
|
9
12
|
|
|
10
13
|
unregister_scopes_in_file(application:, file:)
|
|
11
14
|
unregsiter_references_in_file(application:, file:)
|
|
@@ -17,9 +20,9 @@ module Holistic::Ruby::Parser
|
|
|
17
20
|
|
|
18
21
|
private
|
|
19
22
|
|
|
20
|
-
def
|
|
23
|
+
def identify_references_to_recalculate(application:, file:)
|
|
21
24
|
# we need to reject references declared in the same because they're already going to be
|
|
22
|
-
#
|
|
25
|
+
# reparsed. If we don't do that, we'll end up with duplicated reference records.
|
|
23
26
|
|
|
24
27
|
application.references
|
|
25
28
|
.list_references_to_scopes_in_file(scopes: application.scopes, file_path: file.path)
|
|
@@ -14,6 +14,7 @@ module Holistic::Ruby::Parser
|
|
|
14
14
|
when ::SyntaxTree::Const then nesting_syntax << node.value
|
|
15
15
|
when ::SyntaxTree::VCall then append.(node.child_nodes.first)
|
|
16
16
|
when ::SyntaxTree::Ident then nesting_syntax << node.value
|
|
17
|
+
when ::SyntaxTree::Kw then nesting_syntax << node.value
|
|
17
18
|
when ::SyntaxTree::IVar then nesting_syntax << node.value
|
|
18
19
|
when ::SyntaxTree::Period then nesting_syntax << "."
|
|
19
20
|
when ::SyntaxTree::Paren then append.(node.child_nodes[1]) # node.child_nodes[0] is ::SyntaxTree::LParen
|
|
@@ -34,32 +34,43 @@ module Holistic::Ruby::Parser
|
|
|
34
34
|
nesting = NestingSyntax.build(declaration_node)
|
|
35
35
|
location = build_scope_location(declaration_node:, body_node:)
|
|
36
36
|
|
|
37
|
-
@constant_resolution.register_child_class(nesting:, location:) do
|
|
37
|
+
class_scope = @constant_resolution.register_child_class(nesting:, location:) do
|
|
38
38
|
visit(body_node)
|
|
39
39
|
end
|
|
40
|
+
|
|
41
|
+
@application.extensions.dispatch(:class_scope_registered, { class_scope:, location: })
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def visit_command(node)
|
|
45
|
+
command_name_node, args_node = node.child_nodes
|
|
46
|
+
|
|
47
|
+
if command_name_node.value == "extend"
|
|
48
|
+
is_extending_self = args_node.child_nodes.size == 1 && NestingSyntax.build(args_node.child_nodes.first).to_s == "self"
|
|
49
|
+
|
|
50
|
+
@constant_resolution.change_method_registration_mode_to_class_methods! if is_extending_self
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
visit(args_node)
|
|
40
54
|
end
|
|
41
55
|
|
|
42
56
|
def visit_def(node)
|
|
43
57
|
instance_node, period_node, method_name_node, _params, body_node = node.child_nodes
|
|
44
58
|
|
|
45
|
-
|
|
46
|
-
if instance_node.present? && period_node.present?
|
|
47
|
-
instance_node.child_nodes.first.value + period_node.value + method_name_node.value
|
|
48
|
-
else
|
|
49
|
-
method_name_node.value
|
|
50
|
-
end
|
|
51
|
-
|
|
59
|
+
nesting = NestingSyntax.new(method_name_node.value)
|
|
52
60
|
location = build_scope_location(declaration_node: method_name_node, body_node:)
|
|
53
61
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
kind =
|
|
63
|
+
if instance_node.present? && instance_node.child_nodes.first.value == "self"
|
|
64
|
+
::Holistic::Ruby::Scope::Kind::CLASS_METHOD
|
|
65
|
+
elsif @constant_resolution.method_registration_class_methods?
|
|
66
|
+
::Holistic::Ruby::Scope::Kind::CLASS_METHOD
|
|
67
|
+
else
|
|
68
|
+
::Holistic::Ruby::Scope::Kind::INSTANCE_METHOD
|
|
69
|
+
end
|
|
61
70
|
|
|
62
|
-
|
|
71
|
+
@constant_resolution.register_child_method(nesting:, location:, kind:) do
|
|
72
|
+
visit(body_node)
|
|
73
|
+
end
|
|
63
74
|
end
|
|
64
75
|
|
|
65
76
|
def visit_vcall(node)
|
|
@@ -128,22 +139,27 @@ module Holistic::Ruby::Parser
|
|
|
128
139
|
nesting = NestingSyntax.build(assign_node)
|
|
129
140
|
location = build_scope_location(declaration_node: assign_node, body_node: block_node)
|
|
130
141
|
|
|
131
|
-
@constant_resolution.register_child_class(nesting:, location:) do
|
|
142
|
+
class_scope = @constant_resolution.register_child_class(nesting:, location:) do
|
|
132
143
|
visit(block_node)
|
|
133
144
|
end
|
|
134
145
|
|
|
146
|
+
@application.extensions.dispatch(:class_scope_registered, { class_scope:, location: })
|
|
147
|
+
|
|
135
148
|
return
|
|
136
149
|
end
|
|
137
150
|
|
|
138
151
|
location = build_scope_location(declaration_node: assign_node, body_node:)
|
|
139
152
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
lambda_scope =
|
|
154
|
+
::Holistic::Ruby::Scope::Register.call(
|
|
155
|
+
repository: @application.scopes,
|
|
156
|
+
parent: @constant_resolution.scope,
|
|
157
|
+
kind: ::Holistic::Ruby::Scope::Kind::LAMBDA,
|
|
158
|
+
name: assign_node.child_nodes.first.value,
|
|
159
|
+
location:
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
@application.extensions.dispatch(:lambda_scope_registered, { lambda_scope:, location: })
|
|
147
163
|
|
|
148
164
|
visit(body_node)
|
|
149
165
|
end
|
data/lib/holistic/ruby/parser.rb
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Holistic::Ruby::Parser
|
|
4
|
+
HasValidSyntax = ->(file:) do
|
|
5
|
+
::SyntaxTree.parse(file.read)
|
|
6
|
+
|
|
7
|
+
true
|
|
8
|
+
rescue ::SyntaxTree::Parser::ParseError
|
|
9
|
+
false
|
|
10
|
+
end
|
|
11
|
+
|
|
4
12
|
ParseFile = ->(application:, file:) do
|
|
5
13
|
program = ::SyntaxTree.parse(file.read)
|
|
6
14
|
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module Holistic::Ruby::Scope
|
|
4
4
|
module Kind
|
|
5
|
-
ROOT
|
|
6
|
-
MODULE
|
|
7
|
-
CLASS
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
ROOT = :root
|
|
6
|
+
MODULE = :module
|
|
7
|
+
CLASS = :class
|
|
8
|
+
INSTANCE_METHOD = :instance_method
|
|
9
|
+
CLASS_METHOD = :class_method
|
|
10
|
+
LAMBDA = :lambda
|
|
10
11
|
end
|
|
11
12
|
end
|
|
@@ -16,10 +16,10 @@ module Holistic::Ruby::Scope
|
|
|
16
16
|
return "" if root?
|
|
17
17
|
|
|
18
18
|
separator =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
case kind
|
|
20
|
+
when Kind::INSTANCE_METHOD then "#"
|
|
21
|
+
when Kind::CLASS_METHOD then "."
|
|
22
|
+
else "::"
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
"#{parent.fully_qualified_name}#{separator}#{name}"
|
|
@@ -41,8 +41,12 @@ module Holistic::Ruby::Scope
|
|
|
41
41
|
kind == Kind::MODULE
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def
|
|
45
|
-
kind == Kind::
|
|
44
|
+
def instance_method?
|
|
45
|
+
kind == Kind::INSTANCE_METHOD
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def class_method?
|
|
49
|
+
kind == Kind::CLASS_METHOD
|
|
46
50
|
end
|
|
47
51
|
|
|
48
52
|
def descendant?(other)
|
|
@@ -37,7 +37,12 @@ module Holistic::Ruby::TypeInference
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
SolveMethodCallInCurrentScope = ->(application:, reference:, method_call_clue:) do
|
|
40
|
-
referenced_method =
|
|
40
|
+
referenced_method =
|
|
41
|
+
if reference.scope.class_method?
|
|
42
|
+
resolve_class_method(application:, scope: reference.scope.parent, method_name: method_call_clue.method_name)
|
|
43
|
+
elsif reference.scope.instance_method? && reference.scope.parent.present?
|
|
44
|
+
resolve_instance_method(application:, scope: reference.scope.parent, method_name: method_call_clue.method_name)
|
|
45
|
+
end
|
|
41
46
|
|
|
42
47
|
return if referenced_method.nil?
|
|
43
48
|
|
|
@@ -53,8 +58,8 @@ module Holistic::Ruby::TypeInference
|
|
|
53
58
|
|
|
54
59
|
return if referenced_scope.nil?
|
|
55
60
|
|
|
56
|
-
referenced_method =
|
|
57
|
-
referenced_method ||= application
|
|
61
|
+
referenced_method = application.extensions.dispatch(:resolve_method_call_known_scope, { reference:, referenced_scope:, method_call_clue: })
|
|
62
|
+
referenced_method ||= resolve_class_method(application:, scope: referenced_scope, method_name: method_call_clue.method_name)
|
|
58
63
|
|
|
59
64
|
Conclusion.done(referenced_method.fully_qualified_name) if referenced_method.present?
|
|
60
65
|
end
|
|
@@ -101,10 +106,16 @@ module Holistic::Ruby::TypeInference
|
|
|
101
106
|
nil
|
|
102
107
|
end
|
|
103
108
|
|
|
104
|
-
def
|
|
109
|
+
def resolve_instance_method(application:, scope:, method_name:)
|
|
105
110
|
method_fully_qualified_name = "#{scope.fully_qualified_name}##{method_name}"
|
|
106
111
|
|
|
107
112
|
application.scopes.find_by_fully_qualified_name(method_fully_qualified_name)
|
|
108
113
|
end
|
|
114
|
+
|
|
115
|
+
def resolve_class_method(application:, scope:, method_name:)
|
|
116
|
+
method_fully_qualified_name = "#{scope.fully_qualified_name}.#{method_name}"
|
|
117
|
+
|
|
118
|
+
application.scopes.find_by_fully_qualified_name(method_fully_qualified_name)
|
|
119
|
+
end
|
|
109
120
|
end
|
|
110
121
|
end
|
data/lib/holistic/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: holistic-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Luiz Vasconcellos
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-08-
|
|
11
|
+
date: 2023-08-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: syntax_tree
|