holistic-ruby 0.1.4 → 0.1.6
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/Gemfile.lock +1 -1
- data/lib/holistic/application.rb +12 -4
- data/lib/holistic/database/migrations.rb +20 -0
- data/lib/holistic/database/node.rb +29 -0
- data/lib/holistic/database/table.rb +53 -53
- data/lib/holistic/document/file/record.rb +10 -0
- data/lib/holistic/document/file/repository.rb +24 -0
- data/lib/holistic/document/file/store.rb +13 -0
- data/lib/holistic/document/location.rb +4 -6
- data/lib/holistic/document/unsaved/record.rb +0 -4
- data/lib/holistic/extensions/ruby/stdlib.rb +6 -6
- data/lib/holistic/language_server/requests/lifecycle/initialize.rb +5 -10
- data/lib/holistic/language_server/requests/text_document/completion.rb +5 -4
- data/lib/holistic/language_server/requests/text_document/did_close.rb +5 -9
- data/lib/holistic/language_server/requests/text_document/did_open.rb +1 -0
- data/lib/holistic/language_server/requests/text_document/did_save.rb +5 -9
- data/lib/holistic/language_server/requests/text_document/find_references.rb +7 -4
- data/lib/holistic/language_server/requests/text_document/go_to_definition.rb +3 -2
- data/lib/holistic/ruby/autocompletion/suggest.rb +40 -20
- data/lib/holistic/ruby/parser/constant_resolution.rb +8 -8
- data/lib/holistic/ruby/parser/live_editing/process_file_changed.rb +21 -21
- data/lib/holistic/ruby/parser/program_visitor.rb +21 -24
- data/lib/holistic/ruby/parser.rb +8 -11
- data/lib/holistic/ruby/reference/delete.rb +18 -0
- data/lib/holistic/ruby/reference/find_referenced_scope.rb +2 -2
- data/lib/holistic/ruby/reference/record.rb +7 -8
- data/lib/holistic/ruby/reference/repository.rb +19 -41
- data/lib/holistic/ruby/reference/store.rb +18 -0
- data/lib/holistic/ruby/scope/delete.rb +29 -0
- data/lib/holistic/ruby/scope/lexical.rb +11 -0
- data/lib/holistic/ruby/scope/list_references.rb +2 -2
- data/lib/holistic/ruby/scope/location.rb +9 -9
- data/lib/holistic/ruby/scope/outline.rb +8 -8
- data/lib/holistic/ruby/scope/record.rb +15 -51
- data/lib/holistic/ruby/scope/repository.rb +24 -25
- data/lib/holistic/ruby/scope/store.rb +45 -0
- data/lib/holistic/ruby/type_inference/processing_queue.rb +19 -0
- data/lib/holistic/ruby/type_inference/solve.rb +16 -25
- data/lib/holistic/ruby/type_inference/solve_pending_references.rb +3 -1
- data/lib/holistic/version.rb +1 -1
- metadata +13 -9
- data/lib/holistic/document/file.rb +0 -36
- data/lib/holistic/ruby/parser/table_of_contents.rb +0 -17
- data/lib/holistic/ruby/reference/register.rb +0 -15
- data/lib/holistic/ruby/reference/unregister.rb +0 -11
- data/lib/holistic/ruby/scope/register.rb +0 -31
- data/lib/holistic/ruby/scope/unregister.rb +0 -27
- data/lib/holistic/ruby/type_inference/conclusion.rb +0 -20
@@ -2,48 +2,47 @@
|
|
2
2
|
|
3
3
|
module Holistic::Ruby::Scope
|
4
4
|
class Repository
|
5
|
-
attr_reader :
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
5
|
+
attr_reader :database, :root
|
6
|
+
|
7
|
+
def initialize(database:)
|
8
|
+
@root = database.store(
|
9
|
+
"root_scope",
|
10
|
+
Record.new("root_scope", {
|
11
|
+
fully_qualified_name: "::",
|
12
|
+
name: "::",
|
13
|
+
kind: Kind::ROOT
|
14
|
+
})
|
15
|
+
)
|
16
|
+
|
17
|
+
@database = database
|
17
18
|
end
|
18
19
|
|
19
|
-
def
|
20
|
-
|
20
|
+
def find(fully_qualified_name)
|
21
|
+
database.find(fully_qualified_name)
|
21
22
|
end
|
22
23
|
|
23
24
|
def find_by_cursor(cursor)
|
24
|
-
|
25
|
-
|
25
|
+
database.find(cursor.file_path)&.then do |file|
|
26
|
+
file.defines_scopes.find do |scope|
|
27
|
+
scope.locations.any? { _1.declaration.contains?(cursor) }
|
28
|
+
end
|
26
29
|
end
|
27
|
-
|
28
|
-
nil
|
29
30
|
end
|
30
31
|
|
31
32
|
def find_inner_most_scope_by_cursor(cursor)
|
32
|
-
|
33
|
+
file = database.find(cursor.file_path)
|
33
34
|
|
34
|
-
|
35
|
+
return nil if file.nil?
|
36
|
+
|
37
|
+
matching_scopes = file.defines_scopes.filter do |scope|
|
35
38
|
scope.locations.any? { _1.body.contains?(cursor) }
|
36
39
|
end
|
37
40
|
|
38
41
|
matching_scopes.last
|
39
42
|
end
|
40
43
|
|
41
|
-
def delete_by_fully_qualified_name(fully_qualified_name)
|
42
|
-
table.delete(fully_qualified_name)
|
43
|
-
end
|
44
|
-
|
45
44
|
def list_scopes_in_file(file_path)
|
46
|
-
|
45
|
+
database.find(file_path)&.defines_scopes || []
|
47
46
|
end
|
48
47
|
end
|
49
48
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Holistic::Ruby::Scope
|
4
|
+
module Store
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def call(database:, parent:, kind:, name:, location:)
|
8
|
+
fully_qualified_name = build_fully_qualified_name(parent:, kind:, name:)
|
9
|
+
|
10
|
+
child_scope = database.find(fully_qualified_name)
|
11
|
+
|
12
|
+
if child_scope.nil?
|
13
|
+
record = Record.new(fully_qualified_name, { fully_qualified_name:, name:, kind:, locations: Location::Collection.new(name) })
|
14
|
+
|
15
|
+
child_scope = database.store(fully_qualified_name, record)
|
16
|
+
end
|
17
|
+
|
18
|
+
child_scope.locations << location
|
19
|
+
|
20
|
+
database.connect(source: parent, target: child_scope, name: :children, inverse_of: :parent)
|
21
|
+
database.connect(source: location.declaration.file, target: child_scope, name: :defines_scopes, inverse_of: :scope_defined_in_file)
|
22
|
+
|
23
|
+
child_scope
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def build_fully_qualified_name(parent:, kind:, name:)
|
29
|
+
parent_fully_qualified_name =
|
30
|
+
case parent.kind
|
31
|
+
when Kind::ROOT then ""
|
32
|
+
else parent.fully_qualified_name
|
33
|
+
end
|
34
|
+
|
35
|
+
separator =
|
36
|
+
case kind
|
37
|
+
when Kind::INSTANCE_METHOD then "#"
|
38
|
+
when Kind::CLASS_METHOD then "."
|
39
|
+
else "::"
|
40
|
+
end
|
41
|
+
|
42
|
+
"#{parent_fully_qualified_name}#{separator}#{name}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Holistic::Ruby::TypeInference::ProcessingQueue
|
4
|
+
def initialize
|
5
|
+
@queue = ::Queue.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def push(reference)
|
9
|
+
@queue.push(reference)
|
10
|
+
end
|
11
|
+
|
12
|
+
def pop
|
13
|
+
@queue.pop(true)
|
14
|
+
end
|
15
|
+
|
16
|
+
def empty?
|
17
|
+
@queue.empty?
|
18
|
+
end
|
19
|
+
end
|
@@ -5,12 +5,13 @@ module Holistic::Ruby::TypeInference
|
|
5
5
|
extend self
|
6
6
|
|
7
7
|
def call(application:, reference:)
|
8
|
-
|
8
|
+
referenced_scope =
|
9
9
|
solve_scope_reference(application:, reference:) ||
|
10
|
-
solve_method_call(application:, reference:)
|
11
|
-
Conclusion.unresolved
|
10
|
+
solve_method_call(application:, reference:)
|
12
11
|
|
13
|
-
|
12
|
+
if referenced_scope
|
13
|
+
application.database.connect(source: reference, target: referenced_scope, name: :referenced_scope, inverse_of: :referenced_by)
|
14
|
+
end
|
14
15
|
end
|
15
16
|
|
16
17
|
private
|
@@ -23,30 +24,21 @@ module Holistic::Ruby::TypeInference
|
|
23
24
|
|
24
25
|
scope_reference_clue = reference.clues.first
|
25
26
|
|
26
|
-
|
27
|
+
resolve_scope(
|
27
28
|
application:,
|
28
29
|
nesting: scope_reference_clue.nesting,
|
29
30
|
resolution_possibilities: scope_reference_clue.resolution_possibilities
|
30
31
|
)
|
31
|
-
|
32
|
-
if referenced_scope.present?
|
33
|
-
return Conclusion.done(referenced_scope.fully_qualified_name)
|
34
|
-
end
|
35
|
-
|
36
|
-
nil
|
37
32
|
end
|
38
33
|
|
39
34
|
SolveMethodCallInCurrentScope = ->(application:, reference:, method_call_clue:) do
|
40
|
-
|
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
|
35
|
+
scope = reference.located_in_scope
|
46
36
|
|
47
|
-
|
48
|
-
|
49
|
-
|
37
|
+
if scope.class_method?
|
38
|
+
resolve_class_method(application:, scope: scope.parent, method_name: method_call_clue.method_name)
|
39
|
+
elsif scope.instance_method? && scope.parent.present?
|
40
|
+
resolve_instance_method(application:, scope: scope.parent, method_name: method_call_clue.method_name)
|
41
|
+
end
|
50
42
|
end
|
51
43
|
|
52
44
|
SolveMethodCallInSpecifiedScope = ->(application:, reference:, method_call_clue:) do
|
@@ -59,9 +51,8 @@ module Holistic::Ruby::TypeInference
|
|
59
51
|
return if referenced_scope.nil?
|
60
52
|
|
61
53
|
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)
|
63
54
|
|
64
|
-
|
55
|
+
referenced_method || resolve_class_method(application:, scope: referenced_scope, method_name: method_call_clue.method_name)
|
65
56
|
end
|
66
57
|
|
67
58
|
SolveMethodCallInLocalVariable = ->(application:, reference:, method_call_clue:) do
|
@@ -98,7 +89,7 @@ module Holistic::Ruby::TypeInference
|
|
98
89
|
"#{resolution_candidate}::#{nesting.to_s}"
|
99
90
|
end
|
100
91
|
|
101
|
-
scope = application.scopes.
|
92
|
+
scope = application.scopes.find(fully_qualified_scope_name)
|
102
93
|
|
103
94
|
return scope if scope.present?
|
104
95
|
end
|
@@ -109,13 +100,13 @@ module Holistic::Ruby::TypeInference
|
|
109
100
|
def resolve_instance_method(application:, scope:, method_name:)
|
110
101
|
method_fully_qualified_name = "#{scope.fully_qualified_name}##{method_name}"
|
111
102
|
|
112
|
-
application.scopes.
|
103
|
+
application.scopes.find(method_fully_qualified_name)
|
113
104
|
end
|
114
105
|
|
115
106
|
def resolve_class_method(application:, scope:, method_name:)
|
116
107
|
method_fully_qualified_name = "#{scope.fully_qualified_name}.#{method_name}"
|
117
108
|
|
118
|
-
application.scopes.
|
109
|
+
application.scopes.find(method_fully_qualified_name)
|
119
110
|
end
|
120
111
|
end
|
121
112
|
end
|
@@ -5,7 +5,9 @@ module Holistic::Ruby::TypeInference
|
|
5
5
|
extend self
|
6
6
|
|
7
7
|
def call(application:)
|
8
|
-
application.
|
8
|
+
until application.type_inference_processing_queue.empty?
|
9
|
+
reference = application.type_inference_processing_queue.pop
|
10
|
+
|
9
11
|
Solve.call(application:, reference:)
|
10
12
|
end
|
11
13
|
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.6
|
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-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: syntax_tree
|
@@ -73,9 +73,13 @@ files:
|
|
73
73
|
- lib/holistic.rb
|
74
74
|
- lib/holistic/application.rb
|
75
75
|
- lib/holistic/background_process.rb
|
76
|
+
- lib/holistic/database/migrations.rb
|
77
|
+
- lib/holistic/database/node.rb
|
76
78
|
- lib/holistic/database/table.rb
|
77
79
|
- lib/holistic/document/cursor.rb
|
78
|
-
- lib/holistic/document/file.rb
|
80
|
+
- lib/holistic/document/file/record.rb
|
81
|
+
- lib/holistic/document/file/repository.rb
|
82
|
+
- lib/holistic/document/file/store.rb
|
79
83
|
- lib/holistic/document/location.rb
|
80
84
|
- lib/holistic/document/unsaved/change.rb
|
81
85
|
- lib/holistic/document/unsaved/collection.rb
|
@@ -110,23 +114,23 @@ files:
|
|
110
114
|
- lib/holistic/ruby/parser/live_editing/process_file_changed.rb
|
111
115
|
- lib/holistic/ruby/parser/nesting_syntax.rb
|
112
116
|
- lib/holistic/ruby/parser/program_visitor.rb
|
113
|
-
- lib/holistic/ruby/
|
117
|
+
- lib/holistic/ruby/reference/delete.rb
|
114
118
|
- lib/holistic/ruby/reference/find_referenced_scope.rb
|
115
119
|
- lib/holistic/ruby/reference/record.rb
|
116
|
-
- lib/holistic/ruby/reference/register.rb
|
117
120
|
- lib/holistic/ruby/reference/repository.rb
|
118
|
-
- lib/holistic/ruby/reference/
|
121
|
+
- lib/holistic/ruby/reference/store.rb
|
122
|
+
- lib/holistic/ruby/scope/delete.rb
|
119
123
|
- lib/holistic/ruby/scope/kind.rb
|
124
|
+
- lib/holistic/ruby/scope/lexical.rb
|
120
125
|
- lib/holistic/ruby/scope/list_references.rb
|
121
126
|
- lib/holistic/ruby/scope/location.rb
|
122
127
|
- lib/holistic/ruby/scope/outline.rb
|
123
128
|
- lib/holistic/ruby/scope/record.rb
|
124
|
-
- lib/holistic/ruby/scope/register.rb
|
125
129
|
- lib/holistic/ruby/scope/repository.rb
|
126
|
-
- lib/holistic/ruby/scope/
|
130
|
+
- lib/holistic/ruby/scope/store.rb
|
127
131
|
- lib/holistic/ruby/type_inference/clue/method_call.rb
|
128
132
|
- lib/holistic/ruby/type_inference/clue/scope_reference.rb
|
129
|
-
- lib/holistic/ruby/type_inference/
|
133
|
+
- lib/holistic/ruby/type_inference/processing_queue.rb
|
130
134
|
- lib/holistic/ruby/type_inference/solve.rb
|
131
135
|
- lib/holistic/ruby/type_inference/solve_pending_references.rb
|
132
136
|
- lib/holistic/version.rb
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Holistic::Document
|
4
|
-
class File
|
5
|
-
attr_reader :path
|
6
|
-
|
7
|
-
def initialize(path:)
|
8
|
-
@path = path
|
9
|
-
end
|
10
|
-
|
11
|
-
def read
|
12
|
-
::File.read(path)
|
13
|
-
end
|
14
|
-
|
15
|
-
def write(content)
|
16
|
-
::File.write(path, content)
|
17
|
-
end
|
18
|
-
|
19
|
-
class Fake
|
20
|
-
attr_reader :path
|
21
|
-
|
22
|
-
def initialize(path:, content:)
|
23
|
-
@path = path
|
24
|
-
@content = content
|
25
|
-
end
|
26
|
-
|
27
|
-
def read
|
28
|
-
@content
|
29
|
-
end
|
30
|
-
|
31
|
-
def write(content)
|
32
|
-
@content = content
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Holistic::Ruby::Parser
|
4
|
-
# TODO: move to an attibute of the scope
|
5
|
-
class TableOfContents
|
6
|
-
attr_reader :records
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
@records = Hash.new { |hash, key| hash[key] = {} }
|
10
|
-
end
|
11
|
-
|
12
|
-
def register(scope:, name:, clue:)
|
13
|
-
@records[scope.fully_qualified_name][name] ||= []
|
14
|
-
@records[scope.fully_qualified_name][name] << clue
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Holistic::Ruby::Reference
|
4
|
-
module Register
|
5
|
-
extend self
|
6
|
-
|
7
|
-
def call(repository:, scope:, clues:, location:)
|
8
|
-
conclusion = ::Holistic::Ruby::TypeInference::Conclusion.pending
|
9
|
-
|
10
|
-
reference = ::Holistic::Ruby::Reference::Record.new(scope:, clues:, location:, conclusion:)
|
11
|
-
|
12
|
-
repository.register_reference(reference)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Holistic::Ruby::Scope
|
4
|
-
module Register
|
5
|
-
extend self
|
6
|
-
|
7
|
-
def call(repository:, parent:, kind:, name:, location:)
|
8
|
-
child_scope = append_location_to_existing_scope(scope: parent, name:, location:) || add_new_scope(parent:, kind:, name:, location:)
|
9
|
-
|
10
|
-
repository.register_scope(child_scope)
|
11
|
-
|
12
|
-
child_scope
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def append_location_to_existing_scope(scope:, name:, location:)
|
18
|
-
child_scope = scope.children.find { _1.name == name }
|
19
|
-
|
20
|
-
return if child_scope.nil?
|
21
|
-
|
22
|
-
child_scope.tap { _1.locations << location }
|
23
|
-
end
|
24
|
-
|
25
|
-
def add_new_scope(parent:, kind:, name:, location:)
|
26
|
-
child_scope = Record.new(kind:, name:, parent:, location:)
|
27
|
-
|
28
|
-
child_scope.tap { parent.children << _1 }
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Holistic::Ruby::Scope
|
4
|
-
module Unregister
|
5
|
-
extend self
|
6
|
-
|
7
|
-
def call(repository:, fully_qualified_name:, file_path:)
|
8
|
-
scope = repository.find_by_fully_qualified_name(fully_qualified_name)
|
9
|
-
|
10
|
-
return :scope_not_found if scope.nil?
|
11
|
-
|
12
|
-
updated_locations = scope.locations.reject! { |scope_location| scope_location.declaration.file_path == file_path }
|
13
|
-
|
14
|
-
return :scope_not_defined_in_speciefied_file if updated_locations.nil?
|
15
|
-
|
16
|
-
if updated_locations.empty?
|
17
|
-
scope.parent.children.delete(scope)
|
18
|
-
|
19
|
-
repository.delete_by_fully_qualified_name(fully_qualified_name)
|
20
|
-
else
|
21
|
-
repository.register_scope(scope)
|
22
|
-
end
|
23
|
-
|
24
|
-
:definition_unregistered
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Holistic::Ruby::TypeInference
|
4
|
-
STATUS_PENDING = :pending
|
5
|
-
STATUS_DONE = :done
|
6
|
-
|
7
|
-
Conclusion = ::Data.define(:status, :dependency_identifier) do
|
8
|
-
def self.pending
|
9
|
-
new(status: STATUS_PENDING, dependency_identifier: nil)
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.unresolved
|
13
|
-
new(status: STATUS_DONE, dependency_identifier: nil)
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.done(dependency_identifier)
|
17
|
-
new(status: STATUS_DONE, dependency_identifier:)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|