casty 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,57 @@
1
+ ######################################################################
2
+ #
3
+ # Node#inspect.
4
+ #
5
+ ######################################################################
6
+
7
+ module C
8
+ class Node
9
+ INSPECT_TAB = ' '
10
+ def inspect
11
+ return Node.inspect1(self)
12
+ end
13
+
14
+ def Node.inspect1(x, prefix='', indent=0, is_child=true)
15
+ case x
16
+ when NodeList
17
+ if x.empty?
18
+ return "#{INSPECT_TAB*indent}#{prefix}[]\n"
19
+ else
20
+ str = "#{INSPECT_TAB*indent}#{prefix}\n"
21
+ x.each do |el|
22
+ str << inspect1(el, "- ", indent+1)
23
+ end
24
+ return str
25
+ end
26
+ when Node
27
+ classname = x.class.name.gsub(/^C::/, '')
28
+ str = "#{INSPECT_TAB*indent}#{prefix}#{classname}"
29
+
30
+ fields = x.fields
31
+ bools, others = fields.partition{|field| field.reader.to_s[-1] == ??}
32
+ bools.delete_if{|field| !x.send(field.reader)}
33
+ bools.map!{|field| field.init_key}
34
+
35
+ unless bools == []
36
+ str << " (#{bools.join(' ')})"
37
+ end
38
+ str << "\n"
39
+
40
+ others.each do |field|
41
+ val = x.send(field.reader)
42
+ next if val == field.make_default ||
43
+ # don't bother with non-child Nodes, since they may cause
44
+ # loops in the tree
45
+ (val.is_a?(Node) && !field.child?)
46
+ str << inspect1(val, "#{field.reader}: ", indent+1, field.child?)
47
+ end
48
+ return str
49
+ when Symbol
50
+ return "#{INSPECT_TAB*indent}#{prefix}#{x}\n"
51
+ else
52
+ return "#{INSPECT_TAB*indent}#{prefix}#{x.inspect}\n"
53
+ end
54
+ return s.string
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,741 @@
1
+ ######################################################################
2
+ #
3
+ # Node core functionality.
4
+ #
5
+ ######################################################################
6
+
7
+ module C
8
+ #
9
+ # Abstract base class for all AST nodes.
10
+ #
11
+ class Node
12
+ #
13
+ # Called by the test suite to ensure all invariants are true.
14
+ #
15
+ def assert_invariants(testcase)
16
+ fields.each do |field|
17
+ if val = send(field.reader)
18
+ assert_same(self, node.parent, "field.reader is #{field.reader}")
19
+ if field.child?
20
+ assert_same(field, val.instance_variable_get(:@parent_field), "field.reader is #{field.reader}")
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ #
27
+ # Like self.new, but the first argument is taken as the position
28
+ # of the Node.
29
+ #
30
+ def self.new_at(pos, *args)
31
+ ret = new(*args)
32
+ ret.pos = pos
33
+ return ret
34
+ end
35
+
36
+ #
37
+ # True iff both are of the same class, and all fields are #==.
38
+ #
39
+ def ==(other)
40
+ return false if !other.is_a? self.class
41
+
42
+ fields.all? do |field|
43
+ mine = self .send(field.reader)
44
+ yours = other.send(field.reader)
45
+ mine == yours
46
+ end
47
+ end
48
+
49
+ #
50
+ # Same as #==.
51
+ #
52
+ def eql?(other)
53
+ return self == other
54
+ end
55
+
56
+ #
57
+ # #hash, as defined in Object.
58
+ #
59
+ def hash
60
+ fields.inject(0) do |hash, field|
61
+ val = send(field.reader)
62
+ hash ^= val.hash
63
+ end
64
+ end
65
+
66
+ #
67
+ # As defined for ::Object, but children are recursively `#dup'ed.
68
+ #
69
+ def dup
70
+ ret = super
71
+ ret.instance_variable_set(:@parent, nil)
72
+ fields.each do |field|
73
+ next if !field.child?
74
+ val = instance_variable_get(field.var)
75
+ val = val.dup unless val.nil?
76
+ ret.instance_variable_set(field.var, nil)
77
+ ret.send(field.writer, val)
78
+ end
79
+ return ret
80
+ end
81
+
82
+ #
83
+ # As defined for ::Object, but children are recursively `#clone'd.
84
+ #
85
+ def clone
86
+ ret = super
87
+ ret.instance_variable_set(:@parent, nil)
88
+ fields.each do |field|
89
+ next if !field.child?
90
+ val = instance_variable_get(field.var)
91
+ val = val.clone unless val.nil?
92
+ ret.instance_variable_set(field.var, nil)
93
+ ret.send(field.writer, val)
94
+ end
95
+ return ret
96
+ end
97
+
98
+ # ----------------------------------------------------------------
99
+ # Tree traversal
100
+ # ----------------------------------------------------------------
101
+
102
+ include Enumerable
103
+
104
+ #
105
+ # Yield each child in field order.
106
+ #
107
+ def each(&blk)
108
+ fields.each do |field|
109
+ if field.child?
110
+ val = self.send(field.reader)
111
+ yield val unless val.nil?
112
+ end
113
+ end
114
+ return self
115
+ end
116
+
117
+ #
118
+ # Yield each child in reverse field order.
119
+ #
120
+ def reverse_each(&blk)
121
+ fields.reverse_each do |field|
122
+ if field.child?
123
+ val = self.send(field.reader)
124
+ yield val unless val.nil?
125
+ end
126
+ end
127
+ return self
128
+ end
129
+
130
+ #
131
+ # Perform a depth-first walk of the AST, yielding on recursively
132
+ # on each child node:
133
+ #
134
+ # - (:descending, node) just prior to descending into `node'
135
+ # - (:ascending, node) just after ascending from `node'
136
+ #
137
+ # If the block throws :prune while descending, the children of the
138
+ # node that was passed to that block will not be visited.
139
+ #
140
+ def depth_first(&blk)
141
+ catch :prune do
142
+ yield :descending, self
143
+ each{|n| n.depth_first(&blk)}
144
+ end
145
+ yield :ascending, self
146
+ return self
147
+ end
148
+
149
+ #
150
+ # Perform a reverse depth-first walk of the AST, yielding on each
151
+ # node:
152
+ #
153
+ # - (:descending, node) just prior to descending into `node'
154
+ # - (:ascending, node) just after ascending from `node'
155
+ #
156
+ # If the block throws :prune while descending, the children of the
157
+ # node that was passed to that block will not be visited.
158
+ #
159
+ def reverse_depth_first(&blk)
160
+ catch :prune do
161
+ yield :descending, self
162
+ reverse_each{|n| n.reverse_depth_first(&blk)}
163
+ end
164
+ yield :ascending, self
165
+ return self
166
+ end
167
+
168
+ #
169
+ # Perform a preorder walk of the AST, yielding each node in turn.
170
+ # Return self.
171
+ #
172
+ # If the block throws :prune, the children of the node that was
173
+ # passed to that block will not be visited.
174
+ #
175
+ def preorder(&blk)
176
+ catch :prune do
177
+ yield self
178
+ each{|n| n.preorder(&blk)}
179
+ end
180
+ return self
181
+ end
182
+
183
+ #
184
+ # Perform a reverse preorder walk of the AST, yielding each node
185
+ # in turn. Return self.
186
+ #
187
+ # If the block throws :prune, the children of the node that was
188
+ # passed to that block will not be visited.
189
+ #
190
+ def reverse_preorder(&blk)
191
+ catch :prune do
192
+ yield self
193
+ reverse_each{|n| n.reverse_preorder(&blk)}
194
+ end
195
+ return self
196
+ end
197
+
198
+ #
199
+ # Perform a postorder walk of the AST, yielding each node in turn.
200
+ # Return self.
201
+ #
202
+ def postorder(&blk)
203
+ each{|n| n.postorder(&blk)}
204
+ yield self
205
+ return self
206
+ end
207
+
208
+ #
209
+ # Perform a reverse postorder walk of the AST, yielding each node
210
+ # in turn. Return self.
211
+ #
212
+ def reverse_postorder(&blk)
213
+ reverse_each{|n| n.reverse_postorder(&blk)}
214
+ yield self
215
+ return self
216
+ end
217
+
218
+ # ----------------------------------------------------------------
219
+ # Node tree-structure methods
220
+ # ----------------------------------------------------------------
221
+
222
+ class BadParent < StandardError; end
223
+ class NoParent < BadParent; end
224
+
225
+ #
226
+ # The Node's parent.
227
+ #
228
+ attr_accessor :parent
229
+ private :parent=
230
+
231
+ #
232
+ # The position in the source file the construct this node
233
+ # represents appears at.
234
+ #
235
+ attr_accessor :pos
236
+
237
+ #
238
+ # Return the sibling Node that comes after this in preorder
239
+ # sequence.
240
+ #
241
+ # Raises NoParent if there's no parent.
242
+ #
243
+ def next
244
+ @parent or raise NoParent
245
+ return @parent.node_after(self)
246
+ end
247
+
248
+ #
249
+ # Return the sibling Node that comes after this in the parent
250
+ # NodeList.
251
+ #
252
+ # Raises:
253
+ # -- NoParent if there's no parent
254
+ # -- BadParent if the parent is otherwise not a NodeList
255
+ #
256
+ def list_next
257
+ @parent or raise NoParent
258
+ @parent.NodeList? or raise BadParent
259
+ return @parent.node_after(self)
260
+ end
261
+
262
+ #
263
+ # Return the sibling Node that comes before this in preorder
264
+ # sequence.
265
+ #
266
+ # Raises NoParent if there's no parent.
267
+ #
268
+ def prev
269
+ @parent or raise NoParent
270
+ return @parent.node_before(self)
271
+ end
272
+
273
+ #
274
+ # Return the sibling Node that comes before this in the parent
275
+ # NodeList.
276
+ #
277
+ # Raises:
278
+ # -- NoParent if there's no parent
279
+ # -- BadParent if the parent is otherwise not a NodeList
280
+ #
281
+ def list_prev
282
+ @parent or raise NoParent
283
+ @parent.NodeList? or raise BadParent
284
+ return @parent.node_before(self)
285
+ end
286
+
287
+ #
288
+ # Detach this Node from the tree and return it.
289
+ #
290
+ # Raises NoParent if there's no parent.
291
+ #
292
+ def detach
293
+ @parent or raise NoParent
294
+ @parent.remove_node(self)
295
+ return self
296
+ end
297
+
298
+ #
299
+ # Replace this Node in the tree with the given node(s). Return
300
+ # this node.
301
+ #
302
+ # Raises:
303
+ # -- NoParent if there's no parent
304
+ # -- BadParent if the parent is otherwise not a NodeList, and
305
+ # more than one node is given.
306
+ #
307
+ def replace_with(*nodes)
308
+ @parent or raise NoParent
309
+ @parent.replace_node(self, *nodes)
310
+ return self
311
+ end
312
+
313
+ #
314
+ # Swap this node with `node' in their trees. If either node is
315
+ # detached, the other will become detached as a result of calling
316
+ # this method.
317
+ #
318
+ def swap_with node
319
+ return self if node.equal? self
320
+ if self.attached?
321
+ if node.attached?
322
+ # both attached -- use placeholder
323
+ placeholder = Default.new
324
+ my_parent = @parent
325
+ my_parent.replace_node(self, placeholder)
326
+ node.parent.replace_node(node, self)
327
+ my_parent.replace_node(placeholder, node)
328
+ else
329
+ # only `self' attached
330
+ @parent.replace_node(self, node)
331
+ end
332
+ else
333
+ if node.attached?
334
+ # only `node' attached
335
+ node.parent.replace_node(node, self)
336
+ else
337
+ # neither attached -- nothing to do
338
+ end
339
+ end
340
+ return self
341
+ end
342
+
343
+ #
344
+ # Insert `newnodes' before this node. Return this node.
345
+ #
346
+ # Raises:
347
+ # -- NoParent if there's no parent
348
+ # -- BadParent if the parent is otherwise not a NodeList
349
+ #
350
+ def insert_prev(*newnodes)
351
+ @parent or raise NoParent
352
+ @parent.NodeList? or raise BadParent
353
+ @parent.insert_before(self, *newnodes)
354
+ return self
355
+ end
356
+
357
+ #
358
+ # Insert `newnodes' after this node. Return this node.
359
+ #
360
+ # Raises:
361
+ # -- NoParent if there's no parent
362
+ # -- BadParent if the parent is otherwise not a NodeList
363
+ #
364
+ def insert_next(*newnodes)
365
+ @parent or raise NoParent
366
+ @parent.NodeList? or raise BadParent
367
+ @parent.insert_after(self, *newnodes)
368
+ return self
369
+ end
370
+
371
+ #
372
+ # Return true if this Node is detached (i.e., #parent is nil),
373
+ # false otherwise.
374
+ #
375
+ # This is equal to !attached?
376
+ #
377
+ def detached?
378
+ @parent.nil?
379
+ end
380
+
381
+ #
382
+ # Return true if this Node is attached (i.e., #parent is nonnil),
383
+ # false otherwise.
384
+ #
385
+ # This is equal to !detached?
386
+ #
387
+ def attached?
388
+ !@parent.nil?
389
+ end
390
+
391
+ # ----------------------------------------------------------------
392
+ # Subclass management
393
+ # ----------------------------------------------------------------
394
+
395
+ #
396
+ # The direct subclasses of this class (an Array of Class).
397
+ #
398
+ attr_reader :subclasses
399
+
400
+ #
401
+ # Return all classes which have this class somewhere in its
402
+ # ancestry (an Array of Class).
403
+ #
404
+ def self.subclasses_recursive
405
+ ret = @subclasses.dup
406
+ @subclasses.each{|c| ret.concat(c.subclasses_recursive)}
407
+ return ret
408
+ end
409
+
410
+ #
411
+ # Callback defined in Class.
412
+ #
413
+ def self.inherited(klass)
414
+ @subclasses << klass
415
+ klass.instance_variable_set(:@subclasses, [])
416
+ klass.instance_variable_set(:@fields , [])
417
+ end
418
+
419
+ #
420
+ # Declare this class as abstract.
421
+ #
422
+ def self.abstract
423
+ end
424
+
425
+ # set the instance vars for Node
426
+ @subclasses = []
427
+ @fields = []
428
+
429
+ # --------------------------------------------------------------
430
+ #
431
+ # Fields
432
+ #
433
+ # Fields are interesting attributes, that are, e.g., compared in
434
+ # `==', and copied in `dup' and `clone'. "Child" fields are also
435
+ # yielded in a traversal. For each field, a setter and getter is
436
+ # created, and the corresponding instance variable is set in
437
+ # `initialize'.
438
+ #
439
+ # Child fields are declared using Node.child; other fields are
440
+ # declared using Node.field.
441
+ #
442
+ # --------------------------------------------------------------
443
+
444
+ private # -------------------------------------------------------
445
+
446
+ #
447
+ # Add the Field `newfield' to the list of fields for this class.
448
+ #
449
+ def self.add_field(newfield)
450
+ # add the newfield to @fields, and set the index
451
+ fields = @fields
452
+ newfield.index = fields.length
453
+ fields << newfield
454
+ # getter
455
+ # define_method(newfield.reader) do
456
+ # instance_variable_get(newfield.var)
457
+ # end
458
+ eval "def #{newfield.reader}; #{newfield.var}; end"
459
+ # setter
460
+ if newfield.child?
461
+ define_method(newfield.writer) do |val|
462
+ old = send(newfield.reader)
463
+ return if val.equal? old
464
+ # detach the old Node
465
+ old = self.send(newfield.reader)
466
+ unless old.nil?
467
+ old.instance_variable_set(:@parent, nil)
468
+ end
469
+ # copy val if needed
470
+ val = val.clone if !val.nil? && val.attached?
471
+ # set
472
+ self.instance_variable_set(newfield.var, val)
473
+ # attach the new Node
474
+ unless val.nil?
475
+ val.instance_variable_set(:@parent, self)
476
+ val.instance_variable_set(:@parent_field, newfield)
477
+ end
478
+ end
479
+ else
480
+ define_method(newfield.writer) do |val|
481
+ instance_variable_set(newfield.var, val)
482
+ end
483
+ end
484
+ public newfield.reader, newfield.writer
485
+ end
486
+ def self.fields
487
+ @fields
488
+ end
489
+
490
+ #
491
+ # Define an initialize method. The initialize method sets the
492
+ # fields named in `syms' from the arguments given to it. The
493
+ # initialize method also takes named parameters (i.e., an optional
494
+ # Hash as the last argument), which may be used to set fields not
495
+ # even named in `syms'. The syms in the optional Hash are the
496
+ # values of the `init_key' members of the corresponding Field
497
+ # objects.
498
+ #
499
+ # As an example for this Node class:
500
+ #
501
+ # class X < Node
502
+ # field :x
503
+ # field :y
504
+ # child :z
505
+ # initializer :z, :y
506
+ # end
507
+ #
508
+ # ...X.new can be called in any of these ways:
509
+ #
510
+ # X.new # all fields set to default
511
+ # X.new(1) # .z = 1
512
+ # X.new(1, 2) # .z = 1, .y = 2
513
+ # X.new(:x = 1, :y => 2, :z => 3) # .x = 1, .y = 2, .z = 3
514
+ # X.new(1, :x => 2) # .z = 1, .x = 2
515
+ # X.new(1, :z => 2) # undefined behaviour!
516
+ # ...etc.
517
+ #
518
+ def self.initializer(*syms)
519
+ define_method(:initialize) do |*args|
520
+ # pop off the opts hash
521
+ opts = args.last.is_a?(::Hash) ? args.pop : {}
522
+
523
+ # add positional args to opts
524
+ args.each_with_index do |arg, i|
525
+ opts[syms[i]] = arg
526
+ end
527
+
528
+ # set field values
529
+ fields.each do |field|
530
+ key = field.init_key
531
+ if opts.key?(key)
532
+ send(field.writer, opts[key])
533
+ else
534
+ send(field.writer, field.make_default)
535
+ end
536
+ end
537
+
538
+ # pos, parent
539
+ @pos = nil
540
+ @parent = nil
541
+ end
542
+ end
543
+
544
+ public # --------------------------------------------------------
545
+
546
+ #
547
+ # Declare a field with the given name and default value.
548
+ #
549
+ def self.field(name, default=:'no default')
550
+ if default == :'no default'
551
+ if name.to_s[-1] == ??
552
+ default = false
553
+ else
554
+ default = nil
555
+ end
556
+ end
557
+
558
+ # if the field exists, just update its default, otherwise, add
559
+ # a new field
560
+ self.fields.each do |field|
561
+ if field.reader == name
562
+ field.default = default
563
+ return
564
+ end
565
+ end
566
+ add_field Field.new(name, default)
567
+ end
568
+
569
+ #
570
+ # Declare a child with the given name and default value. The
571
+ # default value is cloned when used (unless cloning is
572
+ # unnecessary).
573
+ #
574
+ def self.child(name, default=nil)
575
+ field = Field.new(name, default)
576
+ field.child = true
577
+ add_field field
578
+ end
579
+
580
+ #
581
+ # Return the list of fields this object has. Don't modify the
582
+ # returned array!
583
+ #
584
+ def fields
585
+ self.class.fields
586
+ end
587
+
588
+ def method_missing(meth, *args, &blk)
589
+ # respond to `Module?'
590
+ methstr = meth.to_s
591
+ if methstr =~ /^([A-Z].*)\?$/ && C.const_defined?($1)
592
+ klass = C.const_get($1)
593
+ if klass.is_a?(::Module)
594
+ return self.is_a?(klass)
595
+ end
596
+ end
597
+
598
+ begin
599
+ super
600
+ rescue NoMethodError => e
601
+ e.set_backtrace(caller)
602
+ raise e
603
+ end
604
+ end
605
+
606
+ # ----------------------------------------------------------------
607
+ # Child management
608
+ # ----------------------------------------------------------------
609
+
610
+ public # --------------------------------------------------------
611
+
612
+ #
613
+ # Return the Node that comes after the given Node in tree
614
+ # preorder.
615
+ #
616
+ def node_after(node)
617
+ node.parent.equal? self or
618
+ raise ArgumentError, "node is not a child"
619
+ fields = self.fields
620
+ i = node.instance_variable_get(:@parent_field).index + 1
621
+ (i...fields.length).each do |i|
622
+ f = fields[i]
623
+ if f.child? && (val = self.send(f.reader))
624
+ return val
625
+ end
626
+ end
627
+ return nil
628
+ end
629
+
630
+ #
631
+ # Return the Node that comes before the given Node in tree
632
+ # preorder.
633
+ #
634
+ def node_before(node)
635
+ node.parent.equal? self or
636
+ raise ArgumentError, "node is not a child"
637
+ fields = self.fields
638
+ i = node.instance_variable_get(:@parent_field).index - 1
639
+ i.downto(0) do |i|
640
+ f = fields[i]
641
+ if f.child? && (val = self.send(f.reader))
642
+ return val
643
+ end
644
+ end
645
+ return nil
646
+ end
647
+
648
+ #
649
+ # Remove the given Node.
650
+ #
651
+ def remove_node(node)
652
+ node.parent.equal? self or
653
+ raise ArgumentError, "node is not a child"
654
+ field = node.instance_variable_get(:@parent_field)
655
+ node.instance_variable_set(:@parent, nil)
656
+ node.instance_variable_set(:@parent_field, nil)
657
+ self.instance_variable_set(field.var, nil)
658
+ return self
659
+ end
660
+
661
+ #
662
+ # Replace `node' with `newnode'.
663
+ #
664
+ def replace_node(node, newnode=nil)
665
+ node.parent.equal? self or
666
+ raise ArgumentError, "node is not a child"
667
+ field = node.instance_variable_get(:@parent_field)
668
+ self.send(field.writer, newnode)
669
+ return self
670
+ end
671
+
672
+ # ----------------------------------------------------------------
673
+ # Node::Field
674
+ # ----------------------------------------------------------------
675
+
676
+ private # -------------------------------------------------------
677
+
678
+ class Field
679
+ attr_accessor :var, :reader, :writer, :init_key, :index,
680
+ :default
681
+
682
+ #
683
+ # True if this field is a child field, false otherwise.
684
+ #
685
+ attr_writer :child
686
+ def child?
687
+ @child
688
+ end
689
+
690
+ #
691
+ # Create a default value for this field. This differs from
692
+ # #default in that if it's a Proc, it is called and the result
693
+ # returned.
694
+ #
695
+ def make_default
696
+ if @default.respond_to? :call
697
+ @default.call
698
+ else
699
+ @default
700
+ end
701
+ end
702
+
703
+ def initialize(name, default)
704
+ name = name.to_s
705
+
706
+ @child = false
707
+ @reader = name.to_sym
708
+ @default = default
709
+
710
+ if name[-1] == ?? then name[-1] = '' end
711
+ @init_key = name.to_sym
712
+ @var = "@#{name}".to_sym
713
+ @writer = "#{name}=".to_sym
714
+ end
715
+ end
716
+
717
+ public # -------------------------------------------------------
718
+
719
+ #
720
+ # A position in a source file. All Nodes may have one in their
721
+ # #pos attribute.
722
+ #
723
+ class Pos
724
+ attr_accessor :filename, :line_num, :col_num
725
+ def initialize(filename, line_num, col_num)
726
+ @filename = filename
727
+ @line_num = line_num
728
+ @col_num = col_num
729
+ end
730
+ def to_s
731
+ (@filename ? "#@filename:" : '') << "#@line_num:#@col_num"
732
+ end
733
+ def <=>(x)
734
+ return nil if self.filename != x.filename
735
+ return (self.line_num <=> x.line_num).nonzero? ||
736
+ self.col_num <=> x.col_num
737
+ end
738
+ include Comparable
739
+ end
740
+ end
741
+ end