syntax_tree 5.1.0 → 5.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 +4 -4
- data/.github/dependabot.yml +4 -0
- data/.github/workflows/auto-merge.yml +1 -1
- data/.github/workflows/main.yml +5 -2
- data/.gitmodules +6 -0
- data/.rubocop.yml +7 -1
- data/CHANGELOG.md +12 -1
- data/Gemfile.lock +7 -7
- data/Rakefile +7 -0
- data/exe/yarv +63 -0
- data/lib/syntax_tree/node.rb +19 -10
- data/lib/syntax_tree/parser.rb +1 -1
- data/lib/syntax_tree/version.rb +1 -1
- data/lib/syntax_tree/yarv/assembler.rb +7 -7
- data/lib/syntax_tree/yarv/bf.rb +13 -16
- data/lib/syntax_tree/yarv/compiler.rb +24 -13
- data/lib/syntax_tree/yarv/decompiler.rb +9 -0
- data/lib/syntax_tree/yarv/disassembler.rb +3 -2
- data/lib/syntax_tree/yarv/instruction_sequence.rb +190 -86
- data/lib/syntax_tree/yarv/instructions.rb +211 -42
- data/lib/syntax_tree/yarv/legacy.rb +26 -3
- data/lib/syntax_tree/yarv/vm.rb +624 -0
- data/lib/syntax_tree/yarv.rb +0 -269
- data/lib/syntax_tree.rb +1 -0
- metadata +7 -3
@@ -399,9 +399,11 @@ module SyntaxTree
|
|
399
399
|
# ~~~
|
400
400
|
#
|
401
401
|
class CheckMatch
|
402
|
-
|
403
|
-
|
404
|
-
|
402
|
+
VM_CHECKMATCH_TYPE_WHEN = 1
|
403
|
+
VM_CHECKMATCH_TYPE_CASE = 2
|
404
|
+
VM_CHECKMATCH_TYPE_RESCUE = 3
|
405
|
+
VM_CHECKMATCH_TYPE_MASK = 0x03
|
406
|
+
VM_CHECKMATCH_ARRAY = 0x04
|
405
407
|
|
406
408
|
attr_reader :type
|
407
409
|
|
@@ -434,7 +436,32 @@ module SyntaxTree
|
|
434
436
|
end
|
435
437
|
|
436
438
|
def call(vm)
|
437
|
-
|
439
|
+
target, pattern = vm.pop(2)
|
440
|
+
|
441
|
+
vm.push(
|
442
|
+
if type & VM_CHECKMATCH_ARRAY > 0
|
443
|
+
pattern.any? { |item| check?(item, target) }
|
444
|
+
else
|
445
|
+
check?(pattern, target)
|
446
|
+
end
|
447
|
+
)
|
448
|
+
end
|
449
|
+
|
450
|
+
private
|
451
|
+
|
452
|
+
def check?(pattern, target)
|
453
|
+
case type & VM_CHECKMATCH_TYPE_MASK
|
454
|
+
when VM_CHECKMATCH_TYPE_WHEN
|
455
|
+
pattern
|
456
|
+
when VM_CHECKMATCH_TYPE_CASE
|
457
|
+
pattern === target
|
458
|
+
when VM_CHECKMATCH_TYPE_RESCUE
|
459
|
+
unless pattern.is_a?(Module)
|
460
|
+
raise TypeError, "class or module required for rescue clause"
|
461
|
+
end
|
462
|
+
|
463
|
+
pattern === target
|
464
|
+
end
|
438
465
|
end
|
439
466
|
end
|
440
467
|
|
@@ -762,12 +789,26 @@ module SyntaxTree
|
|
762
789
|
|
763
790
|
def call(vm)
|
764
791
|
object, superclass = vm.pop(2)
|
765
|
-
iseq = class_iseq
|
766
792
|
|
767
|
-
|
768
|
-
|
793
|
+
if name == :singletonclass
|
794
|
+
vm.push(vm.run_class_frame(class_iseq, object.singleton_class))
|
795
|
+
elsif object.const_defined?(name)
|
796
|
+
vm.push(vm.run_class_frame(class_iseq, object.const_get(name)))
|
797
|
+
elsif flags & TYPE_MODULE > 0
|
798
|
+
clazz = Module.new
|
799
|
+
object.const_set(name, clazz)
|
800
|
+
vm.push(vm.run_class_frame(class_iseq, clazz))
|
801
|
+
else
|
802
|
+
clazz =
|
803
|
+
if flags & FLAG_HAS_SUPERCLASS > 0
|
804
|
+
Class.new(superclass)
|
805
|
+
else
|
806
|
+
Class.new
|
807
|
+
end
|
769
808
|
|
770
|
-
|
809
|
+
object.const_set(name, clazz)
|
810
|
+
vm.push(vm.run_class_frame(class_iseq, clazz))
|
811
|
+
end
|
771
812
|
end
|
772
813
|
end
|
773
814
|
|
@@ -882,17 +923,19 @@ module SyntaxTree
|
|
882
923
|
when TYPE_NIL, TYPE_SELF, TYPE_TRUE, TYPE_FALSE, TYPE_ASGN, TYPE_EXPR
|
883
924
|
message
|
884
925
|
when TYPE_IVAR
|
885
|
-
message if vm._self.instance_variable_defined?(name)
|
926
|
+
message if vm.frame._self.instance_variable_defined?(name)
|
886
927
|
when TYPE_LVAR
|
887
928
|
raise NotImplementedError, "defined TYPE_LVAR"
|
888
929
|
when TYPE_GVAR
|
889
930
|
message if global_variables.include?(name)
|
890
931
|
when TYPE_CVAR
|
891
|
-
clazz = vm._self
|
932
|
+
clazz = vm.frame._self
|
892
933
|
clazz = clazz.singleton_class unless clazz.is_a?(Module)
|
893
934
|
message if clazz.class_variable_defined?(name)
|
894
935
|
when TYPE_CONST
|
895
|
-
|
936
|
+
clazz = vm.frame._self
|
937
|
+
clazz = clazz.singleton_class unless clazz.is_a?(Module)
|
938
|
+
message if clazz.const_defined?(name)
|
896
939
|
when TYPE_METHOD
|
897
940
|
raise NotImplementedError, "defined TYPE_METHOD"
|
898
941
|
when TYPE_YIELD
|
@@ -904,7 +947,9 @@ module SyntaxTree
|
|
904
947
|
when TYPE_FUNC
|
905
948
|
message if object.respond_to?(name, true)
|
906
949
|
when TYPE_CONST_FROM
|
907
|
-
|
950
|
+
defined =
|
951
|
+
vm.frame.nesting.any? { |scope| scope.const_defined?(name, true) }
|
952
|
+
message if defined
|
908
953
|
end
|
909
954
|
|
910
955
|
vm.push(result)
|
@@ -962,12 +1007,22 @@ module SyntaxTree
|
|
962
1007
|
|
963
1008
|
def call(vm)
|
964
1009
|
name = method_name
|
1010
|
+
nesting = vm.frame.nesting
|
965
1011
|
iseq = method_iseq
|
966
1012
|
|
967
1013
|
vm
|
1014
|
+
.frame
|
968
1015
|
._self
|
969
1016
|
.__send__(:define_method, name) do |*args, **kwargs, &block|
|
970
|
-
vm.run_method_frame(
|
1017
|
+
vm.run_method_frame(
|
1018
|
+
name,
|
1019
|
+
nesting,
|
1020
|
+
iseq,
|
1021
|
+
self,
|
1022
|
+
*args,
|
1023
|
+
**kwargs,
|
1024
|
+
&block
|
1025
|
+
)
|
971
1026
|
end
|
972
1027
|
end
|
973
1028
|
end
|
@@ -1024,12 +1079,22 @@ module SyntaxTree
|
|
1024
1079
|
|
1025
1080
|
def call(vm)
|
1026
1081
|
name = method_name
|
1082
|
+
nesting = vm.frame.nesting
|
1027
1083
|
iseq = method_iseq
|
1028
1084
|
|
1029
1085
|
vm
|
1086
|
+
.frame
|
1030
1087
|
._self
|
1031
1088
|
.__send__(:define_singleton_method, name) do |*args, **kwargs, &block|
|
1032
|
-
vm.run_method_frame(
|
1089
|
+
vm.run_method_frame(
|
1090
|
+
name,
|
1091
|
+
nesting,
|
1092
|
+
iseq,
|
1093
|
+
self,
|
1094
|
+
*args,
|
1095
|
+
**kwargs,
|
1096
|
+
&block
|
1097
|
+
)
|
1033
1098
|
end
|
1034
1099
|
end
|
1035
1100
|
end
|
@@ -1259,7 +1324,42 @@ module SyntaxTree
|
|
1259
1324
|
end
|
1260
1325
|
|
1261
1326
|
def call(vm)
|
1262
|
-
|
1327
|
+
object = vm.pop
|
1328
|
+
object =
|
1329
|
+
if Array === object
|
1330
|
+
object.dup
|
1331
|
+
elsif object.respond_to?(:to_ary, true)
|
1332
|
+
object.to_ary
|
1333
|
+
else
|
1334
|
+
[object]
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
splat_flag = flags & 0x01 > 0
|
1338
|
+
postarg_flag = flags & 0x02 > 0
|
1339
|
+
|
1340
|
+
if number == 0 && splat_flag == 0
|
1341
|
+
# no space left on stack
|
1342
|
+
elsif postarg_flag
|
1343
|
+
values = []
|
1344
|
+
|
1345
|
+
if number > object.size
|
1346
|
+
(number - object.size).times { values.push(nil) }
|
1347
|
+
end
|
1348
|
+
[number, object.size].min.times { values.push(object.pop) }
|
1349
|
+
values.push(object.to_a) if splat_flag
|
1350
|
+
|
1351
|
+
values.each { |item| vm.push(item) }
|
1352
|
+
else
|
1353
|
+
values = []
|
1354
|
+
|
1355
|
+
[number, object.size].min.times { values.push(object.shift) }
|
1356
|
+
if number > values.size
|
1357
|
+
(number - values.size).times { values.push(nil) }
|
1358
|
+
end
|
1359
|
+
values.push(object.to_a) if splat_flag
|
1360
|
+
|
1361
|
+
values.reverse_each { |item| vm.push(item) }
|
1362
|
+
end
|
1263
1363
|
end
|
1264
1364
|
end
|
1265
1365
|
|
@@ -1424,7 +1524,7 @@ module SyntaxTree
|
|
1424
1524
|
end
|
1425
1525
|
|
1426
1526
|
def call(vm)
|
1427
|
-
clazz = vm._self
|
1527
|
+
clazz = vm.frame._self
|
1428
1528
|
clazz = clazz.class unless clazz.is_a?(Class)
|
1429
1529
|
vm.push(clazz.class_variable_get(name))
|
1430
1530
|
end
|
@@ -1474,14 +1574,20 @@ module SyntaxTree
|
|
1474
1574
|
end
|
1475
1575
|
|
1476
1576
|
def call(vm)
|
1477
|
-
|
1478
|
-
vm.pop(2)
|
1577
|
+
const_base, allow_nil = vm.pop(2)
|
1479
1578
|
|
1480
|
-
|
1481
|
-
if
|
1482
|
-
vm.push(
|
1579
|
+
if const_base
|
1580
|
+
if const_base.const_defined?(name)
|
1581
|
+
vm.push(const_base.const_get(name))
|
1483
1582
|
return
|
1484
1583
|
end
|
1584
|
+
elsif const_base.nil? && allow_nil
|
1585
|
+
vm.frame.nesting.reverse_each do |clazz|
|
1586
|
+
if clazz.const_defined?(name)
|
1587
|
+
vm.push(clazz.const_get(name))
|
1588
|
+
return
|
1589
|
+
end
|
1590
|
+
end
|
1485
1591
|
end
|
1486
1592
|
|
1487
1593
|
raise NameError, "uninitialized constant #{name}"
|
@@ -1590,7 +1696,7 @@ module SyntaxTree
|
|
1590
1696
|
|
1591
1697
|
def call(vm)
|
1592
1698
|
method = Object.instance_method(:instance_variable_get)
|
1593
|
-
vm.push(method.bind(vm._self).call(name))
|
1699
|
+
vm.push(method.bind(vm.frame._self).call(name))
|
1594
1700
|
end
|
1595
1701
|
end
|
1596
1702
|
|
@@ -1948,8 +2054,9 @@ module SyntaxTree
|
|
1948
2054
|
def call(vm)
|
1949
2055
|
block =
|
1950
2056
|
if (iseq = block_iseq)
|
2057
|
+
frame = vm.frame
|
1951
2058
|
->(*args, **kwargs, &blk) do
|
1952
|
-
vm.run_block_frame(iseq, *args, **kwargs, &blk)
|
2059
|
+
vm.run_block_frame(iseq, frame, *args, **kwargs, &blk)
|
1953
2060
|
end
|
1954
2061
|
end
|
1955
2062
|
|
@@ -2396,7 +2503,7 @@ module SyntaxTree
|
|
2396
2503
|
|
2397
2504
|
def call(vm)
|
2398
2505
|
return if @executed
|
2399
|
-
vm.push(vm.run_block_frame(iseq))
|
2506
|
+
vm.push(vm.run_block_frame(iseq, vm.frame))
|
2400
2507
|
@executed = true
|
2401
2508
|
end
|
2402
2509
|
end
|
@@ -2960,7 +3067,7 @@ module SyntaxTree
|
|
2960
3067
|
end
|
2961
3068
|
|
2962
3069
|
def call(vm)
|
2963
|
-
current = vm._self
|
3070
|
+
current = vm.frame._self
|
2964
3071
|
current = current.class unless current.is_a?(Class)
|
2965
3072
|
|
2966
3073
|
names.each do |name|
|
@@ -4254,7 +4361,7 @@ module SyntaxTree
|
|
4254
4361
|
end
|
4255
4362
|
|
4256
4363
|
def call(vm)
|
4257
|
-
vm.push(vm._self)
|
4364
|
+
vm.push(vm.frame._self)
|
4258
4365
|
end
|
4259
4366
|
end
|
4260
4367
|
|
@@ -4310,7 +4417,7 @@ module SyntaxTree
|
|
4310
4417
|
when OBJECT_VMCORE
|
4311
4418
|
vm.push(vm.frozen_core)
|
4312
4419
|
when OBJECT_CBASE
|
4313
|
-
value = vm._self
|
4420
|
+
value = vm.frame._self
|
4314
4421
|
value = value.singleton_class unless value.is_a?(Class)
|
4315
4422
|
vm.push(value)
|
4316
4423
|
when OBJECT_CONST_BASE
|
@@ -4418,9 +4525,12 @@ module SyntaxTree
|
|
4418
4525
|
def call(vm)
|
4419
4526
|
block =
|
4420
4527
|
if (iseq = block_iseq)
|
4528
|
+
frame = vm.frame
|
4421
4529
|
->(*args, **kwargs, &blk) do
|
4422
|
-
vm.run_block_frame(iseq, *args, **kwargs, &blk)
|
4530
|
+
vm.run_block_frame(iseq, frame, *args, **kwargs, &blk)
|
4423
4531
|
end
|
4532
|
+
elsif calldata.flag?(CallData::CALL_ARGS_BLOCKARG)
|
4533
|
+
vm.pop
|
4424
4534
|
end
|
4425
4535
|
|
4426
4536
|
keywords =
|
@@ -4542,7 +4652,7 @@ module SyntaxTree
|
|
4542
4652
|
end
|
4543
4653
|
|
4544
4654
|
def call(vm)
|
4545
|
-
clazz = vm._self
|
4655
|
+
clazz = vm.frame._self
|
4546
4656
|
clazz = clazz.class unless clazz.is_a?(Class)
|
4547
4657
|
clazz.class_variable_set(name, vm.pop)
|
4548
4658
|
end
|
@@ -4698,7 +4808,7 @@ module SyntaxTree
|
|
4698
4808
|
|
4699
4809
|
def call(vm)
|
4700
4810
|
method = Object.instance_method(:instance_variable_set)
|
4701
|
-
method.bind(vm._self).call(name, vm.pop)
|
4811
|
+
method.bind(vm.frame._self).call(name, vm.pop)
|
4702
4812
|
end
|
4703
4813
|
end
|
4704
4814
|
|
@@ -4946,7 +5056,7 @@ module SyntaxTree
|
|
4946
5056
|
def call(vm)
|
4947
5057
|
case key
|
4948
5058
|
when GetSpecial::SVAR_LASTLINE
|
4949
|
-
raise NotImplementedError, "
|
5059
|
+
raise NotImplementedError, "setspecial SVAR_LASTLINE"
|
4950
5060
|
when GetSpecial::SVAR_BACKREF
|
4951
5061
|
raise NotImplementedError, "setspecial SVAR_BACKREF"
|
4952
5062
|
when GetSpecial::SVAR_FLIPFLOP_START
|
@@ -4999,7 +5109,27 @@ module SyntaxTree
|
|
4999
5109
|
end
|
5000
5110
|
|
5001
5111
|
def call(vm)
|
5002
|
-
vm.
|
5112
|
+
value = vm.pop
|
5113
|
+
|
5114
|
+
vm.push(
|
5115
|
+
if Array === value
|
5116
|
+
value.instance_of?(Array) ? value.dup : Array[*value]
|
5117
|
+
elsif value.nil?
|
5118
|
+
value.to_a
|
5119
|
+
else
|
5120
|
+
if value.respond_to?(:to_a, true)
|
5121
|
+
result = value.to_a
|
5122
|
+
|
5123
|
+
if result.nil?
|
5124
|
+
[value]
|
5125
|
+
elsif !result.is_a?(Array)
|
5126
|
+
raise TypeError, "expected to_a to return an Array"
|
5127
|
+
end
|
5128
|
+
else
|
5129
|
+
[value]
|
5130
|
+
end
|
5131
|
+
end
|
5132
|
+
)
|
5003
5133
|
end
|
5004
5134
|
end
|
5005
5135
|
|
@@ -5061,15 +5191,18 @@ module SyntaxTree
|
|
5061
5191
|
# ~~~
|
5062
5192
|
#
|
5063
5193
|
class Throw
|
5064
|
-
|
5065
|
-
|
5066
|
-
|
5067
|
-
|
5068
|
-
|
5069
|
-
|
5070
|
-
|
5071
|
-
|
5072
|
-
|
5194
|
+
RUBY_TAG_NONE = 0x0
|
5195
|
+
RUBY_TAG_RETURN = 0x1
|
5196
|
+
RUBY_TAG_BREAK = 0x2
|
5197
|
+
RUBY_TAG_NEXT = 0x3
|
5198
|
+
RUBY_TAG_RETRY = 0x4
|
5199
|
+
RUBY_TAG_REDO = 0x5
|
5200
|
+
RUBY_TAG_RAISE = 0x6
|
5201
|
+
RUBY_TAG_THROW = 0x7
|
5202
|
+
RUBY_TAG_FATAL = 0x8
|
5203
|
+
|
5204
|
+
VM_THROW_NO_ESCAPE_FLAG = 0x8000
|
5205
|
+
VM_THROW_STATE_MASK = 0xff
|
5073
5206
|
|
5074
5207
|
attr_reader :type
|
5075
5208
|
|
@@ -5102,7 +5235,43 @@ module SyntaxTree
|
|
5102
5235
|
end
|
5103
5236
|
|
5104
5237
|
def call(vm)
|
5105
|
-
|
5238
|
+
state = type & VM_THROW_STATE_MASK
|
5239
|
+
value = vm.pop
|
5240
|
+
|
5241
|
+
case state
|
5242
|
+
when RUBY_TAG_NONE
|
5243
|
+
case value
|
5244
|
+
when nil
|
5245
|
+
# do nothing
|
5246
|
+
when Exception
|
5247
|
+
raise value
|
5248
|
+
else
|
5249
|
+
raise NotImplementedError
|
5250
|
+
end
|
5251
|
+
when RUBY_TAG_RETURN
|
5252
|
+
raise VM::ReturnError.new(value, error_backtrace(vm))
|
5253
|
+
when RUBY_TAG_BREAK
|
5254
|
+
raise VM::BreakError.new(value, error_backtrace(vm))
|
5255
|
+
when RUBY_TAG_NEXT
|
5256
|
+
raise VM::NextError.new(value, error_backtrace(vm))
|
5257
|
+
else
|
5258
|
+
raise NotImplementedError, "Unknown throw kind #{state}"
|
5259
|
+
end
|
5260
|
+
end
|
5261
|
+
|
5262
|
+
private
|
5263
|
+
|
5264
|
+
def error_backtrace(vm)
|
5265
|
+
backtrace = []
|
5266
|
+
current = vm.frame
|
5267
|
+
|
5268
|
+
while current
|
5269
|
+
backtrace << "#{current.iseq.file}:#{current.line}:in" \
|
5270
|
+
"`#{current.iseq.name}'"
|
5271
|
+
current = current.parent
|
5272
|
+
end
|
5273
|
+
|
5274
|
+
[*backtrace, *caller]
|
5106
5275
|
end
|
5107
5276
|
end
|
5108
5277
|
|
@@ -45,6 +45,14 @@ module SyntaxTree
|
|
45
45
|
def pushes
|
46
46
|
1
|
47
47
|
end
|
48
|
+
|
49
|
+
def canonical
|
50
|
+
YARV::GetClassVariable.new(name, nil)
|
51
|
+
end
|
52
|
+
|
53
|
+
def call(vm)
|
54
|
+
canonical.call(vm)
|
55
|
+
end
|
48
56
|
end
|
49
57
|
|
50
58
|
# ### Summary
|
@@ -94,6 +102,10 @@ module SyntaxTree
|
|
94
102
|
1
|
95
103
|
end
|
96
104
|
|
105
|
+
def canonical
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
97
109
|
def call(vm)
|
98
110
|
vm.push(nil)
|
99
111
|
end
|
@@ -102,8 +114,8 @@ module SyntaxTree
|
|
102
114
|
# ### Summary
|
103
115
|
#
|
104
116
|
# `opt_setinlinecache` sets an inline cache for a constant lookup. It pops
|
105
|
-
# the value it should set off the top of the stack. It
|
106
|
-
# value back onto the top of the stack.
|
117
|
+
# the value it should set off the top of the stack. It uses this value to
|
118
|
+
# set the cache. It then pushes that value back onto the top of the stack.
|
107
119
|
#
|
108
120
|
# This instruction is no longer used since in Ruby 3.2 it was replaced by
|
109
121
|
# the consolidated `opt_getconstant_path` instruction.
|
@@ -141,8 +153,11 @@ module SyntaxTree
|
|
141
153
|
1
|
142
154
|
end
|
143
155
|
|
156
|
+
def canonical
|
157
|
+
self
|
158
|
+
end
|
159
|
+
|
144
160
|
def call(vm)
|
145
|
-
vm.push(vm.pop)
|
146
161
|
end
|
147
162
|
end
|
148
163
|
|
@@ -186,6 +201,14 @@ module SyntaxTree
|
|
186
201
|
def pushes
|
187
202
|
0
|
188
203
|
end
|
204
|
+
|
205
|
+
def canonical
|
206
|
+
YARV::SetClassVariable.new(name, nil)
|
207
|
+
end
|
208
|
+
|
209
|
+
def call(vm)
|
210
|
+
canonical.call(vm)
|
211
|
+
end
|
189
212
|
end
|
190
213
|
end
|
191
214
|
end
|