casty 0.3.1

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,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