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 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