riml 0.1.3

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