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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +108 -0
- data/Rakefile +10 -0
- data/lib/yadriggy.rb +32 -0
- data/lib/yadriggy/algebra.rb +497 -0
- data/lib/yadriggy/ast.rb +1839 -0
- data/lib/yadriggy/ast_location.rb +73 -0
- data/lib/yadriggy/ast_value.rb +428 -0
- data/lib/yadriggy/c.rb +11 -0
- data/lib/yadriggy/c/c.rb +220 -0
- data/lib/yadriggy/c/codegen.rb +481 -0
- data/lib/yadriggy/c/config.rb +51 -0
- data/lib/yadriggy/c/ctype.rb +118 -0
- data/lib/yadriggy/c/ctypecheck.rb +449 -0
- data/lib/yadriggy/c/ffi.rb +301 -0
- data/lib/yadriggy/c/opencl.rb +458 -0
- data/lib/yadriggy/c/program.rb +86 -0
- data/lib/yadriggy/c1.rb +10 -0
- data/lib/yadriggy/checker.rb +216 -0
- data/lib/yadriggy/eval.rb +200 -0
- data/lib/yadriggy/eval_all.rb +159 -0
- data/lib/yadriggy/pretty_print.rb +492 -0
- data/lib/yadriggy/printer.rb +82 -0
- data/lib/yadriggy/ruby_typecheck.rb +468 -0
- data/lib/yadriggy/ruby_typeinfer.rb +335 -0
- data/lib/yadriggy/source_code.rb +168 -0
- data/lib/yadriggy/syntax.rb +524 -0
- data/lib/yadriggy/type.rb +754 -0
- data/lib/yadriggy/typecheck.rb +277 -0
- data/lib/yadriggy/version.rb +5 -0
- data/yadriggy.gemspec +33 -0
- metadata +149 -0
data/lib/yadriggy/ast.rb
ADDED
@@ -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
|