cast 0.1.0 → 0.2.0

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