syntax_tree 5.1.0 → 5.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.
@@ -285,7 +285,7 @@ module SyntaxTree
285
285
  # if we need to return the value of the last statement.
286
286
  attr_reader :last_statement
287
287
 
288
- def initialize(options)
288
+ def initialize(options = Options.new)
289
289
  @options = options
290
290
  @iseq = nil
291
291
  @last_statement = false
@@ -304,10 +304,11 @@ module SyntaxTree
304
304
  end
305
305
 
306
306
  def visit_END(node)
307
+ start_line = node.location.start_line
307
308
  once_iseq =
308
- with_child_iseq(iseq.block_child_iseq(node.location)) do
309
+ with_child_iseq(iseq.block_child_iseq(start_line)) do
309
310
  postexe_iseq =
310
- with_child_iseq(iseq.block_child_iseq(node.location)) do
311
+ with_child_iseq(iseq.block_child_iseq(start_line)) do
311
312
  iseq.event(:RUBY_EVENT_B_CALL)
312
313
 
313
314
  *statements, last_statement = node.statements.body
@@ -567,7 +568,7 @@ module SyntaxTree
567
568
  end
568
569
 
569
570
  def visit_block(node)
570
- with_child_iseq(iseq.block_child_iseq(node.location)) do
571
+ with_child_iseq(iseq.block_child_iseq(node.location.start_line)) do
571
572
  iseq.event(:RUBY_EVENT_B_CALL)
572
573
  visit(node.block_var)
573
574
  visit(node.bodystmt)
@@ -751,7 +752,9 @@ module SyntaxTree
751
752
  def visit_class(node)
752
753
  name = node.constant.constant.value.to_sym
753
754
  class_iseq =
754
- with_child_iseq(iseq.class_child_iseq(name, node.location)) do
755
+ with_child_iseq(
756
+ iseq.class_child_iseq(name, node.location.start_line)
757
+ ) do
755
758
  iseq.event(:RUBY_EVENT_CLASS)
756
759
  visit(node.bodystmt)
757
760
  iseq.event(:RUBY_EVENT_END)
@@ -818,7 +821,8 @@ module SyntaxTree
818
821
 
819
822
  def visit_def(node)
820
823
  name = node.name.value.to_sym
821
- method_iseq = iseq.method_child_iseq(name.to_s, node.location)
824
+ method_iseq =
825
+ iseq.method_child_iseq(name.to_s, node.location.start_line)
822
826
 
823
827
  with_child_iseq(method_iseq) do
824
828
  visit(node.params) if node.params
@@ -939,7 +943,9 @@ module SyntaxTree
939
943
  iseq.local_table.plain(name)
940
944
 
941
945
  block_iseq =
942
- with_child_iseq(iseq.block_child_iseq(node.statements.location)) do
946
+ with_child_iseq(
947
+ iseq.block_child_iseq(node.statements.location.start_line)
948
+ ) do
943
949
  iseq.argument_options[:lead_num] ||= 0
944
950
  iseq.argument_options[:lead_num] += 1
945
951
  iseq.argument_options[:ambiguous_param0] = true
@@ -1076,7 +1082,7 @@ module SyntaxTree
1076
1082
 
1077
1083
  def visit_lambda(node)
1078
1084
  lambda_iseq =
1079
- with_child_iseq(iseq.block_child_iseq(node.location)) do
1085
+ with_child_iseq(iseq.block_child_iseq(node.location.start_line)) do
1080
1086
  iseq.event(:RUBY_EVENT_B_CALL)
1081
1087
  visit(node.params)
1082
1088
  visit(node.statements)
@@ -1127,7 +1133,9 @@ module SyntaxTree
1127
1133
  def visit_module(node)
1128
1134
  name = node.constant.constant.value.to_sym
1129
1135
  module_iseq =
1130
- with_child_iseq(iseq.module_child_iseq(name, node.location)) do
1136
+ with_child_iseq(
1137
+ iseq.module_child_iseq(name, node.location.start_line)
1138
+ ) do
1131
1139
  iseq.event(:RUBY_EVENT_CLASS)
1132
1140
  visit(node.bodystmt)
1133
1141
  iseq.event(:RUBY_EVENT_END)
@@ -1375,10 +1383,11 @@ module SyntaxTree
1375
1383
 
1376
1384
  top_iseq =
1377
1385
  InstructionSequence.new(
1378
- :top,
1379
1386
  "<compiled>",
1387
+ "<compiled>",
1388
+ 1,
1389
+ :top,
1380
1390
  nil,
1381
- node.location,
1382
1391
  options
1383
1392
  )
1384
1393
 
@@ -1543,7 +1552,9 @@ module SyntaxTree
1543
1552
  iseq.putnil
1544
1553
 
1545
1554
  singleton_iseq =
1546
- with_child_iseq(iseq.singleton_class_child_iseq(node.location)) do
1555
+ with_child_iseq(
1556
+ iseq.singleton_class_child_iseq(node.location.start_line)
1557
+ ) do
1547
1558
  iseq.event(:RUBY_EVENT_CLASS)
1548
1559
  visit(node.bodystmt)
1549
1560
  iseq.event(:RUBY_EVENT_END)
@@ -2018,7 +2029,7 @@ module SyntaxTree
2018
2029
  if node.constant
2019
2030
  iseq.dup
2020
2031
  visit(node.constant)
2021
- iseq.checkmatch(CheckMatch::TYPE_CASE)
2032
+ iseq.checkmatch(CheckMatch::VM_CHECKMATCH_TYPE_CASE)
2022
2033
  iseq.branchunless(match_failure_label)
2023
2034
  end
2024
2035
 
@@ -2078,7 +2089,7 @@ module SyntaxTree
2078
2089
  iseq.setlocal(lookup.index, lookup.level)
2079
2090
  else
2080
2091
  visit(required)
2081
- iseq.checkmatch(CheckMatch::TYPE_CASE)
2092
+ iseq.checkmatch(CheckMatch::VM_CHECKMATCH_TYPE_CASE)
2082
2093
  iseq.branchunless(match_failure_label)
2083
2094
  end
2084
2095
 
@@ -64,6 +64,13 @@ module SyntaxTree
64
64
  clauses[label] = clause
65
65
  clause = []
66
66
  label = insn.name
67
+ when BranchIf
68
+ body = [
69
+ Assign(block_label.field, node_for(insn.label.name)),
70
+ Next(Args([]))
71
+ ]
72
+
73
+ clause << UnlessNode(clause.pop, Statements(body), nil)
67
74
  when BranchUnless
68
75
  body = [
69
76
  Assign(block_label.field, node_for(insn.label.name)),
@@ -90,7 +97,7 @@ module SyntaxTree
90
97
  clause << Next(Args([]))
91
98
  when Leave
92
99
  value = Args([clause.pop])
93
- clause << (iseq.type == :top ? Break(value) : ReturnNode(value))
100
+ clause << (iseq.type != :top ? Break(value) : ReturnNode(value))
94
101
  when OptAnd, OptDiv, OptEq, OptGE, OptGT, OptLE, OptLT, OptLTLT,
95
102
  OptMinus, OptMod, OptMult, OptOr, OptPlus
96
103
  left, right = clause.pop(2)
@@ -157,6 +164,8 @@ module SyntaxTree
157
164
  )
158
165
  end
159
166
  end
167
+ when Pop
168
+ # skip
160
169
  when PutObject
161
170
  case insn.object
162
171
  when Float
@@ -4,7 +4,8 @@ module SyntaxTree
4
4
  module YARV
5
5
  class Disassembler
6
6
  attr_reader :output, :queue
7
- attr_reader :current_prefix, :current_iseq
7
+ attr_reader :current_prefix
8
+ attr_accessor :current_iseq
8
9
 
9
10
  def initialize
10
11
  @output = StringIO.new
@@ -114,7 +115,7 @@ module SyntaxTree
114
115
  output << "#{current_prefix}== disasm: "
115
116
  output << "#<ISeq:#{iseq.name}@<compiled>:1 "
116
117
 
117
- location = iseq.location
118
+ location = Location.fixed(line: iseq.line, char: 0, column: 0)
118
119
  output << "(#{location.start_line},#{location.start_column})-"
119
120
  output << "(#{location.end_line},#{location.end_column})"
120
121
  output << "> "
@@ -70,7 +70,7 @@ module SyntaxTree
70
70
  [Fiddle::TYPE_VOIDP] * 3,
71
71
  Fiddle::TYPE_VOIDP
72
72
  )
73
- rescue NameError
73
+ rescue NameError, Fiddle::DLError
74
74
  end
75
75
 
76
76
  # This object is used to track the size of the stack at any given time. It
@@ -116,18 +116,18 @@ module SyntaxTree
116
116
  end
117
117
  end
118
118
 
119
- # The type of the instruction sequence.
120
- attr_reader :type
121
-
122
119
  # The name of the instruction sequence.
123
120
  attr_reader :name
124
121
 
122
+ # The source location of the instruction sequence.
123
+ attr_reader :file, :line
124
+
125
+ # The type of the instruction sequence.
126
+ attr_reader :type
127
+
125
128
  # The parent instruction sequence, if there is one.
126
129
  attr_reader :parent_iseq
127
130
 
128
- # The location of the root node of this instruction sequence.
129
- attr_reader :location
130
-
131
131
  # This is the list of information about the arguments to this
132
132
  # instruction sequence.
133
133
  attr_accessor :argument_size
@@ -157,16 +157,18 @@ module SyntaxTree
157
157
  attr_reader :options
158
158
 
159
159
  def initialize(
160
- type,
161
160
  name,
162
- parent_iseq,
163
- location,
161
+ file,
162
+ line,
163
+ type,
164
+ parent_iseq = nil,
164
165
  options = Compiler::Options.new
165
166
  )
166
- @type = type
167
167
  @name = name
168
+ @file = file
169
+ @line = line
170
+ @type = type
168
171
  @parent_iseq = parent_iseq
169
- @location = location
170
172
 
171
173
  @argument_size = 0
172
174
  @argument_options = {}
@@ -256,9 +258,9 @@ module SyntaxTree
256
258
  node_ids: [-1] * insns.length
257
259
  },
258
260
  name,
261
+ file,
259
262
  "<compiled>",
260
- "<compiled>",
261
- location.start_line,
263
+ line,
262
264
  type,
263
265
  local_table.names,
264
266
  dumped_options,
@@ -278,6 +280,12 @@ module SyntaxTree
278
280
  def compile!
279
281
  specialize_instructions! if options.specialized_instruction?
280
282
 
283
+ catch_table.each do |catch_entry|
284
+ if !catch_entry.is_a?(CatchBreak) && catch_entry.iseq
285
+ catch_entry.iseq.compile!
286
+ end
287
+ end
288
+
281
289
  length = 0
282
290
  insns.each do |insn|
283
291
  case insn
@@ -416,30 +424,30 @@ module SyntaxTree
416
424
  # Child instruction sequence methods
417
425
  ##########################################################################
418
426
 
419
- def child_iseq(type, name, location)
420
- InstructionSequence.new(type, name, self, location, options)
427
+ def child_iseq(name, line, type)
428
+ InstructionSequence.new(name, file, line, type, self, options)
421
429
  end
422
430
 
423
- def block_child_iseq(location)
431
+ def block_child_iseq(line)
424
432
  current = self
425
433
  current = current.parent_iseq while current.type == :block
426
- child_iseq(:block, "block in #{current.name}", location)
434
+ child_iseq("block in #{current.name}", line, :block)
427
435
  end
428
436
 
429
- def class_child_iseq(name, location)
430
- child_iseq(:class, "<class:#{name}>", location)
437
+ def class_child_iseq(name, line)
438
+ child_iseq("<class:#{name}>", line, :class)
431
439
  end
432
440
 
433
- def method_child_iseq(name, location)
434
- child_iseq(:method, name, location)
441
+ def method_child_iseq(name, line)
442
+ child_iseq(name, line, :method)
435
443
  end
436
444
 
437
- def module_child_iseq(name, location)
438
- child_iseq(:class, "<module:#{name}>", location)
445
+ def module_child_iseq(name, line)
446
+ child_iseq("<module:#{name}>", line, :class)
439
447
  end
440
448
 
441
- def singleton_class_child_iseq(location)
442
- child_iseq(:class, "singleton class", location)
449
+ def singleton_class_child_iseq(line)
450
+ child_iseq("singleton class", line, :class)
443
451
  end
444
452
 
445
453
  ##########################################################################
@@ -447,19 +455,39 @@ module SyntaxTree
447
455
  ##########################################################################
448
456
 
449
457
  class CatchEntry
450
- attr_reader :iseq, :begin_label, :end_label, :exit_label
458
+ attr_reader :iseq, :begin_label, :end_label, :exit_label, :restore_sp
451
459
 
452
- def initialize(iseq, begin_label, end_label, exit_label)
460
+ def initialize(iseq, begin_label, end_label, exit_label, restore_sp)
453
461
  @iseq = iseq
454
462
  @begin_label = begin_label
455
463
  @end_label = end_label
456
464
  @exit_label = exit_label
465
+ @restore_sp = restore_sp
457
466
  end
458
467
  end
459
468
 
460
469
  class CatchBreak < CatchEntry
461
470
  def to_a
462
- [:break, iseq.to_a, begin_label.name, end_label.name, exit_label.name]
471
+ [
472
+ :break,
473
+ iseq.to_a,
474
+ begin_label.name,
475
+ end_label.name,
476
+ exit_label.name,
477
+ restore_sp
478
+ ]
479
+ end
480
+ end
481
+
482
+ class CatchEnsure < CatchEntry
483
+ def to_a
484
+ [
485
+ :ensure,
486
+ iseq.to_a,
487
+ begin_label.name,
488
+ end_label.name,
489
+ exit_label.name
490
+ ]
463
491
  end
464
492
  end
465
493
 
@@ -493,24 +521,64 @@ module SyntaxTree
493
521
  end
494
522
  end
495
523
 
496
- def catch_break(iseq, begin_label, end_label, exit_label)
497
- catch_table << CatchBreak.new(iseq, begin_label, end_label, exit_label)
498
- end
499
-
500
- def catch_next(begin_label, end_label, exit_label)
501
- catch_table << CatchNext.new(nil, begin_label, end_label, exit_label)
502
- end
503
-
504
- def catch_redo(begin_label, end_label, exit_label)
505
- catch_table << CatchRedo.new(nil, begin_label, end_label, exit_label)
506
- end
507
-
508
- def catch_rescue(iseq, begin_label, end_label, exit_label)
509
- catch_table << CatchRescue.new(iseq, begin_label, end_label, exit_label)
510
- end
511
-
512
- def catch_retry(begin_label, end_label, exit_label)
513
- catch_table << CatchRetry.new(nil, begin_label, end_label, exit_label)
524
+ def catch_break(iseq, begin_label, end_label, exit_label, restore_sp)
525
+ catch_table << CatchBreak.new(
526
+ iseq,
527
+ begin_label,
528
+ end_label,
529
+ exit_label,
530
+ restore_sp
531
+ )
532
+ end
533
+
534
+ def catch_ensure(iseq, begin_label, end_label, exit_label, restore_sp)
535
+ catch_table << CatchEnsure.new(
536
+ iseq,
537
+ begin_label,
538
+ end_label,
539
+ exit_label,
540
+ restore_sp
541
+ )
542
+ end
543
+
544
+ def catch_next(begin_label, end_label, exit_label, restore_sp)
545
+ catch_table << CatchNext.new(
546
+ nil,
547
+ begin_label,
548
+ end_label,
549
+ exit_label,
550
+ restore_sp
551
+ )
552
+ end
553
+
554
+ def catch_redo(begin_label, end_label, exit_label, restore_sp)
555
+ catch_table << CatchRedo.new(
556
+ nil,
557
+ begin_label,
558
+ end_label,
559
+ exit_label,
560
+ restore_sp
561
+ )
562
+ end
563
+
564
+ def catch_rescue(iseq, begin_label, end_label, exit_label, restore_sp)
565
+ catch_table << CatchRescue.new(
566
+ iseq,
567
+ begin_label,
568
+ end_label,
569
+ exit_label,
570
+ restore_sp
571
+ )
572
+ end
573
+
574
+ def catch_retry(begin_label, end_label, exit_label, restore_sp)
575
+ catch_table << CatchRetry.new(
576
+ nil,
577
+ begin_label,
578
+ end_label,
579
+ exit_label,
580
+ restore_sp
581
+ )
514
582
  end
515
583
 
516
584
  ##########################################################################
@@ -895,7 +963,8 @@ module SyntaxTree
895
963
  # This method will create a new instruction sequence from a serialized
896
964
  # RubyVM::InstructionSequence object.
897
965
  def self.from(source, options = Compiler::Options.new, parent_iseq = nil)
898
- iseq = new(source[9], source[5], parent_iseq, Location.default, options)
966
+ iseq =
967
+ new(source[5], source[6], source[8], source[9], parent_iseq, options)
899
968
 
900
969
  # set up the labels object so that the labels are shared between the
901
970
  # location in the instruction sequence and the instructions that
@@ -914,45 +983,9 @@ module SyntaxTree
914
983
  iseq.argument_options[:opt].map! { |opt| labels[opt] }
915
984
  end
916
985
 
917
- # set up the catch table
918
- source[12].each do |entry|
919
- case entry[0]
920
- when :break
921
- iseq.catch_break(
922
- from(entry[1]),
923
- labels[entry[2]],
924
- labels[entry[3]],
925
- labels[entry[4]]
926
- )
927
- when :next
928
- iseq.catch_next(
929
- labels[entry[2]],
930
- labels[entry[3]],
931
- labels[entry[4]]
932
- )
933
- when :rescue
934
- iseq.catch_rescue(
935
- from(entry[1]),
936
- labels[entry[2]],
937
- labels[entry[3]],
938
- labels[entry[4]]
939
- )
940
- when :redo
941
- iseq.catch_redo(
942
- labels[entry[2]],
943
- labels[entry[3]],
944
- labels[entry[4]]
945
- )
946
- when :retry
947
- iseq.catch_retry(
948
- labels[entry[2]],
949
- labels[entry[3]],
950
- labels[entry[4]]
951
- )
952
- else
953
- raise "unknown catch type: #{entry[0]}"
954
- end
955
- end
986
+ # track the child block iseqs so that our catch table can point to the
987
+ # correctly created iseqs
988
+ block_iseqs = []
956
989
 
957
990
  # set up all of the instructions
958
991
  source[13].each do |insn|
@@ -1135,6 +1168,7 @@ module SyntaxTree
1135
1168
  iseq.putspecialobject(opnds[0])
1136
1169
  when :send
1137
1170
  block_iseq = opnds[1] ? from(opnds[1], options, iseq) : nil
1171
+ block_iseqs << block_iseq if block_iseq
1138
1172
  iseq.send(CallData.from(opnds[0]), block_iseq)
1139
1173
  when :setclassvariable
1140
1174
  iseq.push(SetClassVariable.new(opnds[0], opnds[1]))
@@ -1163,6 +1197,76 @@ module SyntaxTree
1163
1197
  end
1164
1198
  end
1165
1199
 
1200
+ # set up the catch table
1201
+ source[12].each do |entry|
1202
+ case entry[0]
1203
+ when :break
1204
+ if entry[1]
1205
+ break_iseq =
1206
+ block_iseqs.find do |block_iseq|
1207
+ block_iseq.name == entry[1][5] &&
1208
+ block_iseq.file == entry[1][6] &&
1209
+ block_iseq.line == entry[1][8]
1210
+ end
1211
+
1212
+ iseq.catch_break(
1213
+ break_iseq || from(entry[1], options, iseq),
1214
+ labels[entry[2]],
1215
+ labels[entry[3]],
1216
+ labels[entry[4]],
1217
+ entry[5]
1218
+ )
1219
+ else
1220
+ iseq.catch_break(
1221
+ nil,
1222
+ labels[entry[2]],
1223
+ labels[entry[3]],
1224
+ labels[entry[4]],
1225
+ entry[5]
1226
+ )
1227
+ end
1228
+ when :ensure
1229
+ iseq.catch_ensure(
1230
+ from(entry[1], options, iseq),
1231
+ labels[entry[2]],
1232
+ labels[entry[3]],
1233
+ labels[entry[4]],
1234
+ entry[5]
1235
+ )
1236
+ when :next
1237
+ iseq.catch_next(
1238
+ labels[entry[2]],
1239
+ labels[entry[3]],
1240
+ labels[entry[4]],
1241
+ entry[5]
1242
+ )
1243
+ when :rescue
1244
+ iseq.catch_rescue(
1245
+ from(entry[1], options, iseq),
1246
+ labels[entry[2]],
1247
+ labels[entry[3]],
1248
+ labels[entry[4]],
1249
+ entry[5]
1250
+ )
1251
+ when :redo
1252
+ iseq.catch_redo(
1253
+ labels[entry[2]],
1254
+ labels[entry[3]],
1255
+ labels[entry[4]],
1256
+ entry[5]
1257
+ )
1258
+ when :retry
1259
+ iseq.catch_retry(
1260
+ labels[entry[2]],
1261
+ labels[entry[3]],
1262
+ labels[entry[4]],
1263
+ entry[5]
1264
+ )
1265
+ else
1266
+ raise "unknown catch type: #{entry[0]}"
1267
+ end
1268
+ end
1269
+
1166
1270
  iseq.compile! if iseq.type == :top
1167
1271
  iseq
1168
1272
  end