syntax_tree 6.1.1 → 6.3.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.
@@ -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
 
@@ -34,7 +41,7 @@ module SyntaxTree
34
41
  end
35
42
 
36
43
  def flag?(mask)
37
- (flags & mask) > 0
44
+ flags.anybits?(mask)
38
45
  end
39
46
 
40
47
  def to_h
@@ -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)
@@ -45,7 +45,7 @@ module SyntaxTree
45
45
  when Integer
46
46
  Int(value.to_s)
47
47
  when Symbol
48
- SymbolLiteral(Ident(value.to_s))
48
+ SymbolLiteral(Ident(value.name))
49
49
  end
50
50
  end
51
51
 
@@ -88,10 +88,10 @@ module SyntaxTree
88
88
 
89
89
  clause << HashLiteral(LBrace("{"), assocs)
90
90
  when GetGlobal
91
- clause << VarRef(GVar(insn.name.to_s))
91
+ clause << VarRef(GVar(insn.name.name))
92
92
  when GetLocalWC0
93
93
  local = iseq.local_table.locals[insn.index]
94
- clause << VarRef(Ident(local.name.to_s))
94
+ clause << VarRef(Ident(local.name.name))
95
95
  when Jump
96
96
  clause << Assign(block_label.field, node_for(insn.label.name))
97
97
  clause << Next(Args([]))
@@ -123,7 +123,7 @@ module SyntaxTree
123
123
  left, right = clause.pop(2)
124
124
  clause << Binary(left, :"!=", right)
125
125
  when OptSendWithoutBlock
126
- method = insn.calldata.method.to_s
126
+ method = insn.calldata.method.name
127
127
  argc = insn.calldata.argc
128
128
 
129
129
  if insn.calldata.flag?(CallData::CALL_FCALL)
@@ -182,7 +182,7 @@ module SyntaxTree
182
182
  when PutSelf
183
183
  clause << VarRef(Kw("self"))
184
184
  when SetGlobal
185
- target = GVar(insn.name.to_s)
185
+ target = GVar(insn.name.name)
186
186
  value = clause.pop
187
187
 
188
188
  clause << if value.is_a?(Binary) && VarRef(target) === value.left
@@ -256,7 +256,7 @@ module SyntaxTree
256
256
  def local_name(index, level)
257
257
  current = iseq
258
258
  level.times { current = current.parent_iseq }
259
- current.local_table.locals[index].name.to_s
259
+ current.local_table.locals[index].name.name
260
260
  end
261
261
  end
262
262
  end
@@ -252,19 +252,23 @@ module SyntaxTree
252
252
  dumped_options = argument_options.dup
253
253
  dumped_options[:opt].map!(&:name) if dumped_options[:opt]
254
254
 
255
+ metadata = {
256
+ arg_size: argument_size,
257
+ local_size: local_table.size,
258
+ stack_max: stack.maximum_size,
259
+ node_id: -1,
260
+ node_ids: [-1] * insns.length
261
+ }
262
+
263
+ metadata[:parser] = :prism if RUBY_VERSION >= "3.3"
264
+
255
265
  # Next, return the instruction sequence as an array.
256
266
  [
257
267
  MAGIC,
258
268
  versions[0],
259
269
  versions[1],
260
270
  1,
261
- {
262
- arg_size: argument_size,
263
- local_size: local_table.size,
264
- stack_max: stack.maximum_size,
265
- node_id: -1,
266
- node_ids: [-1] * insns.length
267
- },
271
+ metadata,
268
272
  name,
269
273
  file,
270
274
  "<compiled>",
@@ -353,11 +357,27 @@ module SyntaxTree
353
357
  next unless calldata.argc == 0
354
358
 
355
359
  case calldata.method
360
+ when :min
361
+ node.value =
362
+ if RUBY_VERSION < "3.3"
363
+ Legacy::OptNewArrayMin.new(value.number)
364
+ else
365
+ OptNewArraySend.new(value.number, :min)
366
+ end
367
+
368
+ node.next_node = next_node.next_node
356
369
  when :max
357
- node.value = OptNewArrayMax.new(value.number)
370
+ node.value =
371
+ if RUBY_VERSION < "3.3"
372
+ Legacy::OptNewArrayMax.new(value.number)
373
+ else
374
+ OptNewArraySend.new(value.number, :max)
375
+ end
376
+
358
377
  node.next_node = next_node.next_node
359
- when :min
360
- node.value = OptNewArrayMin.new(value.number)
378
+ when :hash
379
+ next if RUBY_VERSION < "3.3"
380
+ node.value = OptNewArraySend.new(value.number, :hash)
361
381
  node.next_node = next_node.next_node
362
382
  end
363
383
  when PutObject, PutString
@@ -673,6 +693,10 @@ module SyntaxTree
673
693
  push(ConcatStrings.new(number))
674
694
  end
675
695
 
696
+ def concattoarray(object)
697
+ push(ConcatToArray.new(object))
698
+ end
699
+
676
700
  def defineclass(name, class_iseq, flags)
677
701
  push(DefineClass.new(name, class_iseq, flags))
678
702
  end
@@ -881,6 +905,14 @@ module SyntaxTree
881
905
  push(Pop.new)
882
906
  end
883
907
 
908
+ def pushtoarraykwsplat
909
+ push(PushToArrayKwSplat.new)
910
+ end
911
+
912
+ def putchilledstring(object)
913
+ push(PutChilledString.new(object))
914
+ end
915
+
884
916
  def putnil
885
917
  push(PutNil.new)
886
918
  end
@@ -1063,6 +1095,8 @@ module SyntaxTree
1063
1095
  iseq.concatarray
1064
1096
  when :concatstrings
1065
1097
  iseq.concatstrings(opnds[0])
1098
+ when :concattoarray
1099
+ iseq.concattoarray(opnds[0])
1066
1100
  when :defineclass
1067
1101
  iseq.defineclass(opnds[0], from(opnds[1], options, iseq), opnds[2])
1068
1102
  when :defined
@@ -1174,6 +1208,14 @@ module SyntaxTree
1174
1208
  when :opt_newarray_min
1175
1209
  iseq.newarray(opnds[0])
1176
1210
  iseq.send(YARV.calldata(:min))
1211
+ when :opt_newarray_send
1212
+ mid = opnds[1]
1213
+ if RUBY_VERSION >= "3.4"
1214
+ mid = %i[max min hash pack pack_buffer include?][mid - 1]
1215
+ end
1216
+
1217
+ iseq.newarray(opnds[0])
1218
+ iseq.send(CallData.new(mid))
1177
1219
  when :opt_neq
1178
1220
  iseq.push(
1179
1221
  OptNEq.new(CallData.from(opnds[0]), CallData.from(opnds[1]))
@@ -1188,6 +1230,10 @@ module SyntaxTree
1188
1230
  iseq.send(YARV.calldata(:-@))
1189
1231
  when :pop
1190
1232
  iseq.pop
1233
+ when :pushtoarraykwsplat
1234
+ iseq.pushtoarraykwsplat
1235
+ when :putchilledstring
1236
+ iseq.putchilledstring(opnds[0])
1191
1237
  when :putnil
1192
1238
  iseq.putnil
1193
1239
  when :putobject
@@ -757,6 +757,59 @@ module SyntaxTree
757
757
  end
758
758
  end
759
759
 
760
+ # ### Summary
761
+ #
762
+ # `concattoarray` pops a single value off the stack and attempts to concat
763
+ # it to the Array on top of the stack. If the value is not an Array, it
764
+ # will be coerced into one.
765
+ #
766
+ # ### Usage
767
+ #
768
+ # ~~~ruby
769
+ # [1, *2]
770
+ # ~~~
771
+ #
772
+ class ConcatToArray < Instruction
773
+ attr_reader :object
774
+
775
+ def initialize(object)
776
+ @object = object
777
+ end
778
+
779
+ def disasm(fmt)
780
+ fmt.instruction("concattoarray", [fmt.object(object)])
781
+ end
782
+
783
+ def to_a(_iseq)
784
+ [:concattoarray, object]
785
+ end
786
+
787
+ def deconstruct_keys(_keys)
788
+ { object: object }
789
+ end
790
+
791
+ def ==(other)
792
+ other.is_a?(ConcatToArray) && other.object == object
793
+ end
794
+
795
+ def length
796
+ 2
797
+ end
798
+
799
+ def pops
800
+ 1
801
+ end
802
+
803
+ def pushes
804
+ 1
805
+ end
806
+
807
+ def call(vm)
808
+ array, value = vm.pop(2)
809
+ vm.push(array.concat(Array(value)))
810
+ end
811
+ end
812
+
760
813
  # ### Summary
761
814
  #
762
815
  # `defineclass` defines a class. First it pops the superclass off the
@@ -3818,9 +3871,10 @@ module SyntaxTree
3818
3871
 
3819
3872
  # ### Summary
3820
3873
  #
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.
3874
+ # `opt_newarray_send` is a specialization that occurs when a dynamic array
3875
+ # literal is created and immediately sent the `min`, `max`, or `hash`
3876
+ # methods. It pops the values of the array off the stack and pushes on the
3877
+ # result of the method call.
3824
3878
  #
3825
3879
  # ### Usage
3826
3880
  #
@@ -3828,83 +3882,36 @@ module SyntaxTree
3828
3882
  # [a, b, c].max
3829
3883
  # ~~~
3830
3884
  #
3831
- class OptNewArrayMax < Instruction
3832
- attr_reader :number
3885
+ class OptNewArraySend < Instruction
3886
+ attr_reader :number, :method
3833
3887
 
3834
- def initialize(number)
3888
+ def initialize(number, method)
3835
3889
  @number = number
3890
+ @method = method
3836
3891
  end
3837
3892
 
3838
3893
  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
3861
-
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)
3887
- @number = number
3888
- end
3889
-
3890
- def disasm(fmt)
3891
- fmt.instruction("opt_newarray_min", [fmt.object(number)])
3894
+ fmt.instruction(
3895
+ "opt_newarray_send",
3896
+ [fmt.object(number), fmt.object(method)]
3897
+ )
3892
3898
  end
3893
3899
 
3894
3900
  def to_a(_iseq)
3895
- [:opt_newarray_min, number]
3901
+ [:opt_newarray_send, number, method]
3896
3902
  end
3897
3903
 
3898
3904
  def deconstruct_keys(_keys)
3899
- { number: number }
3905
+ { number: number, method: method }
3900
3906
  end
3901
3907
 
3902
3908
  def ==(other)
3903
- other.is_a?(OptNewArrayMin) && other.number == number
3909
+ other.is_a?(OptNewArraySend) && other.number == number &&
3910
+ other.method == method
3904
3911
  end
3905
3912
 
3906
3913
  def length
3907
- 2
3914
+ 3
3908
3915
  end
3909
3916
 
3910
3917
  def pops
@@ -3916,7 +3923,7 @@ module SyntaxTree
3916
3923
  end
3917
3924
 
3918
3925
  def call(vm)
3919
- vm.push(vm.pop(number).min)
3926
+ vm.push(vm.pop(number).__send__(method))
3920
3927
  end
3921
3928
  end
3922
3929
 
@@ -4518,6 +4525,52 @@ module SyntaxTree
4518
4525
  end
4519
4526
  end
4520
4527
 
4528
+ # ### Summary
4529
+ #
4530
+ # `pushtoarraykwsplat` is used to append a hash literal that is being
4531
+ # splatted onto an array.
4532
+ #
4533
+ # ### Usage
4534
+ #
4535
+ # ~~~ruby
4536
+ # ["string", **{ foo: "bar" }]
4537
+ # ~~~
4538
+ #
4539
+ class PushToArrayKwSplat < Instruction
4540
+ def disasm(fmt)
4541
+ fmt.instruction("pushtoarraykwsplat")
4542
+ end
4543
+
4544
+ def to_a(_iseq)
4545
+ [:pushtoarraykwsplat]
4546
+ end
4547
+
4548
+ def deconstruct_keys(_keys)
4549
+ {}
4550
+ end
4551
+
4552
+ def ==(other)
4553
+ other.is_a?(PushToArrayKwSplat)
4554
+ end
4555
+
4556
+ def length
4557
+ 2
4558
+ end
4559
+
4560
+ def pops
4561
+ 2
4562
+ end
4563
+
4564
+ def pushes
4565
+ 1
4566
+ end
4567
+
4568
+ def call(vm)
4569
+ array, hash = vm.pop(2)
4570
+ vm.push(array << hash)
4571
+ end
4572
+ end
4573
+
4521
4574
  # ### Summary
4522
4575
  #
4523
4576
  # `putnil` pushes a global nil object onto the stack.
@@ -4805,6 +4858,54 @@ module SyntaxTree
4805
4858
  end
4806
4859
  end
4807
4860
 
4861
+ # ### Summary
4862
+ #
4863
+ # `putchilledstring` pushes an unfrozen string literal onto the stack that
4864
+ # acts like a frozen string. This is a migration path to frozen string
4865
+ # literals as the default in the future.
4866
+ #
4867
+ # ### Usage
4868
+ #
4869
+ # ~~~ruby
4870
+ # "foo"
4871
+ # ~~~
4872
+ #
4873
+ class PutChilledString < Instruction
4874
+ attr_reader :object
4875
+
4876
+ def initialize(object)
4877
+ @object = object
4878
+ end
4879
+
4880
+ def disasm(fmt)
4881
+ fmt.instruction("putchilledstring", [fmt.object(object)])
4882
+ end
4883
+
4884
+ def to_a(_iseq)
4885
+ [:putchilledstring, object]
4886
+ end
4887
+
4888
+ def deconstruct_keys(_keys)
4889
+ { object: object }
4890
+ end
4891
+
4892
+ def ==(other)
4893
+ other.is_a?(PutChilledString) && other.object == object
4894
+ end
4895
+
4896
+ def length
4897
+ 2
4898
+ end
4899
+
4900
+ def pushes
4901
+ 1
4902
+ end
4903
+
4904
+ def call(vm)
4905
+ vm.push(object.dup)
4906
+ end
4907
+ end
4908
+
4808
4909
  # ### Summary
4809
4910
  #
4810
4911
  # `putstring` pushes an unfrozen string literal onto the stack.
@@ -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"
@@ -43,8 +43,13 @@ module ParseHelper
43
43
  # that we do not support.
44
44
  return if (versions & %w[3.1 3.2]).empty?
45
45
 
46
- entry = caller.find { _1.include?("test_parser.rb") }
47
- _, lineno, name = *entry.match(/(\d+):in `(.+)'/)
46
+ entry =
47
+ caller.find do |call|
48
+ call.include?("test_parser.rb") && call.match?(%r{(?<!/)test_})
49
+ end
50
+
51
+ _, lineno, name =
52
+ *entry.match(/(\d+):in [`'](?:block in )?(?:TestParser#)?(.+)'/)
48
53
 
49
54
  COLLECTED["#{name}:#{lineno}"] << code
50
55
  end