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.
- checksums.yaml +4 -4
- data/.github/workflows/auto-merge.yml +1 -1
- data/.github/workflows/gh-pages.yml +6 -6
- data/.github/workflows/main.yml +2 -1
- data/.rubocop.yml +10 -1
- data/CHANGELOG.md +28 -1
- data/Gemfile +2 -0
- data/Gemfile.lock +30 -20
- data/README.md +3 -3
- data/lib/syntax_tree/cli.rb +69 -14
- data/lib/syntax_tree/database.rb +331 -0
- data/lib/syntax_tree/formatter.rb +1 -1
- data/lib/syntax_tree/language_server.rb +8 -2
- data/lib/syntax_tree/node.rb +70 -67
- data/lib/syntax_tree/parser.rb +8 -3
- data/lib/syntax_tree/pattern.rb +1 -0
- 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 +2 -3
- data/lib/syntax_tree/yarv/calldata.rb +21 -15
- data/lib/syntax_tree/yarv/decompiler.rb +6 -6
- data/lib/syntax_tree/yarv/instruction_sequence.rb +56 -10
- data/lib/syntax_tree/yarv/instructions.rb +165 -64
- data/lib/syntax_tree/yarv/legacy.rb +104 -0
- data/lib/syntax_tree.rb +1 -0
- data/tasks/whitequark.rake +7 -2
- metadata +5 -9
- data/.ruby-version +0 -1
@@ -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
|
|
@@ -34,7 +41,7 @@ module SyntaxTree
|
|
34
41
|
end
|
35
42
|
|
36
43
|
def flag?(mask)
|
37
|
-
(
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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 =
|
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 :
|
360
|
-
|
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
|
-
# `
|
3822
|
-
# is
|
3823
|
-
# stack and pushes on the
|
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
|
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(
|
3840
|
-
|
3841
|
-
|
3842
|
-
|
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
|
-
[:
|
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?(
|
3909
|
+
other.is_a?(OptNewArraySend) && other.number == number &&
|
3910
|
+
other.method == method
|
3904
3911
|
end
|
3905
3912
|
|
3906
3913
|
def length
|
3907
|
-
|
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).
|
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"
|
data/tasks/whitequark.rake
CHANGED
@@ -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 =
|
47
|
-
|
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
|