csquare-cast 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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,740 @@
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
+ end
485
+ def self.fields
486
+ @fields
487
+ end
488
+
489
+ #
490
+ # Define an initialize method. The initialize method sets the
491
+ # fields named in `syms' from the arguments given to it. The
492
+ # initialize method also takes named parameters (i.e., an optional
493
+ # Hash as the last argument), which may be used to set fields not
494
+ # even named in `syms'. The syms in the optional Hash are the
495
+ # values of the `init_key' members of the corresponding Field
496
+ # objects.
497
+ #
498
+ # As an example for this Node class:
499
+ #
500
+ # class X < Node
501
+ # field :x
502
+ # field :y
503
+ # child :z
504
+ # initializer :z, :y
505
+ # end
506
+ #
507
+ # ...X.new can be called in any of these ways:
508
+ #
509
+ # X.new # all fields set to default
510
+ # X.new(1) # .z = 1
511
+ # X.new(1, 2) # .z = 1, .y = 2
512
+ # X.new(:x = 1, :y => 2, :z => 3) # .x = 1, .y = 2, .z = 3
513
+ # X.new(1, :x => 2) # .z = 1, .x = 2
514
+ # X.new(1, :z => 2) # undefined behaviour!
515
+ # ...etc.
516
+ #
517
+ def self.initializer(*syms)
518
+ define_method(:initialize) do |*args|
519
+ # pop off the opts hash
520
+ opts = args.last.is_a?(::Hash) ? args.pop : {}
521
+
522
+ # add positional args to opts
523
+ args.each_with_index do |arg, i|
524
+ opts[syms[i]] = arg
525
+ end
526
+
527
+ # set field values
528
+ fields.each do |field|
529
+ key = field.init_key
530
+ if opts.key?(key)
531
+ send(field.writer, opts[key])
532
+ else
533
+ send(field.writer, field.make_default)
534
+ end
535
+ end
536
+
537
+ # pos, parent
538
+ @pos = nil
539
+ @parent = nil
540
+ end
541
+ end
542
+
543
+ public # --------------------------------------------------------
544
+
545
+ #
546
+ # Declare a field with the given name and default value.
547
+ #
548
+ def self.field(name, default=:'no default')
549
+ if default == :'no default'
550
+ if name.to_s[-1] == ??
551
+ default = false
552
+ else
553
+ default = nil
554
+ end
555
+ end
556
+
557
+ # if the field exists, just update its default, otherwise, add
558
+ # a new field
559
+ self.fields.each do |field|
560
+ if field.reader == name
561
+ field.default = default
562
+ return
563
+ end
564
+ end
565
+ add_field Field.new(name, default)
566
+ end
567
+
568
+ #
569
+ # Declare a child with the given name and default value. The
570
+ # default value is cloned when used (unless cloning is
571
+ # unnecessary).
572
+ #
573
+ def self.child(name, default=nil)
574
+ field = Field.new(name, default)
575
+ field.child = true
576
+ add_field field
577
+ end
578
+
579
+ #
580
+ # Return the list of fields this object has. Don't modify the
581
+ # returned array!
582
+ #
583
+ def fields
584
+ self.class.fields
585
+ end
586
+
587
+ def method_missing(meth, *args, &blk)
588
+ # respond to `Module?'
589
+ methstr = meth.to_s
590
+ if methstr =~ /^([A-Z].*)\?$/ && C.const_defined?($1)
591
+ klass = C.const_get($1)
592
+ if klass.is_a?(::Module)
593
+ return self.is_a?(klass)
594
+ end
595
+ end
596
+
597
+ begin
598
+ super
599
+ rescue NoMethodError => e
600
+ e.set_backtrace(caller)
601
+ raise e
602
+ end
603
+ end
604
+
605
+ # ----------------------------------------------------------------
606
+ # Child management
607
+ # ----------------------------------------------------------------
608
+
609
+ public # --------------------------------------------------------
610
+
611
+ #
612
+ # Return the Node that comes after the given Node in tree
613
+ # preorder.
614
+ #
615
+ def node_after(node)
616
+ node.parent.equal? self or
617
+ raise ArgumentError, "node is not a child"
618
+ fields = self.fields
619
+ i = node.instance_variable_get(:@parent_field).index + 1
620
+ (i...fields.length).each do |i|
621
+ f = fields[i]
622
+ if f.child? && (val = self.send(f.reader))
623
+ return val
624
+ end
625
+ end
626
+ return nil
627
+ end
628
+
629
+ #
630
+ # Return the Node that comes before the given Node in tree
631
+ # preorder.
632
+ #
633
+ def node_before(node)
634
+ node.parent.equal? self or
635
+ raise ArgumentError, "node is not a child"
636
+ fields = self.fields
637
+ i = node.instance_variable_get(:@parent_field).index - 1
638
+ i.downto(0) do |i|
639
+ f = fields[i]
640
+ if f.child? && (val = self.send(f.reader))
641
+ return val
642
+ end
643
+ end
644
+ return nil
645
+ end
646
+
647
+ #
648
+ # Remove the given Node.
649
+ #
650
+ def remove_node(node)
651
+ node.parent.equal? self or
652
+ raise ArgumentError, "node is not a child"
653
+ field = node.instance_variable_get(:@parent_field)
654
+ node.instance_variable_set(:@parent, nil)
655
+ node.instance_variable_set(:@parent_field, nil)
656
+ self.instance_variable_set(field.var, nil)
657
+ return self
658
+ end
659
+
660
+ #
661
+ # Replace `node' with `newnode'.
662
+ #
663
+ def replace_node(node, newnode=nil)
664
+ node.parent.equal? self or
665
+ raise ArgumentError, "node is not a child"
666
+ field = node.instance_variable_get(:@parent_field)
667
+ self.send(field.writer, newnode)
668
+ return self
669
+ end
670
+
671
+ # ----------------------------------------------------------------
672
+ # Node::Field
673
+ # ----------------------------------------------------------------
674
+
675
+ private # -------------------------------------------------------
676
+
677
+ class Field
678
+ attr_accessor :var, :reader, :writer, :init_key, :index,
679
+ :default
680
+
681
+ #
682
+ # True if this field is a child field, false otherwise.
683
+ #
684
+ attr_writer :child
685
+ def child?
686
+ @child
687
+ end
688
+
689
+ #
690
+ # Create a default value for this field. This differs from
691
+ # #default in that if it's a Proc, it is called and the result
692
+ # returned.
693
+ #
694
+ def make_default
695
+ if @default.respond_to? :call
696
+ @default.call
697
+ else
698
+ @default
699
+ end
700
+ end
701
+
702
+ def initialize(name, default)
703
+ name = name.to_s
704
+
705
+ @child = false
706
+ @reader = name.to_sym
707
+ @default = default
708
+
709
+ if name[-1] == ?? then name[-1] = '' end
710
+ @init_key = name.to_sym
711
+ @var = "@#{name}".to_sym
712
+ @writer = "#{name}=".to_sym
713
+ end
714
+ end
715
+
716
+ public # -------------------------------------------------------
717
+
718
+ #
719
+ # A position in a source file. All Nodes may have one in their
720
+ # #pos attribute.
721
+ #
722
+ class Pos
723
+ attr_accessor :filename, :line_num, :col_num
724
+ def initialize(filename, line_num, col_num)
725
+ @filename = filename
726
+ @line_num = line_num
727
+ @col_num = col_num
728
+ end
729
+ def to_s
730
+ (@filename ? "#@filename:" : '') << "#@line_num:#@col_num"
731
+ end
732
+ def <=>(x)
733
+ return nil if self.filename != x.filename
734
+ return (self.line_num <=> x.line_num).nonzero? ||
735
+ self.col_num <=> x.col_num
736
+ end
737
+ include Comparable
738
+ end
739
+ end
740
+ end