yadriggy 1.0.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.
@@ -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