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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31a164da5fc7e3de4ae0d009993bd0d7b81ca0fd6d99dffe97e932321e122beb
4
- data.tar.gz: d345c0e73f3286e5e8ade42d6c39646b2537a7b184fb14d4af4fdb031c8a9f8b
3
+ metadata.gz: ec83d4ecf5722316de95bb541d45d6213db7917ff6bb6e13fef397a65075bffa
4
+ data.tar.gz: 6171e1b60ab99eea54a761d5feec302554133b97fea8f95ed473a799e4005542
5
5
  SHA512:
6
- metadata.gz: fe70bcbd90253660d903278f23858a19fc9c644cb3f8b5fc1d8772be552f9cd594565445a3970dcec7374a27c3d087e3c772397d1ed9fb8bb86d616fa481ee06
7
- data.tar.gz: 2d676538addd43745630e1721a4f059e3342d46902fbb25702b6daa16adae80c3f376444ddd67dd079569feeab8f0322ec9acef79a024789348372575263fbaf
6
+ metadata.gz: 5266b33544de3aae02d4d200f7239ed388a1e1bb045e93ed46c1d14d1fb618ee8592238ce21040cc05708c7947ed564dd3477d757849da080758c9399d883309
7
+ data.tar.gz: 398685af92d3b506382feba646f5d24e4151b6dc3d25e19a018b8fdfe5e0d301a53c54a0684a584c083951267e9205be46ab36420d075536bbe1a08d12de7b3d
@@ -12,7 +12,7 @@ jobs:
12
12
  steps:
13
13
  - name: Dependabot metadata
14
14
  id: metadata
15
- uses: dependabot/fetch-metadata@v1.3.6
15
+ uses: dependabot/fetch-metadata@v1.6.0
16
16
  with:
17
17
  github-token: "${{ secrets.GITHUB_TOKEN }}"
18
18
  - name: Enable auto-merge for Dependabot PRs
@@ -25,7 +25,7 @@ jobs:
25
25
  runs-on: ubuntu-latest
26
26
  steps:
27
27
  - name: Checkout
28
- uses: actions/checkout@v3
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@v1
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.2...HEAD
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.1.1)
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
- minitest (5.18.0)
14
- parallel (1.22.1)
15
- parser (3.2.1.1)
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.7.0)
21
- rexml (3.2.5)
22
- rubocop (1.48.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.0.0)
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.26.0, < 2.0)
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.27.0)
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, to be sure to be using a version control system.
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/visitor](lib/syntax_tree/visitor) directory.
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?(DISABLE_TERNARY)
63
+ defined?(DISABLE_AUTO_TERNARY)
64
64
  else
65
65
  disable_auto_ternary
66
66
  end
@@ -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
- last_child.message.comments.any? && last_child.operator
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 | Node] the optional constant wrapper
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 | Node] the optional constant wrapper
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
- force_parens =
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
- unless statements.empty?
7219
- q.indent do
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 rest
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SyntaxTree
4
4
  class Formatter
5
- DISABLE_TERNARY = true
5
+ DISABLE_AUTO_TERNARY = true
6
6
  end
7
7
  end
@@ -64,7 +64,7 @@ module SyntaxTree
64
64
 
65
65
  class << self
66
66
  def parse(comment)
67
- comment = comment.gsub(/\n/, " ")
67
+ comment = comment.gsub("\n", " ")
68
68
 
69
69
  unless comment.start_with?("[")
70
70
  raise "Comment does not start with a bracket: #{comment.inspect}"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SyntaxTree
4
- VERSION = "6.1.1"
4
+ VERSION = "6.2.0"
5
5
  end
@@ -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
- CALL_ARGS_SPLAT = 1 << 0
9
- CALL_ARGS_BLOCKARG = 1 << 1
10
- CALL_FCALL = 1 << 2
11
- CALL_VCALL = 1 << 3
12
- CALL_ARGS_SIMPLE = 1 << 4
13
- CALL_BLOCKISEQ = 1 << 5
14
- CALL_KWARG = 1 << 6
15
- CALL_KW_SPLAT = 1 << 7
16
- CALL_TAILCALL = 1 << 8
17
- CALL_SUPER = 1 << 9
18
- CALL_ZSUPER = 1 << 10
19
- CALL_OPT_SEND = 1 << 11
20
- CALL_KW_SPLAT_MUT = 1 << 12
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 = OptNewArrayMax.new(value.number)
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 :min
360
- node.value = OptNewArrayMin.new(value.number)
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
- # `opt_newarray_max` is a specialization that occurs when the `max` method
3822
- # is called on an array literal. It pops the values of the array off the
3823
- # stack and pushes on the result.
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 OptNewArrayMax < Instruction
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 pushes
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("opt_newarray_min", [fmt.object(number)])
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
- [:opt_newarray_min, number]
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?(OptNewArrayMin) && other.number == number
3856
+ other.is_a?(OptNewArraySend) && other.number == number &&
3857
+ other.method == method
3904
3858
  end
3905
3859
 
3906
3860
  def length
3907
- 2
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).min)
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.1.1
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-03-21 00:00:00.000000000 Z
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/disable_ternary.rb
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.4.1
202
+ rubygems_version: 3.5.0.dev
202
203
  signing_key:
203
204
  specification_version: 4
204
205
  summary: A parser based on ripper