syntax_tree 6.1.1 → 6.2.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 +4 -4
- data/.github/workflows/auto-merge.yml +1 -1
- data/.github/workflows/gh-pages.yml +2 -2
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +14 -1
- data/Gemfile.lock +16 -10
- data/README.md +2 -2
- data/lib/syntax_tree/database.rb +331 -0
- data/lib/syntax_tree/formatter.rb +1 -1
- data/lib/syntax_tree/node.rb +16 -32
- data/lib/syntax_tree/plugin/{disable_ternary.rb → disable_auto_ternary.rb} +1 -1
- data/lib/syntax_tree/reflection.rb +1 -1
- data/lib/syntax_tree/version.rb +1 -1
- data/lib/syntax_tree/with_scope.rb +1 -4
- data/lib/syntax_tree/yarv/assembler.rb +0 -1
- data/lib/syntax_tree/yarv/calldata.rb +20 -14
- data/lib/syntax_tree/yarv/instruction_sequence.rb +22 -3
- data/lib/syntax_tree/yarv/instructions.rb +18 -64
- data/lib/syntax_tree/yarv/legacy.rb +104 -0
- data/lib/syntax_tree.rb +1 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec83d4ecf5722316de95bb541d45d6213db7917ff6bb6e13fef397a65075bffa
|
4
|
+
data.tar.gz: 6171e1b60ab99eea54a761d5feec302554133b97fea8f95ed473a799e4005542
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5266b33544de3aae02d4d200f7239ed388a1e1bb045e93ed46c1d14d1fb618ee8592238ce21040cc05708c7947ed564dd3477d757849da080758c9399d883309
|
7
|
+
data.tar.gz: 398685af92d3b506382feba646f5d24e4151b6dc3d25e19a018b8fdfe5e0d301a53c54a0684a584c083951267e9205be46ab36420d075536bbe1a08d12de7b3d
|
@@ -25,7 +25,7 @@ jobs:
|
|
25
25
|
runs-on: ubuntu-latest
|
26
26
|
steps:
|
27
27
|
- name: Checkout
|
28
|
-
uses: actions/checkout@
|
28
|
+
uses: actions/checkout@v4
|
29
29
|
- name: Setup Pages
|
30
30
|
uses: actions/configure-pages@v3
|
31
31
|
- name: Set up Ruby
|
@@ -39,7 +39,7 @@ jobs:
|
|
39
39
|
rdoc --main README.md --op _site --exclude={Gemfile,Rakefile,"coverage/*","vendor/*","bin/*","test/*","tmp/*"}
|
40
40
|
cp -r doc _site/doc
|
41
41
|
- name: Upload artifact
|
42
|
-
uses: actions/upload-pages-artifact@
|
42
|
+
uses: actions/upload-pages-artifact@v2
|
43
43
|
|
44
44
|
# Deployment job
|
45
45
|
deploy:
|
data/.rubocop.yml
CHANGED
@@ -7,7 +7,7 @@ AllCops:
|
|
7
7
|
SuggestExtensions: false
|
8
8
|
TargetRubyVersion: 2.7
|
9
9
|
Exclude:
|
10
|
-
- '{.git,.github,bin,coverage,pkg,sorbet,spec,test/fixtures,vendor,tmp}/**/*'
|
10
|
+
- '{.git,.github,.ruby-lsp,bin,coverage,doc,pkg,sorbet,spec,test/fixtures,vendor,tmp}/**/*'
|
11
11
|
- test.rb
|
12
12
|
|
13
13
|
Gemspec/DevelopmentDependencies:
|
@@ -154,6 +154,9 @@ Style/ParallelAssignment:
|
|
154
154
|
Style/PerlBackrefs:
|
155
155
|
Enabled: false
|
156
156
|
|
157
|
+
Style/RedundantArrayConstructor:
|
158
|
+
Enabled: false
|
159
|
+
|
157
160
|
Style/SafeNavigation:
|
158
161
|
Enabled: false
|
159
162
|
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [6.2.0] - 2023-09-20
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- Fix `WithScope` for destructured post arguments.
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
|
17
|
+
- Always use `do`/`end` for multi-line lambdas.
|
18
|
+
|
9
19
|
## [6.1.1] - 2023-03-21
|
10
20
|
|
11
21
|
### Changed
|
@@ -603,7 +613,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
603
613
|
|
604
614
|
- 🎉 Initial release! 🎉
|
605
615
|
|
606
|
-
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v6.0
|
616
|
+
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v6.2.0...HEAD
|
617
|
+
[6.2.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v6.1.1...v6.2.0
|
618
|
+
[6.1.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v6.1.0...v6.1.1
|
619
|
+
[6.1.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v6.0.2...v6.1.0
|
607
620
|
[6.0.2]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v6.0.1...v6.0.2
|
608
621
|
[6.0.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v6.0.0...v6.0.1
|
609
622
|
[6.0.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v5.3.0...v6.0.0
|
data/Gemfile.lock
CHANGED
@@ -1,35 +1,41 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
syntax_tree (6.
|
4
|
+
syntax_tree (6.2.0)
|
5
5
|
prettier_print (>= 1.2.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
ast (2.4.2)
|
11
|
+
base64 (0.1.1)
|
11
12
|
docile (1.4.0)
|
12
13
|
json (2.6.3)
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
language_server-protocol (3.17.0.3)
|
15
|
+
minitest (5.20.0)
|
16
|
+
parallel (1.23.0)
|
17
|
+
parser (3.2.2.3)
|
16
18
|
ast (~> 2.4.1)
|
19
|
+
racc
|
17
20
|
prettier_print (1.2.1)
|
21
|
+
racc (1.7.1)
|
18
22
|
rainbow (3.1.1)
|
19
23
|
rake (13.0.6)
|
20
|
-
regexp_parser (2.
|
21
|
-
rexml (3.2.
|
22
|
-
rubocop (1.
|
24
|
+
regexp_parser (2.8.1)
|
25
|
+
rexml (3.2.6)
|
26
|
+
rubocop (1.56.3)
|
27
|
+
base64 (~> 0.1.1)
|
23
28
|
json (~> 2.3)
|
29
|
+
language_server-protocol (>= 3.17.0)
|
24
30
|
parallel (~> 1.10)
|
25
|
-
parser (>= 3.2.
|
31
|
+
parser (>= 3.2.2.3)
|
26
32
|
rainbow (>= 2.2.2, < 4.0)
|
27
33
|
regexp_parser (>= 1.8, < 3.0)
|
28
34
|
rexml (>= 3.2.5, < 4.0)
|
29
|
-
rubocop-ast (>= 1.
|
35
|
+
rubocop-ast (>= 1.28.1, < 2.0)
|
30
36
|
ruby-progressbar (~> 1.7)
|
31
37
|
unicode-display_width (>= 2.4.0, < 3.0)
|
32
|
-
rubocop-ast (1.
|
38
|
+
rubocop-ast (1.29.0)
|
33
39
|
parser (>= 3.2.1.0)
|
34
40
|
ruby-progressbar (1.13.0)
|
35
41
|
simplecov (0.22.0)
|
data/README.md
CHANGED
@@ -297,7 +297,7 @@ Note that the output of the `match` CLI command creates a valid pattern that can
|
|
297
297
|
|
298
298
|
### write
|
299
299
|
|
300
|
-
This command will format the listed files and write that formatted version back to the source files. Note that this overwrites the original content,
|
300
|
+
This command will format the listed files and write that formatted version back to the source files. Note that this overwrites the original content, so be sure to be using a version control system.
|
301
301
|
|
302
302
|
```sh
|
303
303
|
stree write path/to/file.rb
|
@@ -525,7 +525,7 @@ With visitors, you only define handlers for the nodes that you need. You can fin
|
|
525
525
|
* call `visit(child)` with each child that you want to visit
|
526
526
|
* call nothing if you're sure you don't want to descend further
|
527
527
|
|
528
|
-
There are a couple of visitors that ship with Syntax Tree that can be used as examples. They live in the [lib/syntax_tree
|
528
|
+
There are a couple of visitors that ship with Syntax Tree that can be used as examples. They live in the [lib/syntax_tree](lib/syntax_tree) directory.
|
529
529
|
|
530
530
|
### visit_method
|
531
531
|
|
@@ -0,0 +1,331 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SyntaxTree
|
4
|
+
# Provides the ability to index source files into a database, then query for
|
5
|
+
# the nodes.
|
6
|
+
module Database
|
7
|
+
class IndexingVisitor < SyntaxTree::FieldVisitor
|
8
|
+
attr_reader :database, :filepath, :node_id
|
9
|
+
|
10
|
+
def initialize(database, filepath)
|
11
|
+
@database = database
|
12
|
+
@filepath = filepath
|
13
|
+
@node_id = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def comments(node)
|
19
|
+
end
|
20
|
+
|
21
|
+
def field(name, value)
|
22
|
+
return unless value.is_a?(SyntaxTree::Node)
|
23
|
+
|
24
|
+
binds = [node_id, visit(value), name]
|
25
|
+
database.execute(<<~SQL, binds)
|
26
|
+
INSERT INTO edges (from_id, to_id, name)
|
27
|
+
VALUES (?, ?, ?)
|
28
|
+
SQL
|
29
|
+
end
|
30
|
+
|
31
|
+
def list(name, values)
|
32
|
+
values.each_with_index do |value, index|
|
33
|
+
binds = [node_id, visit(value), name, index]
|
34
|
+
database.execute(<<~SQL, binds)
|
35
|
+
INSERT INTO edges (from_id, to_id, name, list_index)
|
36
|
+
VALUES (?, ?, ?, ?)
|
37
|
+
SQL
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def node(node, _name)
|
42
|
+
previous = node_id
|
43
|
+
binds = [
|
44
|
+
node.class.name.delete_prefix("SyntaxTree::"),
|
45
|
+
filepath,
|
46
|
+
node.location.start_line,
|
47
|
+
node.location.start_column
|
48
|
+
]
|
49
|
+
|
50
|
+
database.execute(<<~SQL, binds)
|
51
|
+
INSERT INTO nodes (type, path, line, column)
|
52
|
+
VALUES (?, ?, ?, ?)
|
53
|
+
SQL
|
54
|
+
|
55
|
+
begin
|
56
|
+
@node_id = database.last_insert_row_id
|
57
|
+
yield
|
58
|
+
@node_id
|
59
|
+
ensure
|
60
|
+
@node_id = previous
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def text(name, value)
|
65
|
+
end
|
66
|
+
|
67
|
+
def pairs(name, values)
|
68
|
+
values.each_with_index do |(key, value), index|
|
69
|
+
binds = [node_id, visit(key), "#{name}[0]", index]
|
70
|
+
database.execute(<<~SQL, binds)
|
71
|
+
INSERT INTO edges (from_id, to_id, name, list_index)
|
72
|
+
VALUES (?, ?, ?, ?)
|
73
|
+
SQL
|
74
|
+
|
75
|
+
binds = [node_id, visit(value), "#{name}[1]", index]
|
76
|
+
database.execute(<<~SQL, binds)
|
77
|
+
INSERT INTO edges (from_id, to_id, name, list_index)
|
78
|
+
VALUES (?, ?, ?, ?)
|
79
|
+
SQL
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Query for a specific type of node.
|
85
|
+
class TypeQuery
|
86
|
+
attr_reader :type
|
87
|
+
|
88
|
+
def initialize(type)
|
89
|
+
@type = type
|
90
|
+
end
|
91
|
+
|
92
|
+
def each(database, &block)
|
93
|
+
sql = "SELECT * FROM nodes WHERE type = ?"
|
94
|
+
database.execute(sql, type).each(&block)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Query for the attributes of a node, optionally also filtering by type.
|
99
|
+
class AttrQuery
|
100
|
+
attr_reader :type, :attrs
|
101
|
+
|
102
|
+
def initialize(type, attrs)
|
103
|
+
@type = type
|
104
|
+
@attrs = attrs
|
105
|
+
end
|
106
|
+
|
107
|
+
def each(database, &block)
|
108
|
+
joins = []
|
109
|
+
binds = []
|
110
|
+
|
111
|
+
attrs.each do |name, query|
|
112
|
+
ids = query.each(database).map { |row| row[0] }
|
113
|
+
joins << <<~SQL
|
114
|
+
JOIN edges AS #{name}
|
115
|
+
ON #{name}.from_id = nodes.id
|
116
|
+
AND #{name}.name = ?
|
117
|
+
AND #{name}.to_id IN (#{(["?"] * ids.size).join(", ")})
|
118
|
+
SQL
|
119
|
+
|
120
|
+
binds.push(name).concat(ids)
|
121
|
+
end
|
122
|
+
|
123
|
+
sql = +"SELECT nodes.* FROM nodes, edges #{joins.join(" ")}"
|
124
|
+
|
125
|
+
if type
|
126
|
+
sql << " WHERE nodes.type = ?"
|
127
|
+
binds << type
|
128
|
+
end
|
129
|
+
|
130
|
+
sql << " GROUP BY nodes.id"
|
131
|
+
database.execute(sql, binds).each(&block)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Query for the results of either query.
|
136
|
+
class OrQuery
|
137
|
+
attr_reader :left, :right
|
138
|
+
|
139
|
+
def initialize(left, right)
|
140
|
+
@left = left
|
141
|
+
@right = right
|
142
|
+
end
|
143
|
+
|
144
|
+
def each(database, &block)
|
145
|
+
left.each(database, &block)
|
146
|
+
right.each(database, &block)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# A lazy query result.
|
151
|
+
class QueryResult
|
152
|
+
attr_reader :database, :query
|
153
|
+
|
154
|
+
def initialize(database, query)
|
155
|
+
@database = database
|
156
|
+
@query = query
|
157
|
+
end
|
158
|
+
|
159
|
+
def each(&block)
|
160
|
+
return enum_for(__method__) unless block_given?
|
161
|
+
query.each(database, &block)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# A pattern matching expression that will be compiled into a query.
|
166
|
+
class Pattern
|
167
|
+
class CompilationError < StandardError
|
168
|
+
end
|
169
|
+
|
170
|
+
attr_reader :query
|
171
|
+
|
172
|
+
def initialize(query)
|
173
|
+
@query = query
|
174
|
+
end
|
175
|
+
|
176
|
+
def compile
|
177
|
+
program =
|
178
|
+
begin
|
179
|
+
SyntaxTree.parse("case nil\nin #{query}\nend")
|
180
|
+
rescue Parser::ParseError
|
181
|
+
raise CompilationError, query
|
182
|
+
end
|
183
|
+
|
184
|
+
compile_node(program.statements.body.first.consequent.pattern)
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
|
189
|
+
def compile_error(node)
|
190
|
+
raise CompilationError, PP.pp(node, +"").chomp
|
191
|
+
end
|
192
|
+
|
193
|
+
# Shortcut for combining two queries into one that returns the results of
|
194
|
+
# if either query matches.
|
195
|
+
def combine_or(left, right)
|
196
|
+
OrQuery.new(left, right)
|
197
|
+
end
|
198
|
+
|
199
|
+
# in foo | bar
|
200
|
+
def compile_binary(node)
|
201
|
+
compile_error(node) if node.operator != :|
|
202
|
+
|
203
|
+
combine_or(compile_node(node.left), compile_node(node.right))
|
204
|
+
end
|
205
|
+
|
206
|
+
# in Ident
|
207
|
+
def compile_const(node)
|
208
|
+
value = node.value
|
209
|
+
|
210
|
+
if SyntaxTree.const_defined?(value, false)
|
211
|
+
clazz = SyntaxTree.const_get(value)
|
212
|
+
TypeQuery.new(clazz.name.delete_prefix("SyntaxTree::"))
|
213
|
+
else
|
214
|
+
compile_error(node)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# in SyntaxTree::Ident
|
219
|
+
def compile_const_path_ref(node)
|
220
|
+
parent = node.parent
|
221
|
+
if !parent.is_a?(SyntaxTree::VarRef) ||
|
222
|
+
!parent.value.is_a?(SyntaxTree::Const)
|
223
|
+
compile_error(node)
|
224
|
+
end
|
225
|
+
|
226
|
+
if parent.value.value == "SyntaxTree"
|
227
|
+
compile_node(node.constant)
|
228
|
+
else
|
229
|
+
compile_error(node)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# in Ident[value: String]
|
234
|
+
def compile_hshptn(node)
|
235
|
+
compile_error(node) unless node.keyword_rest.nil?
|
236
|
+
|
237
|
+
attrs = {}
|
238
|
+
node.keywords.each do |keyword, value|
|
239
|
+
compile_error(node) unless keyword.is_a?(SyntaxTree::Label)
|
240
|
+
attrs[keyword.value.chomp(":")] = compile_node(value)
|
241
|
+
end
|
242
|
+
|
243
|
+
type = node.constant ? compile_node(node.constant).type : nil
|
244
|
+
AttrQuery.new(type, attrs)
|
245
|
+
end
|
246
|
+
|
247
|
+
# in Foo
|
248
|
+
def compile_var_ref(node)
|
249
|
+
value = node.value
|
250
|
+
|
251
|
+
if value.is_a?(SyntaxTree::Const)
|
252
|
+
compile_node(value)
|
253
|
+
else
|
254
|
+
compile_error(node)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def compile_node(node)
|
259
|
+
case node
|
260
|
+
when SyntaxTree::Binary
|
261
|
+
compile_binary(node)
|
262
|
+
when SyntaxTree::Const
|
263
|
+
compile_const(node)
|
264
|
+
when SyntaxTree::ConstPathRef
|
265
|
+
compile_const_path_ref(node)
|
266
|
+
when SyntaxTree::HshPtn
|
267
|
+
compile_hshptn(node)
|
268
|
+
when SyntaxTree::VarRef
|
269
|
+
compile_var_ref(node)
|
270
|
+
else
|
271
|
+
compile_error(node)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
class Connection
|
277
|
+
attr_reader :raw_connection
|
278
|
+
|
279
|
+
def initialize(raw_connection)
|
280
|
+
@raw_connection = raw_connection
|
281
|
+
end
|
282
|
+
|
283
|
+
def execute(query, binds = [])
|
284
|
+
raw_connection.execute(query, binds)
|
285
|
+
end
|
286
|
+
|
287
|
+
def index_file(filepath)
|
288
|
+
program = SyntaxTree.parse(SyntaxTree.read(filepath))
|
289
|
+
program.accept(IndexingVisitor.new(self, filepath))
|
290
|
+
end
|
291
|
+
|
292
|
+
def last_insert_row_id
|
293
|
+
raw_connection.last_insert_row_id
|
294
|
+
end
|
295
|
+
|
296
|
+
def prepare
|
297
|
+
raw_connection.execute(<<~SQL)
|
298
|
+
CREATE TABLE nodes (
|
299
|
+
id integer primary key,
|
300
|
+
type varchar(20),
|
301
|
+
path varchar(200),
|
302
|
+
line integer,
|
303
|
+
column integer
|
304
|
+
);
|
305
|
+
SQL
|
306
|
+
|
307
|
+
raw_connection.execute(<<~SQL)
|
308
|
+
CREATE INDEX nodes_type ON nodes (type);
|
309
|
+
SQL
|
310
|
+
|
311
|
+
raw_connection.execute(<<~SQL)
|
312
|
+
CREATE TABLE edges (
|
313
|
+
id integer primary key,
|
314
|
+
from_id integer,
|
315
|
+
to_id integer,
|
316
|
+
name varchar(20),
|
317
|
+
list_index integer
|
318
|
+
);
|
319
|
+
SQL
|
320
|
+
|
321
|
+
raw_connection.execute(<<~SQL)
|
322
|
+
CREATE INDEX edges_name ON edges (name);
|
323
|
+
SQL
|
324
|
+
end
|
325
|
+
|
326
|
+
def search(query)
|
327
|
+
QueryResult.new(self, Pattern.new(query).compile)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
@@ -60,7 +60,7 @@ module SyntaxTree
|
|
60
60
|
# constant. That constant is responsible for determining the default
|
61
61
|
# disable ternary value. If it's defined, then we default to true.
|
62
62
|
# Otherwise we default to false.
|
63
|
-
defined?(
|
63
|
+
defined?(DISABLE_AUTO_TERNARY)
|
64
64
|
else
|
65
65
|
disable_auto_ternary
|
66
66
|
end
|
data/lib/syntax_tree/node.rb
CHANGED
@@ -1299,7 +1299,7 @@ module SyntaxTree
|
|
1299
1299
|
end
|
1300
1300
|
end
|
1301
1301
|
|
1302
|
-
# [nil | VarRef] the optional constant wrapper
|
1302
|
+
# [nil | VarRef | ConstPathRef] the optional constant wrapper
|
1303
1303
|
attr_reader :constant
|
1304
1304
|
|
1305
1305
|
# [Array[ Node ]] the regular positional arguments that this array
|
@@ -2849,7 +2849,10 @@ module SyntaxTree
|
|
2849
2849
|
# to print the operator trailing in order to keep it working.
|
2850
2850
|
last_child = children.last
|
2851
2851
|
if last_child.is_a?(CallNode) && last_child.message != :call &&
|
2852
|
-
|
2852
|
+
(
|
2853
|
+
(last_child.message.comments.any? && last_child.operator) ||
|
2854
|
+
(last_child.operator && last_child.operator.comments.any?)
|
2855
|
+
)
|
2853
2856
|
q.format(CallOperatorFormatter.new(last_child.operator))
|
2854
2857
|
skip_operator = true
|
2855
2858
|
else
|
@@ -5413,7 +5416,7 @@ module SyntaxTree
|
|
5413
5416
|
# end
|
5414
5417
|
#
|
5415
5418
|
class FndPtn < Node
|
5416
|
-
# [nil |
|
5419
|
+
# [nil | VarRef | ConstPathRef] the optional constant wrapper
|
5417
5420
|
attr_reader :constant
|
5418
5421
|
|
5419
5422
|
# [VarField] the splat on the left-hand side
|
@@ -6035,7 +6038,7 @@ module SyntaxTree
|
|
6035
6038
|
end
|
6036
6039
|
end
|
6037
6040
|
|
6038
|
-
# [nil |
|
6041
|
+
# [nil | VarRef | ConstPathRef] the optional constant wrapper
|
6039
6042
|
attr_reader :constant
|
6040
6043
|
|
6041
6044
|
# [Array[ [DynaSymbol | Label, nil | Node] ]] the set of tuples
|
@@ -7207,36 +7210,17 @@ module SyntaxTree
|
|
7207
7210
|
q.text(" ")
|
7208
7211
|
q
|
7209
7212
|
.if_break do
|
7210
|
-
|
7211
|
-
q.parents.any? do |node|
|
7212
|
-
node.is_a?(Command) || node.is_a?(CommandCall)
|
7213
|
-
end
|
7214
|
-
|
7215
|
-
if force_parens
|
7216
|
-
q.text("{")
|
7213
|
+
q.text("do")
|
7217
7214
|
|
7218
|
-
|
7219
|
-
|
7220
|
-
q.breakable_space
|
7221
|
-
q.format(statements)
|
7222
|
-
end
|
7215
|
+
unless statements.empty?
|
7216
|
+
q.indent do
|
7223
7217
|
q.breakable_space
|
7218
|
+
q.format(statements)
|
7224
7219
|
end
|
7225
|
-
|
7226
|
-
q.text("}")
|
7227
|
-
else
|
7228
|
-
q.text("do")
|
7229
|
-
|
7230
|
-
unless statements.empty?
|
7231
|
-
q.indent do
|
7232
|
-
q.breakable_space
|
7233
|
-
q.format(statements)
|
7234
|
-
end
|
7235
|
-
end
|
7236
|
-
|
7237
|
-
q.breakable_space
|
7238
|
-
q.text("end")
|
7239
7220
|
end
|
7221
|
+
|
7222
|
+
q.breakable_space
|
7223
|
+
q.text("end")
|
7240
7224
|
end
|
7241
7225
|
.if_flat do
|
7242
7226
|
q.text("{")
|
@@ -8293,8 +8277,8 @@ module SyntaxTree
|
|
8293
8277
|
# parameter
|
8294
8278
|
attr_reader :rest
|
8295
8279
|
|
8296
|
-
# [Array[ Ident ]] any positional parameters that exist after a
|
8297
|
-
# parameter
|
8280
|
+
# [Array[ Ident | MLHSParen ]] any positional parameters that exist after a
|
8281
|
+
# rest parameter
|
8298
8282
|
attr_reader :posts
|
8299
8283
|
|
8300
8284
|
# [Array[ [ Label, nil | Node ] ]] any keyword parameters and their
|
data/lib/syntax_tree/version.rb
CHANGED
@@ -152,10 +152,7 @@ module SyntaxTree
|
|
152
152
|
# arguments.
|
153
153
|
def visit_params(node)
|
154
154
|
add_argument_definitions(node.requireds)
|
155
|
-
|
156
|
-
node.posts.each do |param|
|
157
|
-
current_scope.add_local_definition(param, :argument)
|
158
|
-
end
|
155
|
+
add_argument_definitions(node.posts)
|
159
156
|
|
160
157
|
node.keywords.each do |param|
|
161
158
|
current_scope.add_local_definition(param.first, :argument)
|
@@ -31,7 +31,6 @@ module SyntaxTree
|
|
31
31
|
"FCALL" => CallData::CALL_FCALL,
|
32
32
|
"VCALL" => CallData::CALL_VCALL,
|
33
33
|
"ARGS_SIMPLE" => CallData::CALL_ARGS_SIMPLE,
|
34
|
-
"BLOCKISEQ" => CallData::CALL_BLOCKISEQ,
|
35
34
|
"KWARG" => CallData::CALL_KWARG,
|
36
35
|
"KW_SPLAT" => CallData::CALL_KW_SPLAT,
|
37
36
|
"TAILCALL" => CallData::CALL_TAILCALL,
|
@@ -5,19 +5,26 @@ module SyntaxTree
|
|
5
5
|
# This is an operand to various YARV instructions that represents the
|
6
6
|
# information about a specific call site.
|
7
7
|
class CallData
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
8
|
+
flags = %i[
|
9
|
+
CALL_ARGS_SPLAT
|
10
|
+
CALL_ARGS_BLOCKARG
|
11
|
+
CALL_FCALL
|
12
|
+
CALL_VCALL
|
13
|
+
CALL_ARGS_SIMPLE
|
14
|
+
CALL_KWARG
|
15
|
+
CALL_KW_SPLAT
|
16
|
+
CALL_TAILCALL
|
17
|
+
CALL_SUPER
|
18
|
+
CALL_ZSUPER
|
19
|
+
CALL_OPT_SEND
|
20
|
+
CALL_KW_SPLAT_MUT
|
21
|
+
]
|
22
|
+
|
23
|
+
# Insert the legacy CALL_BLOCKISEQ flag for Ruby 3.2 and earlier.
|
24
|
+
flags.insert(5, :CALL_BLOCKISEQ) if RUBY_VERSION < "3.3"
|
25
|
+
|
26
|
+
# Set the flags as constants on the class.
|
27
|
+
flags.each_with_index { |name, index| const_set(name, 1 << index) }
|
21
28
|
|
22
29
|
attr_reader :method, :argc, :flags, :kw_arg
|
23
30
|
|
@@ -50,7 +57,6 @@ module SyntaxTree
|
|
50
57
|
names << :FCALL if flag?(CALL_FCALL)
|
51
58
|
names << :VCALL if flag?(CALL_VCALL)
|
52
59
|
names << :ARGS_SIMPLE if flag?(CALL_ARGS_SIMPLE)
|
53
|
-
names << :BLOCKISEQ if flag?(CALL_BLOCKISEQ)
|
54
60
|
names << :KWARG if flag?(CALL_KWARG)
|
55
61
|
names << :KW_SPLAT if flag?(CALL_KW_SPLAT)
|
56
62
|
names << :TAILCALL if flag?(CALL_TAILCALL)
|
@@ -353,11 +353,27 @@ module SyntaxTree
|
|
353
353
|
next unless calldata.argc == 0
|
354
354
|
|
355
355
|
case calldata.method
|
356
|
+
when :min
|
357
|
+
node.value =
|
358
|
+
if RUBY_VERSION < "3.3"
|
359
|
+
Legacy::OptNewArrayMin.new(value.number)
|
360
|
+
else
|
361
|
+
OptNewArraySend.new(value.number, :min)
|
362
|
+
end
|
363
|
+
|
364
|
+
node.next_node = next_node.next_node
|
356
365
|
when :max
|
357
|
-
node.value =
|
366
|
+
node.value =
|
367
|
+
if RUBY_VERSION < "3.3"
|
368
|
+
Legacy::OptNewArrayMax.new(value.number)
|
369
|
+
else
|
370
|
+
OptNewArraySend.new(value.number, :max)
|
371
|
+
end
|
372
|
+
|
358
373
|
node.next_node = next_node.next_node
|
359
|
-
when :
|
360
|
-
|
374
|
+
when :hash
|
375
|
+
next if RUBY_VERSION < "3.3"
|
376
|
+
node.value = OptNewArraySend.new(value.number, :hash)
|
361
377
|
node.next_node = next_node.next_node
|
362
378
|
end
|
363
379
|
when PutObject, PutString
|
@@ -1174,6 +1190,9 @@ module SyntaxTree
|
|
1174
1190
|
when :opt_newarray_min
|
1175
1191
|
iseq.newarray(opnds[0])
|
1176
1192
|
iseq.send(YARV.calldata(:min))
|
1193
|
+
when :opt_newarray_send
|
1194
|
+
iseq.newarray(opnds[0])
|
1195
|
+
iseq.send(CallData.new(opnds[1]))
|
1177
1196
|
when :opt_neq
|
1178
1197
|
iseq.push(
|
1179
1198
|
OptNEq.new(CallData.from(opnds[0]), CallData.from(opnds[1]))
|
@@ -3818,9 +3818,10 @@ module SyntaxTree
|
|
3818
3818
|
|
3819
3819
|
# ### Summary
|
3820
3820
|
#
|
3821
|
-
# `
|
3822
|
-
# is
|
3823
|
-
# stack and pushes on the
|
3821
|
+
# `opt_newarray_send` is a specialization that occurs when a dynamic array
|
3822
|
+
# literal is created and immediately sent the `min`, `max`, or `hash`
|
3823
|
+
# methods. It pops the values of the array off the stack and pushes on the
|
3824
|
+
# result of the method call.
|
3824
3825
|
#
|
3825
3826
|
# ### Usage
|
3826
3827
|
#
|
@@ -3828,83 +3829,36 @@ module SyntaxTree
|
|
3828
3829
|
# [a, b, c].max
|
3829
3830
|
# ~~~
|
3830
3831
|
#
|
3831
|
-
class
|
3832
|
-
attr_reader :number
|
3833
|
-
|
3834
|
-
def initialize(number)
|
3835
|
-
@number = number
|
3836
|
-
end
|
3837
|
-
|
3838
|
-
def disasm(fmt)
|
3839
|
-
fmt.instruction("opt_newarray_max", [fmt.object(number)])
|
3840
|
-
end
|
3841
|
-
|
3842
|
-
def to_a(_iseq)
|
3843
|
-
[:opt_newarray_max, number]
|
3844
|
-
end
|
3845
|
-
|
3846
|
-
def deconstruct_keys(_keys)
|
3847
|
-
{ number: number }
|
3848
|
-
end
|
3849
|
-
|
3850
|
-
def ==(other)
|
3851
|
-
other.is_a?(OptNewArrayMax) && other.number == number
|
3852
|
-
end
|
3853
|
-
|
3854
|
-
def length
|
3855
|
-
2
|
3856
|
-
end
|
3857
|
-
|
3858
|
-
def pops
|
3859
|
-
number
|
3860
|
-
end
|
3832
|
+
class OptNewArraySend < Instruction
|
3833
|
+
attr_reader :number, :method
|
3861
3834
|
|
3862
|
-
def
|
3863
|
-
1
|
3864
|
-
end
|
3865
|
-
|
3866
|
-
def call(vm)
|
3867
|
-
vm.push(vm.pop(number).max)
|
3868
|
-
end
|
3869
|
-
end
|
3870
|
-
|
3871
|
-
# ### Summary
|
3872
|
-
#
|
3873
|
-
# `opt_newarray_min` is a specialization that occurs when the `min` method
|
3874
|
-
# is called on an array literal. It pops the values of the array off the
|
3875
|
-
# stack and pushes on the result.
|
3876
|
-
#
|
3877
|
-
# ### Usage
|
3878
|
-
#
|
3879
|
-
# ~~~ruby
|
3880
|
-
# [a, b, c].min
|
3881
|
-
# ~~~
|
3882
|
-
#
|
3883
|
-
class OptNewArrayMin < Instruction
|
3884
|
-
attr_reader :number
|
3885
|
-
|
3886
|
-
def initialize(number)
|
3835
|
+
def initialize(number, method)
|
3887
3836
|
@number = number
|
3837
|
+
@method = method
|
3888
3838
|
end
|
3889
3839
|
|
3890
3840
|
def disasm(fmt)
|
3891
|
-
fmt.instruction(
|
3841
|
+
fmt.instruction(
|
3842
|
+
"opt_newarray_send",
|
3843
|
+
[fmt.object(number), fmt.object(method)]
|
3844
|
+
)
|
3892
3845
|
end
|
3893
3846
|
|
3894
3847
|
def to_a(_iseq)
|
3895
|
-
[:
|
3848
|
+
[:opt_newarray_send, number, method]
|
3896
3849
|
end
|
3897
3850
|
|
3898
3851
|
def deconstruct_keys(_keys)
|
3899
|
-
{ number: number }
|
3852
|
+
{ number: number, method: method }
|
3900
3853
|
end
|
3901
3854
|
|
3902
3855
|
def ==(other)
|
3903
|
-
other.is_a?(
|
3856
|
+
other.is_a?(OptNewArraySend) && other.number == number &&
|
3857
|
+
other.method == method
|
3904
3858
|
end
|
3905
3859
|
|
3906
3860
|
def length
|
3907
|
-
|
3861
|
+
3
|
3908
3862
|
end
|
3909
3863
|
|
3910
3864
|
def pops
|
@@ -3916,7 +3870,7 @@ module SyntaxTree
|
|
3916
3870
|
end
|
3917
3871
|
|
3918
3872
|
def call(vm)
|
3919
|
-
vm.push(vm.pop(number).
|
3873
|
+
vm.push(vm.pop(number).__send__(method))
|
3920
3874
|
end
|
3921
3875
|
end
|
3922
3876
|
|
@@ -124,6 +124,110 @@ module SyntaxTree
|
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
+
# ### Summary
|
128
|
+
#
|
129
|
+
# `opt_newarray_max` is a specialization that occurs when the `max` method
|
130
|
+
# is called on an array literal. It pops the values of the array off the
|
131
|
+
# stack and pushes on the result.
|
132
|
+
#
|
133
|
+
# ### Usage
|
134
|
+
#
|
135
|
+
# ~~~ruby
|
136
|
+
# [a, b, c].max
|
137
|
+
# ~~~
|
138
|
+
#
|
139
|
+
class OptNewArrayMax < Instruction
|
140
|
+
attr_reader :number
|
141
|
+
|
142
|
+
def initialize(number)
|
143
|
+
@number = number
|
144
|
+
end
|
145
|
+
|
146
|
+
def disasm(fmt)
|
147
|
+
fmt.instruction("opt_newarray_max", [fmt.object(number)])
|
148
|
+
end
|
149
|
+
|
150
|
+
def to_a(_iseq)
|
151
|
+
[:opt_newarray_max, number]
|
152
|
+
end
|
153
|
+
|
154
|
+
def deconstruct_keys(_keys)
|
155
|
+
{ number: number }
|
156
|
+
end
|
157
|
+
|
158
|
+
def ==(other)
|
159
|
+
other.is_a?(OptNewArrayMax) && other.number == number
|
160
|
+
end
|
161
|
+
|
162
|
+
def length
|
163
|
+
2
|
164
|
+
end
|
165
|
+
|
166
|
+
def pops
|
167
|
+
number
|
168
|
+
end
|
169
|
+
|
170
|
+
def pushes
|
171
|
+
1
|
172
|
+
end
|
173
|
+
|
174
|
+
def call(vm)
|
175
|
+
vm.push(vm.pop(number).max)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# ### Summary
|
180
|
+
#
|
181
|
+
# `opt_newarray_min` is a specialization that occurs when the `min` method
|
182
|
+
# is called on an array literal. It pops the values of the array off the
|
183
|
+
# stack and pushes on the result.
|
184
|
+
#
|
185
|
+
# ### Usage
|
186
|
+
#
|
187
|
+
# ~~~ruby
|
188
|
+
# [a, b, c].min
|
189
|
+
# ~~~
|
190
|
+
#
|
191
|
+
class OptNewArrayMin < Instruction
|
192
|
+
attr_reader :number
|
193
|
+
|
194
|
+
def initialize(number)
|
195
|
+
@number = number
|
196
|
+
end
|
197
|
+
|
198
|
+
def disasm(fmt)
|
199
|
+
fmt.instruction("opt_newarray_min", [fmt.object(number)])
|
200
|
+
end
|
201
|
+
|
202
|
+
def to_a(_iseq)
|
203
|
+
[:opt_newarray_min, number]
|
204
|
+
end
|
205
|
+
|
206
|
+
def deconstruct_keys(_keys)
|
207
|
+
{ number: number }
|
208
|
+
end
|
209
|
+
|
210
|
+
def ==(other)
|
211
|
+
other.is_a?(OptNewArrayMin) && other.number == number
|
212
|
+
end
|
213
|
+
|
214
|
+
def length
|
215
|
+
2
|
216
|
+
end
|
217
|
+
|
218
|
+
def pops
|
219
|
+
number
|
220
|
+
end
|
221
|
+
|
222
|
+
def pushes
|
223
|
+
1
|
224
|
+
end
|
225
|
+
|
226
|
+
def call(vm)
|
227
|
+
vm.push(vm.pop(number).min)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
127
231
|
# ### Summary
|
128
232
|
#
|
129
233
|
# `opt_setinlinecache` sets an inline cache for a constant lookup. It pops
|
data/lib/syntax_tree.rb
CHANGED
@@ -21,6 +21,7 @@ module SyntaxTree
|
|
21
21
|
# CLI. Requiring those features takes time, so we autoload as many constants
|
22
22
|
# as possible in order to keep the CLI as fast as possible.
|
23
23
|
|
24
|
+
autoload :Database, "syntax_tree/database"
|
24
25
|
autoload :DSL, "syntax_tree/dsl"
|
25
26
|
autoload :FieldVisitor, "syntax_tree/field_visitor"
|
26
27
|
autoload :Index, "syntax_tree/index"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: syntax_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Newton
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prettier_print
|
@@ -130,6 +130,7 @@ files:
|
|
130
130
|
- lib/syntax_tree.rb
|
131
131
|
- lib/syntax_tree/basic_visitor.rb
|
132
132
|
- lib/syntax_tree/cli.rb
|
133
|
+
- lib/syntax_tree/database.rb
|
133
134
|
- lib/syntax_tree/dsl.rb
|
134
135
|
- lib/syntax_tree/field_visitor.rb
|
135
136
|
- lib/syntax_tree/formatter.rb
|
@@ -143,7 +144,7 @@ files:
|
|
143
144
|
- lib/syntax_tree/node.rb
|
144
145
|
- lib/syntax_tree/parser.rb
|
145
146
|
- lib/syntax_tree/pattern.rb
|
146
|
-
- lib/syntax_tree/plugin/
|
147
|
+
- lib/syntax_tree/plugin/disable_auto_ternary.rb
|
147
148
|
- lib/syntax_tree/plugin/single_quotes.rb
|
148
149
|
- lib/syntax_tree/plugin/trailing_comma.rb
|
149
150
|
- lib/syntax_tree/pretty_print_visitor.rb
|
@@ -198,7 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
198
199
|
- !ruby/object:Gem::Version
|
199
200
|
version: '0'
|
200
201
|
requirements: []
|
201
|
-
rubygems_version: 3.
|
202
|
+
rubygems_version: 3.5.0.dev
|
202
203
|
signing_key:
|
203
204
|
specification_version: 4
|
204
205
|
summary: A parser based on ripper
|