yadriggy 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1839 @@
1
+ # Copyright (C) 2017- Shigeru Chiba. All rights reserved.
2
+
3
+ require 'yadriggy/source_code'
4
+
5
+ module Yadriggy
6
+
7
+ # Gets the abstract syntax tree (AST) of the given procedure `proc`.
8
+ # If `proc` is nil, the block argument is converted into an abstract
9
+ # syntax tree. The returned {ASTree} object is a container holding
10
+ # not only an AST but also other data. To get an AST, call {ASTree#tree}
11
+ # on the {ASTree} object.
12
+ #
13
+ # {ASTree#reify} on the {ASTree} object obtains the ASTs of other
14
+ # procs and methods. It returns the same AST for the same proc or
15
+ # method since it records ASTs obtained before. The table of
16
+ # the recorded ASTs are shared among {ASTree} objects.
17
+ # Every call to {Yadriggy#reify} on {Yadriggy} makes a new table. Hence,
18
+ #
19
+ # <pre>ast1 = Yadriggy.reify(proc1)
20
+ # ast2 = ast.reify(proc2)
21
+ # a1 = Yadriggy.reify(proc1) # a1 != ast1
22
+ # a2 = a1.reify(proc2) # a2 != ast2
23
+ # b2 = a1.reify(proc2) # b2 == a2</pre>
24
+ #
25
+ # Although `ast1` and `a1`, and `ast2` and `a2` are different copies
26
+ # of the AST of the same proc, `a2` and `b2` refer to the same AST.
27
+ #
28
+ # @param [Method|UnboundMethod|Proc] proc the procedure.
29
+ # @yield the block is used as the procedure if `proc` is `nil`.
30
+ # @return [ASTree|nil] the abstract syntax tree.
31
+ #
32
+ # @see ASTree#reify
33
+ def self.reify(proc = nil, &block)
34
+ code = proc || block
35
+ return nil if code.nil?
36
+ # a is used only for bootstrapping.
37
+ a = ASTree.new(ASTreeTable.new, code, '?', [:zsuper])
38
+ a.astrees.delete(code)
39
+ a.reify(code)
40
+ end
41
+
42
+ # The common ancestor class of AST nodes.
43
+ #
44
+ class ASTnode
45
+ # @return [ASTnode] the parent node.
46
+ attr_accessor :parent
47
+
48
+ # Overrides the printer printer.
49
+ def pretty_print(pp)
50
+ Yadriggy::simpler_pretty_print(pp, self, '@parent')
51
+ end
52
+
53
+ # @param [ASTnode] node adds a child node.
54
+ # @return [void]
55
+ def add_child(node)
56
+ node.parent = self unless node.nil?
57
+ end
58
+
59
+ # @param [Array<ASTnode>] nodes adds child nodes.
60
+ # @return [void]
61
+ def add_children(nodes)
62
+ nodes.map {|e| e.parent = self unless e.nil? }
63
+ end
64
+
65
+ # @return [ASTnode] the root node.
66
+ def root
67
+ parent&.root || self
68
+ end
69
+ end
70
+
71
+ # Abstract class.
72
+ #
73
+ class Name < ASTnode
74
+ # @return [String] the name.
75
+ attr_reader :name
76
+
77
+ # @return [Integer] the line number.
78
+ attr_reader :line_no
79
+
80
+ # @return [Integer] the column.
81
+ attr_reader :column
82
+
83
+ # Converts the name to a symbol
84
+ # @return [Symbol] the converted symbol.
85
+ def to_sym
86
+ @name.to_sym
87
+ end
88
+
89
+ private
90
+ def initialize(sexp)
91
+ @name = sexp[1]
92
+ @line_no = sexp[2][0].to_i
93
+ @column = sexp[2][1].to_i
94
+ end
95
+ end
96
+
97
+ # @abstract
98
+ # The super class of {Identifier} and {VariableCall}.
99
+ #
100
+ class IdentifierOrCall < Name
101
+ def initialize(sexp)
102
+ super(sexp)
103
+ end
104
+ end
105
+
106
+ # Identifier.
107
+ class Identifier < IdentifierOrCall
108
+ def self.tags() [:@ident, :@op] end
109
+
110
+ def initialize(sexp)
111
+ super(sexp)
112
+ end
113
+
114
+ # A method for Visitor pattern.
115
+ # @param [Eval] evaluator the visitor of Visitor pattern.
116
+ # @return [void]
117
+ def accept(evaluator)
118
+ evaluator.identifier(self)
119
+ end
120
+ end
121
+
122
+ # Constant variable such as a class name.
123
+ #
124
+ class Const < Name
125
+ def self.tag() :@const end
126
+
127
+ def initialize(sexp)
128
+ super(sexp)
129
+ end
130
+
131
+ # A method for Visitor pattern.
132
+ # @param [Eval] evaluator the visitor of Visitor pattern.
133
+ # @return [void]
134
+ def accept(evaluator)
135
+ evaluator.const(self)
136
+ end
137
+ end
138
+
139
+ # Reserved words such self, true, and false.
140
+ #
141
+ class Reserved < Name
142
+ def self.tag() :@kw end
143
+
144
+ def initialize(sexp)
145
+ super(sexp)
146
+ end
147
+
148
+ # A method for Visitor pattern.
149
+ # @param [Eval] evaluator the visitor of Visitor pattern.
150
+ # @return [void]
151
+ def accept(evaluator)
152
+ evaluator.reserved(self)
153
+ end
154
+ end
155
+
156
+ # Label such as `length:`.
157
+ #
158
+ class Label < Name
159
+ def self.tag() :@label end
160
+
161
+ def initialize(sexp)
162
+ super([:@label, sexp[1].chop, sexp[2]])
163
+ end
164
+
165
+ # @return [String] the label name.
166
+ # For example, if this object represents `length:`,
167
+ # then `"length"` (without a colon) is returned.
168
+ def name() super end
169
+
170
+ # A method for Visitor pattern.
171
+ # @param [Eval] evaluator the visitor of Visitor pattern.
172
+ # @return [void]
173
+ def accept(evaluator)
174
+ evaluator.label(self)
175
+ end
176
+ end
177
+
178
+ # Global variable.
179
+ class GlobalVariable < Name
180
+ def self.tag() :@gvar end
181
+
182
+ def initialize(sexp)
183
+ super(sexp)
184
+ end
185
+
186
+ # A method for Visitor pattern.
187
+ # @param [Eval] evaluator the visitor of Visitor pattern.
188
+ # @return [void]
189
+ def accept(evaluator)
190
+ evaluator.global_variable(self)
191
+ end
192
+ end
193
+
194
+ # Instance variable and class variable, such as `@x` and `@@x`.
195
+ # The value returned by `name` contains `@`.
196
+ #
197
+ class InstanceVariable < Name
198
+ def self.tags() [:@ivar, :@cvar] end
199
+
200
+ def initialize(sexp)
201
+ super(sexp)
202
+ end
203
+
204
+ # A method for Visitor pattern.
205
+ # @param [Eval] evaluator the visitor of Visitor pattern.
206
+ # @return [void]
207
+ def accept(evaluator)
208
+ evaluator.instance_variable(self)
209
+ end
210
+ end
211
+
212
+ # Method call without parentheses or arguments.
213
+ #
214
+ class VariableCall < IdentifierOrCall
215
+ def self.tag() :vcall end
216
+
217
+ def initialize(sexp)
218
+ super(sexp[1])
219
+ end
220
+
221
+ # A method for Visitor pattern.
222
+ # @param [Eval] evaluator the visitor of Visitor pattern.
223
+ # @return [void]
224
+ def accept(evaluator)
225
+ evaluator.variable_call(self)
226
+ end
227
+ end
228
+
229
+ # Reserved word `super`.
230
+ # `super` is a reserved word but no position (line numbre) is
231
+ # associated with it. Hence {Super} is not a subclass of
232
+ # {Reserved}.
233
+ #
234
+ class Super < ASTnode
235
+ def self.tag() :zsuper end
236
+
237
+ def initialize(sexp) end
238
+
239
+ # A method for Visitor pattern.
240
+ # @param [Eval] evaluator the visitor of Visitor pattern.
241
+ # @return [void]
242
+ def accept(evaluator)
243
+ evaluator.super_method(self)
244
+ end
245
+ end
246
+
247
+ # Numeric literal.
248
+ #
249
+ class Number < ASTnode
250
+ # @return [Numeric] the number.
251
+ attr_reader :value
252
+ # @return [Integer] the line number.
253
+ attr_reader :line_no
254
+ # @return [Integer] the column.
255
+ attr_reader :column
256
+
257
+ def self.tags()
258
+ [:@int, :@float]
259
+ end
260
+
261
+ def initialize(sexp)
262
+ @value = case sexp[0]
263
+ when :@int
264
+ if sexp[1].start_with? "0x"
265
+ sexp[1].hex
266
+ else
267
+ sexp[1].to_i
268
+ end
269
+ when :@float
270
+ sexp[1].to_f
271
+ else
272
+ raise "unknown symbol " + sexp[0]
273
+ end
274
+ @line_no = sexp[2][0].to_i
275
+ @column = sexp[2][1].to_i
276
+ end
277
+
278
+ # A method for Visitor pattern.
279
+ # @param [Eval] evaluator the visitor of Visitor pattern.
280
+ # @return [void]
281
+ def accept(evaluator)
282
+ evaluator.number(self)
283
+ end
284
+ end
285
+
286
+ # Helper module
287
+ #
288
+ module AstHelper
289
+ # @param [Array] s an S-expression.
290
+ # @return [ASTnode] an AST.
291
+ def to_node(s) ASTree.to_node(s) end
292
+
293
+ # @param [Array] s an array of S-expression.
294
+ # @return [Array<ASTnode>] ASTs.
295
+ def to_nodes(s)
296
+ raise "not an array: #{s}" unless s.class == Array
297
+ s.map {|e| ASTree.to_node(e) }
298
+ end
299
+
300
+ # @param [Array] s an S-expression.
301
+ # @param [Symbol] tag
302
+ # @return [Array] the S-expression if it starts with the tag.
303
+ # Otherwise, raise an error.
304
+ def has_tag?(s, tag)
305
+ raise "s-exp is not :#{tag.to_s}. #{s}" if !s.nil? && s[0] != tag
306
+ s
307
+ end
308
+ end
309
+
310
+ # Symbol.
311
+ #
312
+ class SymbolLiteral < ASTnode
313
+ include AstHelper
314
+ # @return [String] the symbol name.
315
+ # For example, if the object represents `:sym`, then
316
+ # `"sym"` (without a colon) is returned.
317
+ attr_reader :name
318
+ # @return [Integer] the line number.
319
+ attr_reader :line_no
320
+ # @return [Integer] the column.
321
+ attr_reader :column
322
+
323
+ def self.tags() [:symbol, :symbol_literal, :dyna_symbol] end
324
+
325
+ def initialize(sexp)
326
+ if sexp[0] == :dyna_symbol
327
+ init(has_tag?(sexp[1][0], :@tstring_content))
328
+ elsif sexp[0] == :symbol_literal
329
+ init(has_tag?(sexp[1], :symbol)[1])
330
+ else
331
+ init(has_tag?(sexp, :symbol)[1])
332
+ end
333
+ end
334
+
335
+ # @return [Symbol] a symbol the literal represents.
336
+ def to_sym
337
+ name.to_sym
338
+ end
339
+
340
+ # A method for Visitor pattern.
341
+ # @param [Eval] evaluator the visitor of Visitor pattern.
342
+ # @return [void]
343
+ def accept(evaluator)
344
+ evaluator.symbol(self)
345
+ end
346
+
347
+ private
348
+ def init(sexp)
349
+ @name = sexp[1]
350
+ @line_no = sexp[2][0].to_i
351
+ @column = sexp[2][1].to_i
352
+ end
353
+ end
354
+
355
+ # expressions, or progn in Lisp.
356
+ #
357
+ class Exprs < ASTnode
358
+ include AstHelper
359
+
360
+ # @return [Array<ASTnode>] the expressions.
361
+ # It may be an empty array.
362
+ attr_reader :expressions
363
+
364
+ # @param [Array] sexp an S-expression.
365
+ # @return [Exprs|ASTnode] an AST.
366
+ def self.make(sexp)
367
+ if sexp.length == 1
368
+ if sexp[0][0] == :void_stmt
369
+ Exprs.new([])
370
+ else
371
+ ASTree.to_node(sexp[0])
372
+ end
373
+ else
374
+ Exprs.new(sexp)
375
+ end
376
+ end
377
+
378
+ def initialize(sexp)
379
+ @expressions = to_nodes(sexp)
380
+ add_children(@expressions)
381
+ end
382
+
383
+ # A method for Visitor pattern.
384
+ # @param [Eval] evaluator the visitor of Visitor pattern.
385
+ # @return [void]
386
+ def accept(evaluator)
387
+ evaluator.exprs(self)
388
+ end
389
+ end
390
+
391
+ # Parenthesis.
392
+ #
393
+ class Paren < ASTnode
394
+ include AstHelper
395
+
396
+ # @return [ASTnode] the expression surrounded with the parentheses.
397
+ attr_reader :expression
398
+
399
+ def self.tag() :paren end
400
+
401
+ def initialize(sexp)
402
+ @expression = to_node(sexp[1][0])
403
+ add_child(@expression)
404
+ end
405
+
406
+ # A method for Visitor pattern.
407
+ # @param [Eval] evaluator the visitor of Visitor pattern.
408
+ # @return [void]
409
+ def accept(evaluator)
410
+ evaluator.paren(self)
411
+ end
412
+ end
413
+
414
+ # Array literal.
415
+ #
416
+ class ArrayLiteral < ASTnode
417
+ include AstHelper
418
+
419
+ # @return [Array<ASTnode>] the array elements.
420
+ attr_reader :elements
421
+
422
+ def self.tag() :array end
423
+
424
+ def initialize(sexp)
425
+ if sexp[1].nil?
426
+ @elements = []
427
+ else
428
+ @elements = to_nodes(sexp[1])
429
+ end
430
+ add_children(@elements)
431
+ end
432
+
433
+ # A method for Visitor pattern.
434
+ # @param [Eval] evaluator the visitor of Visitor pattern.
435
+ # @return [void]
436
+ def accept(evaluator)
437
+ evaluator.array(self)
438
+ end
439
+ end
440
+
441
+ # String interpolation.
442
+ #
443
+ class StringInterpolation < ASTnode
444
+ include AstHelper
445
+
446
+ # @return [Array<ASTnode>] the strings and the embedded expressions.
447
+ attr_reader :contents
448
+
449
+ def self.tag() :string_literal end
450
+
451
+ def initialize(sexp)
452
+ s = has_tag?(sexp[1], :string_content)
453
+ elements = s[1..s.length]
454
+ @contents = elements.map do |e|
455
+ case e[0]
456
+ when :string_embexpr
457
+ Exprs.make(e[1])
458
+ when :@tstring_content
459
+ StringLiteral.new(e)
460
+ else
461
+ raise "unknown string contents #{e[0]}"
462
+ end
463
+ end
464
+ add_children(@contents)
465
+ end
466
+
467
+ # A method for Visitor pattern.
468
+ # @param [Eval] evaluator the visitor of Visitor pattern.
469
+ # @return [void]
470
+ def accept(evaluator)
471
+ evaluator.string_interpolation(self)
472
+ end
473
+ end
474
+
475
+ # String literal.
476
+ #
477
+ class StringLiteral < ASTnode
478
+ # @return [String] the character string.
479
+ attr_reader :value
480
+
481
+ # @return [Integer] the line number.
482
+ attr_reader :line_no
483
+
484
+ # @return [Integer] the column.
485
+ attr_reader :column
486
+
487
+ def self.tags()
488
+ [:@tstring_content, :@CHAR]
489
+ end
490
+
491
+ def initialize(sexp)
492
+ @value = case sexp[0]
493
+ when :@CHAR
494
+ eval(sexp[1])
495
+ else # :@tstring_content
496
+ if sexp[1] =~ /\n$/
497
+ sexp[1] # maybe here document
498
+ else
499
+ eval( "<<_YAD_STRING_\n#{sexp[1]}\n_YAD_STRING_\n").chop
500
+ end
501
+ end
502
+ @line_no = sexp[2][0].to_i
503
+ @column = sexp[2][1].to_i
504
+ end
505
+
506
+ # A method for Visitor pattern.
507
+ # @param [Eval] evaluator the visitor of Visitor pattern.
508
+ # @return [void]
509
+ def accept(evaluator)
510
+ evaluator.string_literal(self)
511
+ end
512
+
513
+ # @param [ASTnode] node an AST.
514
+ # @return [ASTnode] the given AST.
515
+ # If it is a {StringInterpolation} with a single element,
516
+ # it is converted into a single {StringLiteral}.
517
+ def self.normalize(node)
518
+ if node.class == StringInterpolation
519
+ if node.contents.length == 1
520
+ return node.contents[0]
521
+ end
522
+ end
523
+ node
524
+ end
525
+ end
526
+
527
+ # Constant path reference, such as `Yadriggy::ConstPathRef`.
528
+ #
529
+ class ConstPathRef < ASTnode
530
+ include AstHelper
531
+
532
+ # @return [ConstPathRef|Const] the scope.
533
+ attr_reader :scope
534
+
535
+ # @return [Const] the class or module name.
536
+ attr_reader :name
537
+
538
+ def self.tags() [:const_path_ref, :top_const_ref] end
539
+
540
+ def initialize(sexp)
541
+ if sexp[0] == :const_path_ref || sexp[0] == :const_path_field
542
+ @scope = to_node(sexp[1])
543
+ @name = to_node(has_tag?(sexp[2], :@const))
544
+ add_child(@scope)
545
+ else
546
+ @scope = nil
547
+ @name = to_node(has_tag?(sexp[1], :@const))
548
+ end
549
+ add_child(@name)
550
+ end
551
+
552
+ # A method for Visitor pattern.
553
+ # @param [Eval] evaluator the visitor of Visitor pattern.
554
+ # @return [void]
555
+ def accept(evaluator)
556
+ evaluator.const_path_ref(self)
557
+ end
558
+ end
559
+
560
+ # Constant path reference as a L-value.
561
+ #
562
+ class ConstPathField < ConstPathRef
563
+ def self.tags() [:const_path_field, :top_const_field] end
564
+
565
+ def initialize(sexp)
566
+ super
567
+ end
568
+
569
+ # A method for Visitor pattern.
570
+ # @param [Eval] evaluator the visitor of Visitor pattern.
571
+ # @return [void]
572
+ def accept(evaluator)
573
+ evaluator.const_path_field(self)
574
+ end
575
+ end
576
+
577
+ # Unary expression.
578
+ # The splat operator `*` is also a unary operator.
579
+ #
580
+ class Unary < ASTnode
581
+ include AstHelper
582
+
583
+ # Returns the operator name.
584
+ # @return [Symbol] the operator name.
585
+ # If this is a unary plus/minus expression, `:+@` or `:-@` is
586
+ # returned.
587
+ attr_reader :op
588
+
589
+ # @return [ASTnode] the operand.
590
+ attr_reader :expr
591
+
592
+ def self.tag() :unary end
593
+
594
+ def initialize(sexp)
595
+ @op = sexp[1]
596
+ @expr = to_node(sexp[2])
597
+ add_child(@expr)
598
+ end
599
+
600
+ # Returns the real operator name.
601
+ # @return [Symbol] the real operator name.
602
+ # If the operator is a unary plus or minus, the method returns
603
+ # `:+` or `:-` although {#op} returns `:+@` or `:-@`.
604
+ #
605
+ def real_operator
606
+ case @op
607
+ when :+@
608
+ :+
609
+ when :-@
610
+ :-
611
+ else
612
+ @op
613
+ end
614
+ end
615
+
616
+ # A method for Visitor pattern.
617
+ # @param [Eval] evaluator the visitor of Visitor pattern.
618
+ # @return [void]
619
+ def accept(evaluator)
620
+ evaluator.unary(self)
621
+ end
622
+ end
623
+
624
+ # Binary expression.
625
+ #
626
+ class Binary < ASTnode
627
+ include AstHelper
628
+
629
+ # @return [ASTnode] the left operand.
630
+ attr_reader :left
631
+ # @return [Symbol] the operator.
632
+ attr_reader :op
633
+ # @return [ASTnode] the right operand.
634
+ attr_reader :right
635
+
636
+ def self.tag() :binary end
637
+
638
+ def initialize(sexp)
639
+ @left = to_node(sexp[1])
640
+ @op = sexp[2] # symbol
641
+ @right = to_node(sexp[3])
642
+ add_child(@left)
643
+ add_child(@right)
644
+ end
645
+
646
+ # A method for Visitor pattern.
647
+ # @param [Eval] evaluator the visitor of Visitor pattern.
648
+ # @return [void]
649
+ def accept(evaluator)
650
+ evaluator.binary(self)
651
+ end
652
+ end
653
+
654
+ # Range.
655
+ #
656
+ class Dots < Binary
657
+ def self.tags() [:dot2, :dot3] end
658
+
659
+ def initialize(sexp)
660
+ @left = to_node(sexp[1])
661
+ @op = if sexp[0] == :dot2 then :'..' else :'...' end
662
+ @right = to_node(sexp[2])
663
+ add_child(@left)
664
+ add_child(@right)
665
+ end
666
+
667
+ # A method for Visitor pattern.
668
+ # @param [Eval] evaluator the visitor of Visitor pattern.
669
+ # @return [void]
670
+ def accept(evaluator)
671
+ evaluator.dots(self)
672
+ end
673
+ end
674
+
675
+ # Assignment such as `=` and `+=`.
676
+ #
677
+ class Assign < Binary
678
+ def self.tags() [:assign, :opassign] end
679
+
680
+ def initialize(sexp)
681
+ case sexp[0]
682
+ when :assign
683
+ @left = to_node(sexp[1])
684
+ @op = :'='
685
+ @right = to_node(sexp[2])
686
+ when :opassign
687
+ @left = to_node(sexp[1])
688
+ @op = has_tag?(sexp[2], :@op)[1].to_sym
689
+ @right = to_node(sexp[3])
690
+ else
691
+ raise "unknown assignment " + sexp[0].to_s
692
+ end
693
+ add_child(@left)
694
+ add_child(@right)
695
+ end
696
+
697
+ # A method for Visitor pattern.
698
+ # @param [Eval] evaluator the visitor of Visitor pattern.
699
+ # @return [void]
700
+ def accept(evaluator)
701
+ evaluator.assign(self)
702
+ end
703
+ end
704
+
705
+ # Hash table.
706
+ #
707
+ class HashLiteral < ASTnode
708
+ include AstHelper
709
+
710
+ # Returns the elements in the hash table.
711
+ # @return [Array<Array<ASTnode>>] the hash elements.
712
+ # Each element is a key-value pair.
713
+ # For example, if the source code is
714
+ # `{key1 => value1, key2 => value2}`,
715
+ # then `[[key1, value2], [key2, value2]]` is returned.
716
+ attr_reader :pairs
717
+
718
+ def self.tags() [:hash, :bare_assoc_hash] end
719
+
720
+ def initialize(sexp)
721
+ if sexp[0] == :hash && sexp[1]
722
+ list = has_tag?(sexp[1], :assoclist_from_args)[1]
723
+ else
724
+ list = sexp[1]
725
+ end
726
+ if list.nil?
727
+ @pairs = []
728
+ else
729
+ @pairs = list.map do |e|
730
+ has_tag?(e, :assoc_new)
731
+ [to_node(e[1]), to_node(e[2])]
732
+ end
733
+ end
734
+ @pairs.map do |p|
735
+ add_child(p[0])
736
+ add_child(p[1])
737
+ end
738
+ end
739
+
740
+ # A method for Visitor pattern.
741
+ # @param [Eval] evaluator the visitor of Visitor pattern.
742
+ # @return [void]
743
+ def accept(evaluator)
744
+ evaluator.hash(self)
745
+ end
746
+ end
747
+
748
+ # Method call following parentheses.
749
+ # @see Command
750
+ # @see VariableCall
751
+ class Call < ASTnode
752
+ include AstHelper
753
+
754
+ # @return [ASTnode|nil] the callee object.
755
+ attr_reader :receiver
756
+
757
+ # Returns either `:"."`, `:"::"`, or `nil`.
758
+ # @return [Symbol] the symbol used as a separator between
759
+ # the receiver and the method name.
760
+ # It is either `:"."`, `:"::"`, or `nil`.
761
+ attr_reader :op
762
+
763
+ # @return [Identifier] the method name.
764
+ attr_reader :name
765
+
766
+ # @return [Array<ASTnode>] the method-call arguments.
767
+ attr_reader :args
768
+
769
+ # @return [ASTnode|nil] the argument preceded by an ampersand.
770
+ attr_reader :block_arg
771
+
772
+ # @return [ASTnode|nil] the block passed to the method.
773
+ attr_reader :block
774
+
775
+ # Makes an instance of {Call} with the given values for its
776
+ # instance variables.
777
+ # @param [ASTnode|nil] receiver the receiver object.
778
+ # @param [Symbol|nil] op the operator.
779
+ # @param [Identifeir] name the method name.
780
+ # @param [Array<ASTnode>] args the method-call arguments.
781
+ # @param [ASTnode|nil] block_arg the argument preceded by an ampersand.
782
+ # @param [ASTnode|nil] block the block passed to the method.
783
+ # @param [ASTnode] parent the parent node.
784
+ # @param [Boolean] link_from_children if true, links from children
785
+ # to `self` are added.
786
+ # @return [Call] the created object.
787
+ def self.make(receiver: nil, op: nil, name:, args: [],
788
+ block_arg: nil, block: nil,
789
+ parent:, link_from_children: false)
790
+ obj = self.allocate
791
+ obj.initialize2(receiver, op, name, args, block_arg, block,
792
+ parent, link_from_children)
793
+ end
794
+
795
+ # @private
796
+ def initialize2(recv, op, name, args, barg, blk,
797
+ parent, link_from_children)
798
+ @receiver = recv
799
+ @op = op
800
+ @name = name
801
+ @args = args
802
+ @block_arg = barg
803
+ @block = blk
804
+ @parent = parent
805
+ if link_from_children
806
+ add_child(@receiver)
807
+ add_child(@name)
808
+ add_children(@args)
809
+ add_child(@block_arg)
810
+ add_child(@block)
811
+ end
812
+ self
813
+ end
814
+
815
+ def self.tags() [:method_add_arg, :call, :method_add_block, :field] end
816
+
817
+ def initialize(sexp)
818
+ @args = []
819
+ @block_arg = nil
820
+ @block = nil
821
+
822
+ case sexp[0]
823
+ when :call, :field
824
+ initialize_call(sexp)
825
+ when :method_add_block
826
+ marg = sexp[1]
827
+ if marg[0] == :method_add_arg
828
+ initialize_method_arg(marg[1], marg[2])
829
+ else
830
+ initialize_method_arg(marg, [])
831
+ end
832
+ @block = to_node(sexp[2])
833
+ add_child(@block)
834
+ else
835
+ initialize_method_arg(sexp[1], sexp[2])
836
+ end
837
+ end
838
+
839
+ # A method for Visitor pattern.
840
+ # @param [Eval] evaluator the visitor of Visitor pattern.
841
+ # @return [void]
842
+ def accept(evaluator)
843
+ evaluator.call(self)
844
+ end
845
+
846
+ private
847
+
848
+ def initialize_method_arg(msg, arg_paren)
849
+ if msg[0] == :fcall
850
+ initialize_call([:call, nil, nil, msg[1]])
851
+ elsif msg[0] == :call
852
+ initialize_call(msg)
853
+ else
854
+ raise 'unknown pattern ' + msg.to_s
855
+ end
856
+
857
+ if arg_paren.length > 0
858
+ args_block = has_tag?(arg_paren, :arg_paren)[1]
859
+ unless args_block.nil?
860
+ initialize_args(args_block)
861
+ end
862
+ end
863
+ end
864
+
865
+ def initialize_call(sexp)
866
+ @receiver = to_node(sexp[1])
867
+ @op = sexp[2] # :"." or :"::" or nil.
868
+ @name = to_node(has_tag?(sexp[3], :@ident))
869
+ add_child(@receiver)
870
+ add_child(@name)
871
+ end
872
+
873
+ def initialize_args(args_block)
874
+ args = has_tag?(args_block, :args_add_block)[1]
875
+ args2 = initialize_star_arg(args)
876
+ @args = to_nodes(args2)
877
+ @block_arg = if args_block[2]
878
+ to_node(args_block[2])
879
+ else
880
+ nil
881
+ end
882
+ add_children(@args)
883
+ add_child(@block_arg)
884
+ end
885
+
886
+ def initialize_star_arg(args)
887
+ if args[0] == :args_add_star
888
+ new_args = initialize_star_arg(args[1]) + [[:unary, :*, args[2]]]
889
+ for i in 3...args.size
890
+ new_args << args[i]
891
+ end
892
+ new_args
893
+ else
894
+ args
895
+ end
896
+ end
897
+ end
898
+
899
+ # A method call without parentheses.
900
+ #
901
+ class Command < Call
902
+ def self.tags() [:command, :command_call] end
903
+
904
+ def initialize(sexp)
905
+ if sexp[0] == :command
906
+ initialize_call([:call, nil, nil, sexp[1]])
907
+ arg_exp = sexp[2]
908
+ elsif sexp[0] == :command_call
909
+ initialize_call([:call, sexp[1], sexp[2], sexp[3]])
910
+ arg_exp = sexp[4]
911
+ else
912
+ raise "unknown pattern " + sexp.to_s
913
+ end
914
+
915
+ if arg_exp[0] == :args_add_block
916
+ initialize_args(arg_exp)
917
+ else
918
+ @args = to_nodes(arg_exp)
919
+ @block_arg = nil
920
+ add_children(@args)
921
+ end
922
+
923
+ @block = nil
924
+ end
925
+
926
+ # A method for Visitor pattern.
927
+ # @param [Eval] evaluator the visitor of Visitor pattern.
928
+ # @return [void]
929
+ def accept(evaluator)
930
+ evaluator.command(self)
931
+ end
932
+ end
933
+
934
+ # Array reference.
935
+ #
936
+ class ArrayRef < ASTnode
937
+ include AstHelper
938
+
939
+ # @return [ASTnode] the array object.
940
+ attr_reader :array
941
+
942
+ # @return [Array<ASTnode>] all the comma-separated indexes.
943
+ # It may be an empty array.
944
+ attr_reader :indexes
945
+
946
+ def self.tag() :aref end
947
+
948
+ def initialize(sexp)
949
+ @array = to_node(sexp[1])
950
+ args_block = sexp[2]
951
+ if args_block.nil?
952
+ @indexes = []
953
+ else
954
+ args = has_tag?(args_block, :args_add_block)[1]
955
+ @indexes = to_nodes(args)
956
+ end
957
+
958
+ add_child(@array)
959
+ add_children(@indexes)
960
+ end
961
+
962
+ # A method for Visitor pattern.
963
+ # @param [Eval] evaluator the visitor of Visitor pattern.
964
+ # @return [void]
965
+ def accept(evaluator)
966
+ evaluator.array_ref(self)
967
+ end
968
+ end
969
+
970
+ # Array reference as L-value.
971
+ #
972
+ class ArrayRefField < ArrayRef
973
+ def self.tag() :aref_field end
974
+
975
+ def initialize(sexp)
976
+ super sexp
977
+ end
978
+
979
+ # A method for Visitor pattern.
980
+ # @param [Eval] evaluator the visitor of Visitor pattern.
981
+ # @return [void]
982
+ def accept(evaluator)
983
+ evaluator.array_ref_field(self)
984
+ end
985
+ end
986
+
987
+ # if, unless, modifier if/unless, and ternary if (`?:`).
988
+ #
989
+ class Conditional < ASTnode
990
+ include AstHelper
991
+ # @return [Symbol] `:if`, `:unless`, `:if_mod`, `:unless_mod`,
992
+ # or `:ifop`.
993
+ attr_reader :op
994
+
995
+ # @return [ASTnode] the condition expression.
996
+ attr_reader :cond
997
+
998
+ # @return [ASTnode] the then-expressin.
999
+ attr_reader :then
1000
+
1001
+ # Returns the elsif-expressions.
1002
+ # @return [Array<ASTnode>] an array of the elsif-expressions.
1003
+ # It may be an empty array.
1004
+ attr_reader :all_elsif
1005
+
1006
+ # @return [ASTnode|nil] the else-expression.
1007
+ attr_reader :else
1008
+
1009
+ def self.tags() [:if, :unless, :ifop, :if_mod, :unless_mod] end
1010
+
1011
+ def initialize(sexp)
1012
+ @op = sexp[0]
1013
+ @cond = to_node(sexp[1])
1014
+ @all_elsif = []
1015
+ case @op
1016
+ when :ifop # ternary if
1017
+ @then = to_node(sexp[2])
1018
+ @else = to_node(sexp[3])
1019
+ when :if_mod, :unless_mod # modifier if/unless
1020
+ @then = to_node(sexp[2])
1021
+ @else = nil
1022
+ else # if/unless
1023
+ @then = Exprs.make(sexp[2])
1024
+ initialize_else(sexp[3])
1025
+ end
1026
+ add_child(@cond)
1027
+ add_child(@then)
1028
+ add_child(@else)
1029
+ @all_elsif.each do |pair|
1030
+ pair.each { |e| add_child(e) }
1031
+ end
1032
+ end
1033
+
1034
+ # A method for Visitor pattern.
1035
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1036
+ # @return [void]
1037
+ def accept(evaluator)
1038
+ evaluator.conditional(self)
1039
+ end
1040
+
1041
+ private
1042
+ def initialize_else(else_part)
1043
+ if else_part.nil?
1044
+ @else = nil
1045
+ elsif else_part[0] == :elsif
1046
+ @all_elsif << [to_node(else_part[1]), Exprs.make(else_part[2])]
1047
+ initialize_else(else_part[3])
1048
+ else
1049
+ @else = Exprs.make(has_tag?(else_part, :else)[1])
1050
+ end
1051
+ end
1052
+ end
1053
+
1054
+ # while, until, and modifier while/until.
1055
+ #
1056
+ class Loop < ASTnode
1057
+ include AstHelper
1058
+
1059
+ # @return [Symbol] `:while`, `:until`, `:while_mod`, or `:until_mod`.
1060
+ attr_reader :op
1061
+
1062
+ # @return [ASTnode] the condition expression.
1063
+ attr_reader :cond
1064
+
1065
+ # @return [ASTnode] the loop body.
1066
+ attr_reader :body
1067
+
1068
+ def self.tags() [:while, :until, :while_mod, :until_mod] end
1069
+
1070
+ def initialize(sexp)
1071
+ @op = sexp[0]
1072
+ @cond = to_node(sexp[1])
1073
+ case @op
1074
+ when :while_mod, :until_mod
1075
+ @body = to_node(sexp[2])
1076
+ else
1077
+ @body = Exprs.make(sexp[2])
1078
+ end
1079
+ add_child(@cond)
1080
+ add_child(@body)
1081
+ end
1082
+
1083
+ # A method for Visitor pattern.
1084
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1085
+ # @return [void]
1086
+ def accept(evaluator)
1087
+ evaluator.loop(self)
1088
+ end
1089
+
1090
+ # Returns the real operator name.
1091
+ # @return [Symbol] the real operator name, `while` or `until`.
1092
+ def real_operator
1093
+ case @op
1094
+ when :while_mod
1095
+ :while
1096
+ when :until_mod
1097
+ :until
1098
+ else
1099
+ @op
1100
+ end
1101
+ end
1102
+ end
1103
+
1104
+ # For statement.
1105
+ #
1106
+ class ForLoop < ASTnode
1107
+ include AstHelper
1108
+
1109
+ # @return [Array<ASTnode>] the variables.
1110
+ attr_reader :vars
1111
+
1112
+ # @return [ASTnode] the elements.
1113
+ attr_reader :set
1114
+
1115
+ # @return [ASTnode] the loop body.
1116
+ attr_reader :body
1117
+
1118
+ def self.tag() :for end
1119
+
1120
+ def initialize(sexp)
1121
+ if sexp[1][0] == :var_field
1122
+ @vars = [ to_node(sexp[1][1]) ]
1123
+ else
1124
+ @vars = to_nodes(sexp[1])
1125
+ end
1126
+ @set = to_node(sexp[2])
1127
+ @body = Exprs.make(sexp[3])
1128
+ add_children(@vars)
1129
+ add_child(@set)
1130
+ add_child(@body)
1131
+ end
1132
+
1133
+ # A method for Visitor pattern.
1134
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1135
+ # @return [void]
1136
+ def accept(evaluator)
1137
+ evaluator.for_loop(self)
1138
+ end
1139
+ end
1140
+
1141
+ # break, next, redo, or retry.
1142
+ #
1143
+ class Break < ASTnode
1144
+ include AstHelper
1145
+ # @return [Symbol] `:break`, `:next`, `:redo`, or `:retry`.
1146
+ attr_reader :op
1147
+ # @return [Array<ASTnode>] an array of the break/next arguments.
1148
+ attr_reader :values
1149
+
1150
+ def self.tags() [:break, :next, :redo, :retry] end
1151
+
1152
+ def initialize(sexp)
1153
+ @op = sexp[0]
1154
+ if @op == :break || @op == :next
1155
+ if sexp[1].size == 0
1156
+ @values = []
1157
+ else
1158
+ values = has_tag?(sexp[1], :args_add_block)[1]
1159
+ @values = to_nodes(values)
1160
+ end
1161
+ add_children(@values)
1162
+ else
1163
+ @values = []
1164
+ end
1165
+ end
1166
+
1167
+ # A method for Visitor pattern.
1168
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1169
+ # @return [void]
1170
+ def accept(evaluator)
1171
+ evaluator.break_out(self)
1172
+ end
1173
+ end
1174
+
1175
+ # Return.
1176
+ #
1177
+ class Return < ASTnode
1178
+ include AstHelper
1179
+ # Gets the returned values.
1180
+ # @return [Array<ASTnode>] the returned values.
1181
+ # It may be an empty array.
1182
+ attr_reader :values
1183
+
1184
+ def self.tags() [:return, :return0] end
1185
+
1186
+ def initialize(sexp)
1187
+ if sexp.length < 2 # return0
1188
+ @values = []
1189
+ else
1190
+ values = has_tag?(sexp[1], :args_add_block)[1]
1191
+ @values = to_nodes(values)
1192
+ add_children(@values)
1193
+ end
1194
+ end
1195
+
1196
+ # A method for Visitor pattern.
1197
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1198
+ # @return [void]
1199
+ def accept(evaluator)
1200
+ evaluator.return_values(self)
1201
+ end
1202
+ end
1203
+
1204
+ # @abstract
1205
+ #
1206
+ class Parameters < ASTnode
1207
+ include AstHelper
1208
+ # @return [Array<ASTnode>] the parameter list.
1209
+ attr_reader :params
1210
+ # @return [Array<Array<ASTnode>>] the list of parameters with default values.
1211
+ # Each element is `[name, value]`.
1212
+ attr_reader :optionals
1213
+ # @return [ASTnode|nil] the parameter preceded by an asterisk (`*`).
1214
+ attr_reader :rest_of_params
1215
+ # @return [Array<ASTnode>] the parameters following the parameter
1216
+ # with asterisk (`*`).
1217
+ attr_reader :params_after_rest
1218
+ # @return [Array<Array<ASTnode>>] the keyword parameters.
1219
+ # Each element is `[keyword, value]`.
1220
+ attr_reader :keywords
1221
+ # @return [ASTnode|nil] the parameters preceded by two asterisks (`**`).
1222
+ attr_reader :rest_of_keywords
1223
+ # @return [ASTnode|nil] the parameter preceded by an ampersand (`&`).
1224
+ attr_reader :block_param
1225
+
1226
+ # @param [Array] params `[:params, ... ]`.
1227
+ def initialize(params)
1228
+ initialize_params(params)
1229
+ end
1230
+
1231
+ def initialize_params(params)
1232
+ if params.nil?
1233
+ @params = []
1234
+ @optionals = []
1235
+ @rest_of_params = nil
1236
+ @params_after_rest = []
1237
+ @keywords = []
1238
+ @rest_of_keywords = nil
1239
+ @block_param = nil
1240
+ else
1241
+ if params[1].nil?
1242
+ @params = []
1243
+ else
1244
+ @params = to_nodes(params[1])
1245
+ add_children(@params)
1246
+ end
1247
+
1248
+ if params[2].nil?
1249
+ @optionals = []
1250
+ else
1251
+ # [[name, value], ...]
1252
+ @optionals = params[2].map {|p| to_nodes(p) }
1253
+ @optionals.map {|p| add_children(p) }
1254
+ end
1255
+
1256
+ if params[3].nil?
1257
+ @rest_of_params = nil
1258
+ else
1259
+ @rest_of_params = to_node(has_tag?(params[3], :rest_param)[1])
1260
+ add_child(@rest_of_params)
1261
+ end
1262
+
1263
+ if params[4].nil?
1264
+ @params_after_rest = []
1265
+ else
1266
+ @params_after_rest = to_nodes(params[4])
1267
+ add_children(@params_after_rest)
1268
+ end
1269
+
1270
+ if params[5].nil?
1271
+ @keywords = []
1272
+ else
1273
+ # [[keyword, value], ...] value may be nil
1274
+ @keywords = params[5].map do |p|
1275
+ default_value = if p[1] then to_node(p[1]) else nil end
1276
+ [ to_node(p[0]), default_value ]
1277
+ end
1278
+ @keywords.map {|p| add_children(p) }
1279
+ end
1280
+
1281
+ if params[6].nil?
1282
+ @rest_of_keywords = nil
1283
+ else
1284
+ rkeys = if params[6][0] == :@ident
1285
+ params[6] # Ruby 2.4 or earlier
1286
+ else
1287
+ has_tag?(params[6], :kwrest_param)[1]
1288
+ end
1289
+ @rest_of_keywords = to_node(has_tag?(rkeys, :@ident))
1290
+ end
1291
+
1292
+ if params[7].nil?
1293
+ @block_param = nil
1294
+ else
1295
+ @block_param = to_node(has_tag?(params[7], :blockarg)[1])
1296
+ add_child(@block_param)
1297
+ end
1298
+ end
1299
+ end
1300
+ end
1301
+
1302
+ # Block.
1303
+ #
1304
+ class Block < Parameters
1305
+ # @return [ASTnode] the body.
1306
+ attr_reader :body
1307
+ # @return [Rescue|nil] the rescue clause.
1308
+ attr_reader :rescue
1309
+
1310
+ def self.tags() [:brace_block, :do_block] end
1311
+
1312
+ def initialize(sexp)
1313
+ var = has_tag?(sexp[1], :block_var)
1314
+ if var.nil?
1315
+ params = nil
1316
+ else
1317
+ params = has_tag?(var[1], :params)
1318
+ end
1319
+ initialize_vars(params, sexp[2])
1320
+ end
1321
+
1322
+ def initialize_vars(params, body)
1323
+ initialize_params(params)
1324
+ if body.is_a?(Array) && body.length > 0 && body[0] == :bodystmt
1325
+ bodystmnt = body[1]
1326
+ @rescue = Rescue.make(body[2], body[3], body[4])
1327
+ else # if Ruby 2.4 or earlier
1328
+ bodystmnt = body
1329
+ @rescue = nil
1330
+ end
1331
+ @body = Exprs.make(bodystmnt)
1332
+ add_child(@body)
1333
+ add_child(@rescue)
1334
+ end
1335
+
1336
+ # A method for Visitor pattern.
1337
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1338
+ # @return [void]
1339
+ def accept(evaluator)
1340
+ evaluator.block(self)
1341
+ end
1342
+ end
1343
+
1344
+ # A lambda expression such as `-> (x) {x + 1}`.
1345
+ #
1346
+ # `lambda {|x|x+1}` is parsed as a call to `lambda` with
1347
+ # an argument `{|x|x + 1}`. So it is an instance of {Call}.
1348
+ #
1349
+ class Lambda < Block
1350
+ def self.tag() :lambda end
1351
+
1352
+ def initialize(sexp)
1353
+ if sexp[1][0] == :paren
1354
+ params = sexp[1][1]
1355
+ else
1356
+ params = sexp[1]
1357
+ end
1358
+ initialize_vars(params, sexp[2])
1359
+ end
1360
+
1361
+ # A method for Visitor pattern.
1362
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1363
+ # @return [void]
1364
+ def accept(evaluator)
1365
+ evaluator.lambda_expr(self)
1366
+ end
1367
+ end
1368
+
1369
+ # begin-rescue-ensure.
1370
+ #
1371
+ # `raise` is parsed as a method call (or a command).
1372
+ #
1373
+ class Rescue < ASTnode
1374
+ include AstHelper
1375
+ # @return [Array<ASTnode>] the exception types. It may be empty.
1376
+ attr_reader :types
1377
+ # @return [ASTnode|nil] the rescue parameter.
1378
+ attr_reader :parameter
1379
+ # @return [ASTnode|nil] the body of the rescue clause.
1380
+ attr_reader :body
1381
+ # @return [Rescue|nil] the rest of rescue clauses.
1382
+ # The returned object's {#else} and {#ensure} are `nil`.
1383
+ attr_reader :nested_rescue
1384
+ # @return [ASTnode|nil] the else clause.
1385
+ attr_reader :else
1386
+ # @return [ASTnode|nil] the ensure clause.
1387
+ attr_reader :ensure
1388
+
1389
+ def self.tag() :rescue end
1390
+
1391
+ def self.make(rescue_expr, else_expr, ensure_expr)
1392
+ if rescue_expr.nil? && else_expr.nil? && ensure_expr.nil?
1393
+ nil
1394
+ else
1395
+ Rescue.new(rescue_expr, else_expr, ensure_expr)
1396
+ end
1397
+ end
1398
+
1399
+ def initialize(rescue_expr, else_expr=nil, ensure_expr=nil)
1400
+ if rescue_expr.nil?
1401
+ @types = []
1402
+ @parameter = nil
1403
+ @body = nil
1404
+ @nested_rescue = nil
1405
+ else
1406
+ expr = has_tag?(rescue_expr, :rescue)
1407
+ rescue_clause = expr[1]
1408
+ if rescue_clause.nil?
1409
+ @types = []
1410
+ elsif rescue_clause[0] == :mrhs_new_from_args
1411
+ types1 = to_nodes(rescue_clause[1])
1412
+ @types = types1 << to_node(rescue_clause[2])
1413
+ else
1414
+ @types = to_nodes(rescue_clause)
1415
+ end
1416
+
1417
+ if expr[2].nil?
1418
+ @parameter = nil
1419
+ else
1420
+ @parameter = to_node(has_tag?(has_tag?(expr[2], :var_field)[1],
1421
+ :@ident))
1422
+ end
1423
+
1424
+ @body = Exprs.make(expr[3])
1425
+ @nested_rescue = to_node(expr[4])
1426
+ add_children(@types)
1427
+ add_child(@parameter)
1428
+ add_child(@body)
1429
+ add_child(@nested_rescue)
1430
+ end
1431
+
1432
+ if else_expr.nil?
1433
+ @else = nil
1434
+ else
1435
+ elsexpr = has_tag?(else_expr, :else)
1436
+ @else = Exprs.make(elsexpr[1])
1437
+ add_child(@else)
1438
+ end
1439
+
1440
+ if ensure_expr.nil?
1441
+ @ensure = nil
1442
+ else
1443
+ ensexpr = has_tag?(ensure_expr, :ensure)
1444
+ @ensure = Exprs.make(ensexpr[1])
1445
+ add_child(@ensure)
1446
+ end
1447
+ end
1448
+
1449
+ # A method for Visitor pattern.
1450
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1451
+ # @return [void]
1452
+ def accept(evaluator)
1453
+ evaluator.rescue_end(self)
1454
+ end
1455
+
1456
+ # @return [Boolean] true if the rescue clause is included.
1457
+ def has_rescue?
1458
+ !@body.nil?
1459
+ end
1460
+
1461
+ # @return [Boolean] true if the else clause is included.
1462
+ def has_else?
1463
+ !@else.nil?
1464
+ end
1465
+
1466
+ # @return [Boolean] true if the ensure clause is included.
1467
+ def has_ensure?
1468
+ !@ensure.nil?
1469
+ end
1470
+ end
1471
+
1472
+ # begin-end.
1473
+ #
1474
+ class BeginEnd < ASTnode
1475
+ include AstHelper
1476
+ # @return [Exprs|ASTnode] the body.
1477
+ attr_reader :body
1478
+ # @return [Rescue|nil] the rescue clause.
1479
+ attr_reader :rescue
1480
+
1481
+ def self.tag() :begin end
1482
+
1483
+ def initialize(sexp)
1484
+ bodystmt = has_tag?(sexp[1], :bodystmt)
1485
+ @body = Exprs.make(bodystmt[1])
1486
+ @rescue = Rescue.make(bodystmt[2], bodystmt[3], bodystmt[4])
1487
+ add_child(@body)
1488
+ add_child(@rescue)
1489
+ end
1490
+
1491
+ # A method for Visitor pattern.
1492
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1493
+ # @return [void]
1494
+ def accept(evaluator)
1495
+ evaluator.begin_end(self)
1496
+ end
1497
+ end
1498
+
1499
+ # Method definition or a singular method definition.
1500
+ #
1501
+ class Def < Parameters
1502
+ # @return [ASTnode|nil] the object if the definition is a singular method.
1503
+ attr_reader :singular
1504
+ # @return [Identifier] the method name.
1505
+ attr_reader :name
1506
+ # @return [Exprs|ASTnode] the body.
1507
+ attr_reader :body
1508
+ # @return [Rescue|nil] the rescue clause.
1509
+ attr_reader :rescue
1510
+
1511
+ def self.tags() [:def, :defs] end
1512
+
1513
+ def initialize(sexp)
1514
+ if sexp[0] == :def
1515
+ @singular = nil
1516
+ offset = 0
1517
+ else
1518
+ @singular = to_node(sexp[1])
1519
+ add_child(@singular)
1520
+ offset = 2
1521
+ end
1522
+
1523
+ def_name = sexp[1 + offset]
1524
+ @name = if def_name[0] == :@op
1525
+ to_node(def_name)
1526
+ else
1527
+ to_node(has_tag?(def_name, :@ident))
1528
+ end
1529
+ add_child(@name)
1530
+
1531
+ params = sexp[2 + offset]
1532
+ if !params.nil? && params[0] == :paren
1533
+ super(params[1])
1534
+ else
1535
+ super(params)
1536
+ end
1537
+
1538
+ bodystmt = has_tag?(sexp[3 + offset], :bodystmt)
1539
+ @body = Exprs.make(bodystmt[1])
1540
+ @rescue = Rescue.make(bodystmt[2], bodystmt[3], bodystmt[4])
1541
+ add_child(@body)
1542
+ add_child(@rescue)
1543
+ end
1544
+
1545
+ # A method for Visitor pattern.
1546
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1547
+ # @return [void]
1548
+ def accept(evaluator)
1549
+ evaluator.define(self)
1550
+ end
1551
+ end
1552
+
1553
+ # Module definition.
1554
+ #
1555
+ class ModuleDef < ASTnode
1556
+ include AstHelper
1557
+ # @return [Const|ConstPathRef] the module name.
1558
+ attr_reader :name
1559
+ # @return [Exprs|ASTnode] the body.
1560
+ attr_reader :body
1561
+ # @return [Rescue|nil] the rescue clause.
1562
+ attr_reader :rescue
1563
+
1564
+ def self.tag() :module end
1565
+
1566
+ def initialize(sexp)
1567
+ @name = to_node(sexp[1]) # Const or ConstPathRef
1568
+ add_child(@name)
1569
+ initialize_body(has_tag?(sexp[2], :bodystmt))
1570
+ end
1571
+
1572
+ def initialize_body(bodystmt)
1573
+ @body = Exprs.make(bodystmt[1] - [[:void_stmt]])
1574
+ @rescue = Rescue.make(bodystmt[2], bodystmt[3], bodystmt[4])
1575
+ add_child(@body)
1576
+ add_child(@rescue)
1577
+ end
1578
+
1579
+ # A method for Visitor pattern.
1580
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1581
+ # @return [void]
1582
+ def accept(evaluator)
1583
+ evaluator.module_def(self)
1584
+ end
1585
+ end
1586
+
1587
+ # Class definition.
1588
+ #
1589
+ class ClassDef < ModuleDef
1590
+ # @return [ASTnode|nil] the super class.
1591
+ attr_reader :superclass
1592
+
1593
+ def self.tag() :class end
1594
+
1595
+ def initialize(sexp)
1596
+ @name = to_node(sexp[1]) # Const or ConstPathRef
1597
+ add_child(@name)
1598
+ @superclass = to_node(sexp[2])
1599
+ add_child(@superclass)
1600
+ initialize_body(has_tag?(sexp[3], :bodystmt))
1601
+ end
1602
+
1603
+ # A method for Visitor pattern.
1604
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1605
+ # @return [void]
1606
+ def accept(evaluator)
1607
+ evaluator.class_def(self)
1608
+ end
1609
+ end
1610
+
1611
+ # Singular class definition.
1612
+ #
1613
+ class SingularClassDef < ModuleDef
1614
+ def self.tag() :sclass end
1615
+
1616
+ def initialize(sexp)
1617
+ @name = to_node(sexp[1]) # Keyword, VariableCall, ...
1618
+ add_child(@name)
1619
+ initialize_body(has_tag?(sexp[2], :bodystmt))
1620
+ end
1621
+
1622
+ # @return [Keyword|VariableCall|ASTnode] self, the object, ...
1623
+ def name() super end
1624
+
1625
+ # A method for Visitor pattern.
1626
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1627
+ # @return [void]
1628
+ def accept(evaluator)
1629
+ evaluator.singular_class_def(self)
1630
+ end
1631
+ end
1632
+
1633
+ # Program.
1634
+ #
1635
+ class Program < ASTnode
1636
+ include AstHelper
1637
+ # @return [Exprs|ASTnode] the program elements.
1638
+ attr_reader :elements
1639
+
1640
+ def self.tag() :program end
1641
+
1642
+ def initialize(sexp)
1643
+ @elements = Exprs.make(sexp[1])
1644
+ add_child(@elements)
1645
+ end
1646
+
1647
+ # A method for Visitor pattern.
1648
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1649
+ # @return [void]
1650
+ def accept(evaluator)
1651
+ evaluator.program(self)
1652
+ end
1653
+ end
1654
+
1655
+ # @private
1656
+ # A table of reified abstract syntax trees.
1657
+ # It is used for guaranteeing the uniqueness
1658
+ # of ASTree objects.
1659
+ #
1660
+ class ASTreeTable
1661
+ # @return [Hash] all the elements.
1662
+ attr_reader :trees
1663
+
1664
+ def initialize()
1665
+ @trees = {}
1666
+ end
1667
+
1668
+ # Records a key-value pair.
1669
+ # @param [Proc|Method|UnboundMethod] context the key.
1670
+ # @param [ASTnode] ast the value.
1671
+ def []=(context, ast)
1672
+ @trees[context] = ast
1673
+ end
1674
+
1675
+ # Deletes a key-value pair.
1676
+ # @param [Proc|Method|UnboundMethod] context the key.
1677
+ def delete(context)
1678
+ @trees.delete(context)
1679
+ end
1680
+
1681
+ # Gets the value associated with the key.
1682
+ # @param [Proc|Method|UnboundMethod] context the key.
1683
+ def [](context)
1684
+ @trees[context]
1685
+ end
1686
+
1687
+ # Executes a block once for each element.
1688
+ def each(&blk)
1689
+ @trees.each_value(&blk)
1690
+ end
1691
+ end
1692
+
1693
+ # Abstract syntax tree (AST).
1694
+ #
1695
+ class ASTree < ASTnode
1696
+ # @return [ASTreeTable] all the reified ASTs.
1697
+ attr_reader :astrees
1698
+
1699
+ # @return [Method|Proc] the Method or Proc object given
1700
+ # for the reification.
1701
+ attr_reader :context
1702
+
1703
+ # @return [String] the source file name.
1704
+ attr_reader :file_name
1705
+
1706
+ # @return [ASTnode] the AST.
1707
+ attr_reader :tree
1708
+
1709
+ def initialize(ast_table, proc, file, sexp)
1710
+ unless proc.is_a?(Proc) || proc.is_a?(Method) ||
1711
+ proc.is_a?(UnboundMethod)
1712
+ raise "unknown context #{proc.class.name}"
1713
+ end
1714
+
1715
+ @astrees = ast_table # ASTreeTable
1716
+ @context = proc # Proc or Method
1717
+ @file_name = file
1718
+ @tree = ASTree.to_node(sexp)
1719
+ add_child(@tree)
1720
+ @astrees[proc] = self
1721
+ end
1722
+
1723
+ def pretty_print(pp)
1724
+ Yadriggy::simpler_pretty_print(pp, self, "@astrees")
1725
+ end
1726
+
1727
+ # Gets the abstract syntax tree of the given procedure.
1728
+ #
1729
+ # @param [Proc|Method|UnboundMethod] proc the procedure or method.
1730
+ # @return [ASTree|nil] the reified AST.
1731
+ # @see Yadriggy.reify
1732
+ def reify(proc)
1733
+ ast_obj = @astrees[proc]
1734
+ unless ast_obj.nil?
1735
+ ast_obj
1736
+ else
1737
+ ast = SourceCode.get_sexp(proc)
1738
+ ast && ast[1] && ASTree.new(@astrees, proc, ast[0], ast[1])
1739
+ end
1740
+ end
1741
+
1742
+ # A method for Visitor pattern.
1743
+ # @param [Eval] evaluator the visitor of Visitor pattern.
1744
+ # @return [void]
1745
+ def accept(evaluator)
1746
+ evaluator.astree(self)
1747
+ end
1748
+
1749
+ @tags = {
1750
+ Const.tag => Const,
1751
+ Reserved.tag => Reserved,
1752
+ Label.tag => Label,
1753
+ GlobalVariable.tag => GlobalVariable,
1754
+ VariableCall.tag => VariableCall,
1755
+ Super.tag => Super,
1756
+ Paren.tag => Paren,
1757
+ ArrayLiteral.tag => ArrayLiteral,
1758
+ StringInterpolation.tag => StringInterpolation,
1759
+ Unary.tag => Unary,
1760
+ Binary.tag => Binary,
1761
+ ArrayRef.tag => ArrayRef,
1762
+ ArrayRefField.tag => ArrayRefField,
1763
+ ForLoop.tag => ForLoop,
1764
+ Lambda.tag => Lambda,
1765
+ Rescue.tag => Rescue,
1766
+ BeginEnd.tag => BeginEnd,
1767
+ ModuleDef.tag => ModuleDef,
1768
+ ClassDef.tag => ClassDef,
1769
+ SingularClassDef.tag => SingularClassDef,
1770
+ Program.tag => Program
1771
+ }
1772
+
1773
+ def self.append_tags(clazz)
1774
+ clazz.tags.each {|t| @tags[t] = clazz }
1775
+ end
1776
+
1777
+ append_tags(Identifier)
1778
+ append_tags(SymbolLiteral)
1779
+ append_tags(InstanceVariable)
1780
+ append_tags(Number)
1781
+ append_tags(StringLiteral)
1782
+ append_tags(ConstPathRef)
1783
+ append_tags(ConstPathField)
1784
+ append_tags(Dots)
1785
+ append_tags(Assign)
1786
+ append_tags(HashLiteral)
1787
+ append_tags(Call)
1788
+ append_tags(Command)
1789
+ append_tags(Conditional)
1790
+ append_tags(Loop)
1791
+ append_tags(Break)
1792
+ append_tags(Return)
1793
+ append_tags(Block)
1794
+ append_tags(Def)
1795
+
1796
+ def self.to_node(sexp)
1797
+ if sexp.nil?
1798
+ nil
1799
+ elsif sexp[0] == :var_ref || sexp[0] == :var_field ||
1800
+ sexp[0] == :const_ref
1801
+ to_node(sexp[1])
1802
+ else
1803
+ klass = @tags[sexp[0]]
1804
+ if klass.nil?
1805
+ sexp_name = if sexp.is_a?(Array)
1806
+ sexp[0].to_s
1807
+ else
1808
+ ':' + sexp.to_s
1809
+ end
1810
+ raise "unknown s-expression " + sexp_name
1811
+ else
1812
+ node = klass.new(sexp)
1813
+ StringLiteral.normalize(node)
1814
+ end
1815
+ end
1816
+ end
1817
+ end
1818
+
1819
+ private
1820
+ def self.simpler_pretty_print(pp, obj, key)
1821
+ pp.object_address_group(obj) do
1822
+ obj.instance_variables.each do |v|
1823
+ pp.breakable
1824
+ v = v.to_s if Symbol === v
1825
+ pp.text(v)
1826
+ pp.text('=')
1827
+ pp.group(1) do
1828
+ if v == key
1829
+ pp.text('...')
1830
+ else
1831
+ pp.breakable
1832
+ pp.pp(obj.instance_eval(v))
1833
+ end
1834
+ end
1835
+ end
1836
+ end
1837
+ end
1838
+
1839
+ end