syntax_tree 5.1.0 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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