riml 0.1.3
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.
- data/LICENSE +20 -0
- data/README.md +148 -0
- data/bin/riml +69 -0
- data/config/environment.rb +10 -0
- data/lib/ast_rewriter.rb +268 -0
- data/lib/class_map.rb +46 -0
- data/lib/compiler.rb +579 -0
- data/lib/constants.rb +280 -0
- data/lib/errors.rb +4 -0
- data/lib/grammar.y +485 -0
- data/lib/helper.rb +45 -0
- data/lib/lexer.rb +276 -0
- data/lib/nodes.rb +723 -0
- data/lib/parser.rb +2748 -0
- data/lib/walker.rb +15 -0
- data/version.rb +4 -0
- metadata +75 -0
data/lib/nodes.rb
ADDED
@@ -0,0 +1,723 @@
|
|
1
|
+
require File.expand_path('../constants', __FILE__)
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Visitable
|
5
|
+
def accept(visitor)
|
6
|
+
visitor.visit(self)
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :parent_node, :scope, :force_newline
|
10
|
+
alias parent parent_node
|
11
|
+
alias parent= parent_node=
|
12
|
+
|
13
|
+
attr_writer :compiled_output
|
14
|
+
def compiled_output
|
15
|
+
@compiled_output ||= ''
|
16
|
+
end
|
17
|
+
|
18
|
+
# catches "descendant_of_#{some_class}?" methods
|
19
|
+
# def descendant_of_call_node?
|
20
|
+
# CallNode === self.parent_node
|
21
|
+
# end
|
22
|
+
DESCENDANT_OF_REGEX = /\Adescendant_of_(.*?)\?/
|
23
|
+
def method_missing(method, *args, &blk)
|
24
|
+
if method =~ DESCENDANT_OF_REGEX
|
25
|
+
parent_node_name = $1.split('_').map(&:capitalize).join
|
26
|
+
parent_node = self.class.const_get parent_node_name
|
27
|
+
parent_node === self.parent_node
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
def respond_to_missing?(method, include_private = false)
|
33
|
+
return true if method =~ DESCENDANT_OF_REGEX
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Walkable
|
39
|
+
include Enumerable
|
40
|
+
|
41
|
+
def each &block
|
42
|
+
children.each &block
|
43
|
+
end
|
44
|
+
alias walk each
|
45
|
+
|
46
|
+
def previous
|
47
|
+
idx = index
|
48
|
+
return unless idx
|
49
|
+
parent.children.fetch(idx - 1)
|
50
|
+
end
|
51
|
+
|
52
|
+
def child_previous_to(node)
|
53
|
+
idx = children.find_index(node)
|
54
|
+
return unless idx
|
55
|
+
children.fetch(idx - 1)
|
56
|
+
end
|
57
|
+
|
58
|
+
def insert_before(node, new_node)
|
59
|
+
idx = children.find_index(node)
|
60
|
+
return unless idx
|
61
|
+
children.insert(idx-1, new_node)
|
62
|
+
end
|
63
|
+
|
64
|
+
def next
|
65
|
+
idx = index
|
66
|
+
return unless idx
|
67
|
+
parent.children.fetch(idx + 1)
|
68
|
+
end
|
69
|
+
|
70
|
+
def child_after(node)
|
71
|
+
idx = children.find_index(node)
|
72
|
+
return unless idx
|
73
|
+
children.fetch(idx + 1)
|
74
|
+
end
|
75
|
+
|
76
|
+
def insert_after(node, new_node)
|
77
|
+
idx = children.find_index(node)
|
78
|
+
return unless idx
|
79
|
+
children.insert(idx+1, new_node)
|
80
|
+
end
|
81
|
+
|
82
|
+
def index
|
83
|
+
parent.children.find_index(self)
|
84
|
+
end
|
85
|
+
|
86
|
+
def remove
|
87
|
+
idx = index
|
88
|
+
parent.children.slice!(idx) if idx
|
89
|
+
end
|
90
|
+
|
91
|
+
def replace_with(new_node)
|
92
|
+
idx = index
|
93
|
+
return unless idx
|
94
|
+
parent.children.insert(idx, new_node)
|
95
|
+
parent.children.slice!(idx+1)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
module Indentable
|
100
|
+
def indent
|
101
|
+
@indent ||= " " * 2
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Collection of nodes each one representing an expression.
|
106
|
+
class Nodes < Struct.new(:nodes)
|
107
|
+
include Visitable
|
108
|
+
include Walkable
|
109
|
+
|
110
|
+
def <<(node)
|
111
|
+
nodes << node
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
def concat(list_of_nodes)
|
116
|
+
nodes.concat(list_of_nodes)
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
# forward missing methods to `nodes` array
|
121
|
+
def method_missing(method, *args, &block)
|
122
|
+
if nodes.respond_to?(method)
|
123
|
+
nodes.send(method, *args, &block)
|
124
|
+
else
|
125
|
+
super
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def respond_to_missing?(method, include_private = false)
|
130
|
+
return true if nodes.respond_to?(method)
|
131
|
+
super
|
132
|
+
end
|
133
|
+
|
134
|
+
def children
|
135
|
+
nodes
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Literals are static values that have a Ruby representation, eg.: a string, number, list,
|
140
|
+
# true, false, nil, etc.
|
141
|
+
class LiteralNode < Struct.new(:value)
|
142
|
+
include Visitable
|
143
|
+
end
|
144
|
+
|
145
|
+
class KeywordNode < Struct.new(:value)
|
146
|
+
include Visitable
|
147
|
+
end
|
148
|
+
|
149
|
+
class NumberNode < LiteralNode; end
|
150
|
+
|
151
|
+
class StringNode < Struct.new(:value, :type) # type: :d or :s for double- or single-quoted
|
152
|
+
include Visitable
|
153
|
+
end
|
154
|
+
|
155
|
+
class RegexpNode < LiteralNode; end
|
156
|
+
class ListNode < LiteralNode
|
157
|
+
include Walkable
|
158
|
+
def self.wrap(value)
|
159
|
+
val = Array === value ? value : [value]
|
160
|
+
new(val)
|
161
|
+
end
|
162
|
+
|
163
|
+
def children
|
164
|
+
value
|
165
|
+
end
|
166
|
+
end
|
167
|
+
class DictionaryNode < LiteralNode; end
|
168
|
+
class ScopeModifierLiteralNode < LiteralNode; end
|
169
|
+
|
170
|
+
class TrueNode < LiteralNode
|
171
|
+
def initialize() super(true) end
|
172
|
+
end
|
173
|
+
|
174
|
+
class FalseNode < LiteralNode
|
175
|
+
def initialize() super(false) end
|
176
|
+
end
|
177
|
+
|
178
|
+
class NilNode < LiteralNode
|
179
|
+
def initialize() super(nil) end
|
180
|
+
end
|
181
|
+
|
182
|
+
class NewlineNode < LiteralNode
|
183
|
+
def initialize() super("\n") end
|
184
|
+
end
|
185
|
+
|
186
|
+
class ExLiteralNode < LiteralNode
|
187
|
+
def initialize(*)
|
188
|
+
super
|
189
|
+
self.force_newline = true
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
class FinishNode < KeywordNode
|
194
|
+
def initialize() super("finish\n") end
|
195
|
+
end
|
196
|
+
|
197
|
+
class BreakNode < KeywordNode
|
198
|
+
def initialize() super("break\n") end
|
199
|
+
end
|
200
|
+
|
201
|
+
class ContinueNode < KeywordNode
|
202
|
+
def initialize() super("continue\n") end
|
203
|
+
end
|
204
|
+
|
205
|
+
|
206
|
+
class ReturnNode < Struct.new(:expression)
|
207
|
+
include Visitable
|
208
|
+
include Walkable
|
209
|
+
|
210
|
+
def children
|
211
|
+
[expression]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
module FullyNameable
|
216
|
+
def self.included(base)
|
217
|
+
base.class_eval do
|
218
|
+
raise "#{base} must define method 'name'" unless method_defined?(:name)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def full_name
|
223
|
+
if respond_to?(:scope_modifier)
|
224
|
+
"#{scope_modifier}#{name}"
|
225
|
+
elsif respond_to?(:prefix)
|
226
|
+
"#{prefix}#{name}"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
# Node of a method call, can take any of these forms:
|
232
|
+
#
|
233
|
+
# Method()
|
234
|
+
# s:Method(argument1, argument2)
|
235
|
+
class CallNode < Struct.new(:scope_modifier, :name, :arguments)
|
236
|
+
include Riml::Constants
|
237
|
+
include Visitable
|
238
|
+
include FullyNameable
|
239
|
+
include Walkable
|
240
|
+
|
241
|
+
def builtin_function?
|
242
|
+
return false unless name.is_a?(String)
|
243
|
+
scope_modifier.nil? and (BUILTIN_FUNCTIONS + BUILTIN_COMMANDS).include?(name)
|
244
|
+
end
|
245
|
+
|
246
|
+
def builtin_command?
|
247
|
+
return false unless name.is_a?(String)
|
248
|
+
scope_modifier.nil? and BUILTIN_COMMANDS.include?(name)
|
249
|
+
end
|
250
|
+
alias no_parens_necessary? builtin_command?
|
251
|
+
|
252
|
+
def must_be_explicit_call?
|
253
|
+
return false if builtin_command?
|
254
|
+
return true if parent.nil?
|
255
|
+
return true if Nodes === parent
|
256
|
+
false
|
257
|
+
end
|
258
|
+
|
259
|
+
def children
|
260
|
+
if name.is_a?(String)
|
261
|
+
arguments
|
262
|
+
else
|
263
|
+
[name] + arguments
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# Node of an explicitly called method, can take any of these forms:
|
269
|
+
#
|
270
|
+
# call Method()
|
271
|
+
# call s:Method(argument1, argument2)
|
272
|
+
class ExplicitCallNode < CallNode; end
|
273
|
+
|
274
|
+
class OperatorNode < Struct.new(:operator, :operands)
|
275
|
+
include Visitable
|
276
|
+
include Walkable
|
277
|
+
|
278
|
+
def children
|
279
|
+
operands
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
class BinaryOperatorNode < OperatorNode
|
284
|
+
include Riml::Constants
|
285
|
+
|
286
|
+
def operand1() operands[0] end
|
287
|
+
def operand1=(val) operands[0] = val end
|
288
|
+
|
289
|
+
def operand2() operands[1] end
|
290
|
+
def operand2=(val) operands[1] = val end
|
291
|
+
|
292
|
+
def ignorecase_capable_operator?(operator)
|
293
|
+
IGNORECASE_CAPABLE_OPERATORS.include?(operator)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
class UnaryOperatorNode < OperatorNode
|
298
|
+
alias operand operands
|
299
|
+
end
|
300
|
+
|
301
|
+
# operator = :ternary
|
302
|
+
# operands = [condition, if_expr, else_expr]
|
303
|
+
class TernaryOperatorNode < OperatorNode
|
304
|
+
def initialize(operands, operator=:ternary)
|
305
|
+
super(operator, operands)
|
306
|
+
end
|
307
|
+
|
308
|
+
def condition() operands[0] end
|
309
|
+
|
310
|
+
def if_expr() operands[1] end
|
311
|
+
|
312
|
+
def else_expr() operands[2] end
|
313
|
+
end
|
314
|
+
|
315
|
+
# let var = 2
|
316
|
+
# let s:var = 4
|
317
|
+
class AssignNode < Struct.new(:operator, :lhs, :rhs)
|
318
|
+
include Visitable
|
319
|
+
include Walkable
|
320
|
+
|
321
|
+
def children
|
322
|
+
[lhs, rhs]
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
module QuestionVariableExistence
|
327
|
+
def self.included(base)
|
328
|
+
base.class_eval do
|
329
|
+
raise "#{base} must define method 'name'" unless method_defined?(:name)
|
330
|
+
alias name_with_question_mark name
|
331
|
+
def name_without_question_mark
|
332
|
+
if question_existence?
|
333
|
+
name_with_question_mark[0...-1]
|
334
|
+
else
|
335
|
+
name_with_question_mark
|
336
|
+
end
|
337
|
+
end
|
338
|
+
alias name name_without_question_mark
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
def question_existence?
|
343
|
+
name_with_question_mark[-1] == ??
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
# s:var
|
348
|
+
# var
|
349
|
+
class GetVariableNode < Struct.new(:scope_modifier, :name)
|
350
|
+
include Visitable
|
351
|
+
include FullyNameable
|
352
|
+
include QuestionVariableExistence
|
353
|
+
end
|
354
|
+
|
355
|
+
# &autoindent
|
356
|
+
# @q
|
357
|
+
class GetSpecialVariableNode < Struct.new(:prefix, :name)
|
358
|
+
include Visitable
|
359
|
+
include FullyNameable
|
360
|
+
end
|
361
|
+
|
362
|
+
class CurlyBracePart < Struct.new(:value)
|
363
|
+
def interpolated?
|
364
|
+
GetVariableNode === value || GetSpecialVariableNode === value
|
365
|
+
end
|
366
|
+
|
367
|
+
def regular?
|
368
|
+
not interpolated?
|
369
|
+
end
|
370
|
+
end
|
371
|
+
class CurlyBraceVariable < Struct.new(:parts)
|
372
|
+
def <<(part)
|
373
|
+
parts << part
|
374
|
+
self
|
375
|
+
end
|
376
|
+
end
|
377
|
+
class GetCurlyBraceNameNode < Struct.new(:scope_modifier, :variable)
|
378
|
+
include Visitable
|
379
|
+
include Walkable
|
380
|
+
|
381
|
+
def children
|
382
|
+
[variable]
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
class UnletVariableNode < Struct.new(:bang, :variables)
|
387
|
+
include Visitable
|
388
|
+
include Walkable
|
389
|
+
|
390
|
+
def <<(variable)
|
391
|
+
variables << variable
|
392
|
+
self
|
393
|
+
end
|
394
|
+
|
395
|
+
def children
|
396
|
+
variables
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
# Method definition.
|
401
|
+
class DefNode < Struct.new(:bang, :scope_modifier, :name, :parameters, :keyword, :expressions)
|
402
|
+
include Visitable
|
403
|
+
include Indentable
|
404
|
+
include FullyNameable
|
405
|
+
include Walkable
|
406
|
+
|
407
|
+
def initialize(*args)
|
408
|
+
super
|
409
|
+
# max number of arguments in viml
|
410
|
+
if parameters.size > 20
|
411
|
+
raise ArgumentError, "can't have more than 20 parameters for #{full_name}"
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
SPLAT = lambda {|arg| arg == '...' || arg[0] == "*"}
|
416
|
+
|
417
|
+
# ["arg1", "arg2"}
|
418
|
+
def argument_variable_names
|
419
|
+
@argument_variable_names ||= parameters.reject(&SPLAT)
|
420
|
+
end
|
421
|
+
|
422
|
+
# returns the splat argument or nil
|
423
|
+
def splat
|
424
|
+
@splat ||= begin
|
425
|
+
parameters.select(&SPLAT).first
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def keyword
|
430
|
+
return super unless name.include?(".")
|
431
|
+
"dict"
|
432
|
+
end
|
433
|
+
|
434
|
+
def super_node
|
435
|
+
expressions.detect {|n| SuperNode === n}
|
436
|
+
end
|
437
|
+
|
438
|
+
def to_scope
|
439
|
+
ScopeNode.new.tap do |scope|
|
440
|
+
scope.argument_variable_names += argument_variable_names
|
441
|
+
scope.function = self
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
def children
|
446
|
+
[expressions]
|
447
|
+
end
|
448
|
+
|
449
|
+
def method_missing(method, *args, &blk)
|
450
|
+
if children.respond_to?(method)
|
451
|
+
children.send(method, *args &blk)
|
452
|
+
else
|
453
|
+
super
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
class ScopeNode
|
459
|
+
attr_writer :for_node_variable_names, :argument_variable_names
|
460
|
+
attr_accessor :function
|
461
|
+
|
462
|
+
def for_node_variable_names
|
463
|
+
@for_node_variable_names ||= Set.new
|
464
|
+
end
|
465
|
+
|
466
|
+
def argument_variable_names
|
467
|
+
@argument_variable_names ||= Set.new
|
468
|
+
end
|
469
|
+
|
470
|
+
alias function? function
|
471
|
+
|
472
|
+
def initialize_copy(source)
|
473
|
+
super
|
474
|
+
self.for_node_variable_names = for_node_variable_names.dup
|
475
|
+
self.argument_variable_names = argument_variable_names.dup
|
476
|
+
self.function = source.function
|
477
|
+
end
|
478
|
+
|
479
|
+
def merge(other)
|
480
|
+
dup.merge! other
|
481
|
+
end
|
482
|
+
|
483
|
+
def merge!(other)
|
484
|
+
unless other.is_a?(ScopeNode)
|
485
|
+
raise ArgumentError, "other must be ScopeNode, is #{other.class}"
|
486
|
+
end
|
487
|
+
self.for_node_variable_names += other.for_node_variable_names
|
488
|
+
self.argument_variable_names -= for_node_variable_names
|
489
|
+
self.function = other.function if function.nil? && other.function
|
490
|
+
self
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
class DefMethodNode < DefNode
|
495
|
+
def to_def_node
|
496
|
+
DefNode.new(bang, scope_modifier, name, parameters, keyword, expressions)
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
# abstract control structure
|
501
|
+
class ControlStructure < Struct.new(:condition, :body)
|
502
|
+
include Visitable
|
503
|
+
include Indentable
|
504
|
+
include Walkable
|
505
|
+
|
506
|
+
def children
|
507
|
+
[condition, body]
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
class IfNode < ControlStructure; end
|
512
|
+
class UnlessNode < ControlStructure; end
|
513
|
+
|
514
|
+
class WhileNode < ControlStructure; end
|
515
|
+
class UntilNode < ControlStructure; end
|
516
|
+
|
517
|
+
class ElseNode < Struct.new(:expressions)
|
518
|
+
include Visitable
|
519
|
+
include Walkable
|
520
|
+
alias body expressions
|
521
|
+
|
522
|
+
def <<(expr)
|
523
|
+
expressions << expr
|
524
|
+
self
|
525
|
+
end
|
526
|
+
|
527
|
+
def pop
|
528
|
+
expressions.pop
|
529
|
+
end
|
530
|
+
|
531
|
+
def last
|
532
|
+
expressions.last
|
533
|
+
end
|
534
|
+
|
535
|
+
def children
|
536
|
+
[expressions]
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
class ElseifNode < ControlStructure
|
541
|
+
include Visitable
|
542
|
+
include Walkable
|
543
|
+
alias expressions body
|
544
|
+
|
545
|
+
def <<(expr)
|
546
|
+
expressions << expr
|
547
|
+
self
|
548
|
+
end
|
549
|
+
|
550
|
+
def pop
|
551
|
+
expressions.pop
|
552
|
+
end
|
553
|
+
|
554
|
+
def last
|
555
|
+
expressions.last
|
556
|
+
end
|
557
|
+
|
558
|
+
def children
|
559
|
+
[expressions]
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
# for variable in someFunction(1,2,3)
|
564
|
+
# echo variable
|
565
|
+
# end
|
566
|
+
#
|
567
|
+
# OR
|
568
|
+
#
|
569
|
+
# for variable in [1,2,3]
|
570
|
+
# echo variable
|
571
|
+
# end
|
572
|
+
class ForNode < Struct.new(:variable, :in_expression, :expressions)
|
573
|
+
include Visitable
|
574
|
+
include Indentable
|
575
|
+
include Walkable
|
576
|
+
|
577
|
+
alias for_variable variable
|
578
|
+
|
579
|
+
def variables
|
580
|
+
variable if ListNode === variable
|
581
|
+
end
|
582
|
+
|
583
|
+
def for_node_variable_names
|
584
|
+
if ListNode === variable
|
585
|
+
variable.value.map(&:name)
|
586
|
+
else
|
587
|
+
[variable]
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
def to_scope
|
592
|
+
ScopeNode.new.tap {|s| s.for_node_variable_names += for_node_variable_names}
|
593
|
+
end
|
594
|
+
|
595
|
+
def children
|
596
|
+
[variable, in_expression, expressions]
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
# lines: [5, 6, 8, 9]
|
601
|
+
# This means the continuation has 4 lines (line.size is 4) and each line
|
602
|
+
# preserves the amt of whitespace specified as the value in the array.
|
603
|
+
# Ex: 1st line preserves 5 spaces, 2nd line preserves 6 spaces, etc...
|
604
|
+
class LineContinuation < Struct.new(:lines)
|
605
|
+
include Visitable
|
606
|
+
|
607
|
+
def size
|
608
|
+
lines.size
|
609
|
+
end
|
610
|
+
|
611
|
+
def [](idx)
|
612
|
+
lines[idx]
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
class DictGetNode < Struct.new(:dict, :keys)
|
617
|
+
include Visitable
|
618
|
+
include Walkable
|
619
|
+
|
620
|
+
def children
|
621
|
+
[dict] + keys
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
# dict['key']
|
626
|
+
# dict['key1']['key2']
|
627
|
+
class DictGetBracketNode < DictGetNode; end
|
628
|
+
|
629
|
+
# dict.key
|
630
|
+
# dict.key.key2
|
631
|
+
class DictGetDotNode < DictGetNode; end
|
632
|
+
|
633
|
+
|
634
|
+
# list_or_dict[0]
|
635
|
+
# function()[identifier]
|
636
|
+
class ListOrDictGetNode < Struct.new(:list_or_dict, :keys)
|
637
|
+
include Visitable
|
638
|
+
include Walkable
|
639
|
+
|
640
|
+
alias list list_or_dict
|
641
|
+
alias dict list_or_dict
|
642
|
+
def children
|
643
|
+
[list_or_dict] + keys
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
class TryNode < Struct.new(:try_block, :catch_nodes, :ensure_block)
|
648
|
+
include Visitable
|
649
|
+
include Indentable
|
650
|
+
include Walkable
|
651
|
+
|
652
|
+
def children
|
653
|
+
[try_block, catch_nodes, ensure_block]
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
class CatchNode < Struct.new(:regexp, :expressions)
|
658
|
+
include Visitable
|
659
|
+
include Walkable
|
660
|
+
|
661
|
+
def children
|
662
|
+
[expressions]
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
class HeredocNode < Struct.new(:pattern, :string_node)
|
667
|
+
include Visitable
|
668
|
+
include Walkable
|
669
|
+
|
670
|
+
def children
|
671
|
+
[string_node]
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
class ClassDefinitionNode < Struct.new(:name, :superclass_name, :expressions)
|
676
|
+
include Visitable
|
677
|
+
include Walkable
|
678
|
+
|
679
|
+
def superclass?
|
680
|
+
not superclass_name.nil?
|
681
|
+
end
|
682
|
+
|
683
|
+
def constructor
|
684
|
+
expressions.detect do |n|
|
685
|
+
DefNode === n && (n.name == 'initialize' || n.name.match(/Constructor\Z/))
|
686
|
+
end
|
687
|
+
end
|
688
|
+
alias constructor? constructor
|
689
|
+
|
690
|
+
def constructor_name
|
691
|
+
"#{name}Constructor"
|
692
|
+
end
|
693
|
+
|
694
|
+
def constructor_obj_name
|
695
|
+
name[0].downcase + name[1..-1] + "Obj"
|
696
|
+
end
|
697
|
+
|
698
|
+
def children
|
699
|
+
[expressions]
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
class SuperNode < Struct.new(:arguments, :with_parens)
|
704
|
+
include Visitable
|
705
|
+
include Walkable
|
706
|
+
|
707
|
+
def use_all_arguments?
|
708
|
+
arguments.empty? && !with_parens
|
709
|
+
end
|
710
|
+
|
711
|
+
def children
|
712
|
+
arguments
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
class ObjectInstantiationNode < Struct.new(:call_node)
|
717
|
+
include Visitable
|
718
|
+
include Walkable
|
719
|
+
|
720
|
+
def children
|
721
|
+
[call_node]
|
722
|
+
end
|
723
|
+
end
|