syntax_tree 6.1.1 → 6.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|