cast 0.0.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.
- data/README +6 -0
- data/doc/index.html +2513 -0
- data/install.rb +14 -0
- data/lib/c.tab.rb +3433 -0
- data/lib/c.y +935 -0
- data/lib/c_nodes.rb +1301 -0
- data/lib/cast.rb +9 -0
- data/lib/node.rb +744 -0
- data/lib/node_list.rb +842 -0
- data/lib/parse.rb +233 -0
- data/lib/to_debug.rb +59 -0
- data/lib/to_s.rb +538 -0
- data/test/common.rb +174 -0
- data/test/run.rb +5 -0
- data/test/test_c_nodes.rb +160 -0
- data/test/test_node.rb +1224 -0
- data/test/test_node_list.rb +2485 -0
- data/test/test_parse.rb +2014 -0
- data/test/test_parser.rb +2925 -0
- metadata +56 -0
data/lib/node_list.rb
ADDED
@@ -0,0 +1,842 @@
|
|
1
|
+
###
|
2
|
+
### ##################################################################
|
3
|
+
###
|
4
|
+
### NodeList and subclasses.
|
5
|
+
###
|
6
|
+
### ##################################################################
|
7
|
+
###
|
8
|
+
|
9
|
+
module C
|
10
|
+
## Declare all the classes, so we don't have to declare the
|
11
|
+
## inheritances later.
|
12
|
+
class NodeList < Node; abstract; end
|
13
|
+
class NodeArray < NodeList; end
|
14
|
+
class NodeChain < NodeList; end
|
15
|
+
|
16
|
+
###
|
17
|
+
### ================================================================
|
18
|
+
###
|
19
|
+
### NodeList
|
20
|
+
###
|
21
|
+
### Abstract base class of the Node list classes.
|
22
|
+
###
|
23
|
+
### ================================================================
|
24
|
+
###
|
25
|
+
class NodeList
|
26
|
+
def self.[] *args
|
27
|
+
new.concat(args)
|
28
|
+
end
|
29
|
+
|
30
|
+
include Enumerable
|
31
|
+
def size
|
32
|
+
length
|
33
|
+
end
|
34
|
+
|
35
|
+
def == other
|
36
|
+
return false if !other.is_a? C::NodeList
|
37
|
+
|
38
|
+
## none of the NodeList classes here have fields, but there's no
|
39
|
+
## reason why one can't subclass one to have fields
|
40
|
+
fields.each do |field|
|
41
|
+
mine = self .send(field.reader)
|
42
|
+
yours = other.send(field.reader)
|
43
|
+
mine == yours or return false
|
44
|
+
end
|
45
|
+
|
46
|
+
other = other.to_a
|
47
|
+
return false if other.length != self.length
|
48
|
+
each_with_index do |node, i|
|
49
|
+
return false if node != other[i]
|
50
|
+
end
|
51
|
+
return true
|
52
|
+
end
|
53
|
+
|
54
|
+
def hash
|
55
|
+
hash = 0
|
56
|
+
each do |node|
|
57
|
+
hash ^= node.hash
|
58
|
+
end
|
59
|
+
return hash
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
self.join ', '
|
64
|
+
end
|
65
|
+
|
66
|
+
def inspect
|
67
|
+
"#{self.class}[#{self.join(', ')}]"
|
68
|
+
end
|
69
|
+
|
70
|
+
protected # -----------------------------------------------------
|
71
|
+
|
72
|
+
###
|
73
|
+
### Return `[i, n, splat?]', where if `args' is used as an index
|
74
|
+
### to ::Array#[]=, it is equivalent to calling:
|
75
|
+
###
|
76
|
+
### val = args.pop
|
77
|
+
### if splat?
|
78
|
+
### array[i, n] = *val
|
79
|
+
### else
|
80
|
+
### array[i, n] = val
|
81
|
+
### end
|
82
|
+
###
|
83
|
+
def parse_index *args
|
84
|
+
## what we must do:
|
85
|
+
##
|
86
|
+
## -- move numbers into range 0..length-1
|
87
|
+
## -- i..j --> i...j+1
|
88
|
+
## -- i...j --> i, j-i
|
89
|
+
case args.length
|
90
|
+
when 1
|
91
|
+
arg = args.first
|
92
|
+
if arg.is_a? ::Range
|
93
|
+
if arg.exclude_end?
|
94
|
+
i = wrap_index(arg.begin)
|
95
|
+
j = wrap_index(arg.begin)
|
96
|
+
return [i, j-1, true]
|
97
|
+
else
|
98
|
+
i = wrap_index(arg.begin)
|
99
|
+
j = wrap_index(arg.begin)
|
100
|
+
return [i, j+1-i, true]
|
101
|
+
end
|
102
|
+
else
|
103
|
+
i = wrap_index(arg)
|
104
|
+
return [i, 1, false]
|
105
|
+
end
|
106
|
+
when 2
|
107
|
+
return [args[0], args[1], true]
|
108
|
+
else
|
109
|
+
raise ArgumentError, "wrong number of arguments"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
###
|
114
|
+
### Wrap the given index if less than 0, and return it.
|
115
|
+
###
|
116
|
+
def wrap_index i
|
117
|
+
i < 0 ? (i + length) : i
|
118
|
+
end
|
119
|
+
|
120
|
+
###
|
121
|
+
### Prepare the given nodes for addition. This means:
|
122
|
+
### -- clone any attached nodes as necessary
|
123
|
+
### -- set the nodes' parents to self.
|
124
|
+
###
|
125
|
+
### `oldnodes' are the nodes that will be replaced. These aren't
|
126
|
+
### cloned the first time they appear in `nodes'.
|
127
|
+
###
|
128
|
+
### Return the list of nodes to add.
|
129
|
+
###
|
130
|
+
def add_prep nodes, oldnodes=nil
|
131
|
+
if oldnodes
|
132
|
+
oldnodes = oldnodes.map{|n| n.object_id}
|
133
|
+
nodes.map! do |node|
|
134
|
+
if node.attached? && oldnodes.delete(node.object_id).nil?
|
135
|
+
node = node.clone
|
136
|
+
end
|
137
|
+
set_parent node, self
|
138
|
+
node
|
139
|
+
end
|
140
|
+
else
|
141
|
+
nodes.map! do |node|
|
142
|
+
node = node.clone if node.attached?
|
143
|
+
set_parent node, self
|
144
|
+
node
|
145
|
+
end
|
146
|
+
end
|
147
|
+
return nodes
|
148
|
+
end
|
149
|
+
|
150
|
+
###
|
151
|
+
### Set the parent of `node' to `val'.
|
152
|
+
###
|
153
|
+
def set_parent node, val
|
154
|
+
node.send(:parent=, val)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class NodeArray
|
159
|
+
def assert_invariants testcase
|
160
|
+
super
|
161
|
+
testcase.assert_same(::Array, @array)
|
162
|
+
@array.each_with_index do |node, i|
|
163
|
+
assert_same(i, node.instance_variable_get(:@parent_index))
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def initialize
|
168
|
+
super
|
169
|
+
@array = []
|
170
|
+
end
|
171
|
+
|
172
|
+
def dup
|
173
|
+
ret = super
|
174
|
+
ret.instance_variable_set(:@array, [])
|
175
|
+
dupes = self.map{|n| n.dup}
|
176
|
+
return ret.push(*dupes)
|
177
|
+
end
|
178
|
+
|
179
|
+
def clone
|
180
|
+
ret = super
|
181
|
+
ret.instance_variable_set(:@array, [])
|
182
|
+
clones = self.map{|n| n.clone}
|
183
|
+
return ret.push(*clones)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class NodeChain
|
188
|
+
def assert_invariants testcase
|
189
|
+
super
|
190
|
+
assert_same(@length.zero?, @first.nil?)
|
191
|
+
assert_same(@length.zero?, @last.nil?)
|
192
|
+
unless @length.zero?
|
193
|
+
assert_same(@first, self[0])
|
194
|
+
assert_same(@last, self[@length-1])
|
195
|
+
(0...@length.times).each do |i|
|
196
|
+
nodeprev = self[i].instance_variable_get(:@prev)
|
197
|
+
nodenext = self[i].instance_variable_get(:@next)
|
198
|
+
if i == 0
|
199
|
+
assert_nil(nodeprev)
|
200
|
+
else
|
201
|
+
assert_same(self[i-1], nodeprev)
|
202
|
+
end
|
203
|
+
|
204
|
+
if i == @length-1
|
205
|
+
assert_nil(nodenext)
|
206
|
+
else
|
207
|
+
assert_same(self[i+1], nodenext)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def initialize
|
214
|
+
super
|
215
|
+
@first = nil
|
216
|
+
@last = nil
|
217
|
+
@length = 0
|
218
|
+
end
|
219
|
+
|
220
|
+
def dup
|
221
|
+
ret = super
|
222
|
+
ret.instance_variable_set(:@first, nil)
|
223
|
+
ret.instance_variable_set(:@last, nil)
|
224
|
+
ret.instance_variable_set(:@length, 0)
|
225
|
+
dupes = self.map{|n| n.dup}
|
226
|
+
ret.push(*dupes)
|
227
|
+
return ret
|
228
|
+
end
|
229
|
+
|
230
|
+
def clone
|
231
|
+
ret = super
|
232
|
+
ret.instance_variable_set(:@first, nil)
|
233
|
+
ret.instance_variable_set(:@last, nil)
|
234
|
+
ret.instance_variable_set(:@length, 0)
|
235
|
+
clones = self.map{|n| n.clone}
|
236
|
+
ret.push(*clones)
|
237
|
+
return ret
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
###
|
242
|
+
### ----------------------------------------------------------------
|
243
|
+
### Methods called from children
|
244
|
+
### ----------------------------------------------------------------
|
245
|
+
###
|
246
|
+
|
247
|
+
class NodeArray
|
248
|
+
def node_after node
|
249
|
+
node.parent.equal? self or
|
250
|
+
raise ArgumentError, "node is not a child"
|
251
|
+
@array[index = node.instance_variable_get(:@parent_index)+1]
|
252
|
+
end
|
253
|
+
|
254
|
+
def node_before node
|
255
|
+
node.parent.equal? self or
|
256
|
+
raise ArgumentError, "node is not a child"
|
257
|
+
index = node.instance_variable_get(:@parent_index)
|
258
|
+
if index.zero?
|
259
|
+
return nil
|
260
|
+
else
|
261
|
+
return @array[index-1]
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def remove_node node
|
266
|
+
node.parent.equal? self or
|
267
|
+
raise ArgumentError, "node is not a child"
|
268
|
+
index = node.instance_variable_get(:@parent_index)
|
269
|
+
index.instance_variable_set(:@parent_index, nil)
|
270
|
+
removed_(@array[index])
|
271
|
+
@array.delete_at(index)
|
272
|
+
adjust_indices_(index)
|
273
|
+
return self
|
274
|
+
end
|
275
|
+
|
276
|
+
def insert_after node, *newnodes
|
277
|
+
node.parent.equal? self or
|
278
|
+
raise ArgumentError, "node is not a child"
|
279
|
+
index = node.instance_variable_get(:@parent_index) + 1
|
280
|
+
insert(index, *newnodes)
|
281
|
+
return self
|
282
|
+
end
|
283
|
+
def insert_before node, *newnodes
|
284
|
+
node.parent.equal? self or
|
285
|
+
raise ArgumentError, "node is not a child"
|
286
|
+
index = node.instance_variable_get(:@parent_index)
|
287
|
+
insert(index, *newnodes)
|
288
|
+
return self
|
289
|
+
end
|
290
|
+
def replace_node oldnode, *newnodes
|
291
|
+
oldnode.parent.equal? self or
|
292
|
+
raise ArgumentError, "node is not a child"
|
293
|
+
index = oldnode.instance_variable_get(:@parent_index)
|
294
|
+
self[index, 1] = newnodes
|
295
|
+
return self
|
296
|
+
end
|
297
|
+
|
298
|
+
private
|
299
|
+
|
300
|
+
###
|
301
|
+
### Adjust the indices of all elements from index `from_i' to the
|
302
|
+
### end.
|
303
|
+
###
|
304
|
+
def adjust_indices_ from_i
|
305
|
+
(from_i...@array.length).each do |i|
|
306
|
+
@array[i].instance_variable_set(:@parent_index, i)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
###
|
310
|
+
### Called when something was added.
|
311
|
+
###
|
312
|
+
def added_ *nodes
|
313
|
+
nodes.each do |n|
|
314
|
+
n.instance_variable_set(:@parent, self)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
###
|
318
|
+
### Called when something was removed.
|
319
|
+
###
|
320
|
+
def removed_ *nodes
|
321
|
+
nodes.each do |n|
|
322
|
+
n.instance_variable_set(:@parent, nil)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
class NodeChain
|
328
|
+
def node_after node
|
329
|
+
node.parent.equal? self or
|
330
|
+
raise ArgumentError, "node is not a child"
|
331
|
+
return node.instance_variable_get(:@next)
|
332
|
+
end
|
333
|
+
def node_before node
|
334
|
+
node.parent.equal? self or
|
335
|
+
raise ArgumentError, "node is not a child"
|
336
|
+
return node.instance_variable_get(:@prev)
|
337
|
+
end
|
338
|
+
def remove_node node
|
339
|
+
node.parent.equal? self or
|
340
|
+
raise ArgumentError, "node is not a child"
|
341
|
+
node_prev = node.instance_variable_get(:@prev)
|
342
|
+
node_next = node.instance_variable_get(:@next)
|
343
|
+
removed_(node)
|
344
|
+
link2_(node_prev, node_next)
|
345
|
+
return self
|
346
|
+
end
|
347
|
+
def insert_after node, *newnodes
|
348
|
+
node.parent.equal? self or
|
349
|
+
raise ArgumentError, "node is not a child"
|
350
|
+
newnodes = add_prep(newnodes)
|
351
|
+
node_next = node.instance_variable_get(:@next)
|
352
|
+
link_(node, newnodes, node_next)
|
353
|
+
added_(*newnodes)
|
354
|
+
return self
|
355
|
+
end
|
356
|
+
def insert_before node, *newnodes
|
357
|
+
node.parent.equal? self or
|
358
|
+
raise ArgumentError, "node is not a child"
|
359
|
+
newnodes = add_prep(newnodes)
|
360
|
+
node_prev = node.instance_variable_get(:@prev)
|
361
|
+
link_(node_prev, newnodes, node)
|
362
|
+
added_(*newnodes)
|
363
|
+
return self
|
364
|
+
end
|
365
|
+
def replace_node oldnode, *newnodes
|
366
|
+
oldnode.parent.equal? self or
|
367
|
+
raise ArgumentError, "node is not a child"
|
368
|
+
newnodes = add_prep(newnodes, [oldnode])
|
369
|
+
prev_node = oldnode.instance_variable_get(:@prev)
|
370
|
+
next_node = oldnode.instance_variable_get(:@next)
|
371
|
+
link_(prev_node, newnodes, next_node)
|
372
|
+
removed_(oldnode)
|
373
|
+
added_(*newnodes)
|
374
|
+
return self
|
375
|
+
end
|
376
|
+
###
|
377
|
+
### Called when something was added.
|
378
|
+
###
|
379
|
+
def added_ *newnodes
|
380
|
+
newnodes.each{|n| n.instance_variable_set(:@parent, self)}
|
381
|
+
@length += newnodes.length
|
382
|
+
end
|
383
|
+
###
|
384
|
+
### Called when something was removed.
|
385
|
+
###
|
386
|
+
def removed_ *nodes
|
387
|
+
nodes.each{|n| n.instance_variable_set(:@parent, nil)}
|
388
|
+
@length -= nodes.length
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
###
|
393
|
+
### ----------------------------------------------------------------
|
394
|
+
### Array methods
|
395
|
+
### ----------------------------------------------------------------
|
396
|
+
###
|
397
|
+
|
398
|
+
class NodeArray
|
399
|
+
%w[
|
400
|
+
first
|
401
|
+
last
|
402
|
+
length
|
403
|
+
[]
|
404
|
+
empty?
|
405
|
+
index
|
406
|
+
rindex
|
407
|
+
values_at
|
408
|
+
join
|
409
|
+
].each do |m|
|
410
|
+
eval "
|
411
|
+
def #{m} *args, &blk
|
412
|
+
@array.#{m} *args, &blk
|
413
|
+
end
|
414
|
+
"
|
415
|
+
end
|
416
|
+
|
417
|
+
%w[
|
418
|
+
each
|
419
|
+
reverse_each
|
420
|
+
each_index
|
421
|
+
].each do |m|
|
422
|
+
eval "
|
423
|
+
def #{m} *args, &blk
|
424
|
+
@array.#{m} *args, &blk
|
425
|
+
return self
|
426
|
+
end
|
427
|
+
"
|
428
|
+
end
|
429
|
+
|
430
|
+
def to_a
|
431
|
+
@array.dup
|
432
|
+
end
|
433
|
+
def push *nodes
|
434
|
+
nodes = add_prep(nodes)
|
435
|
+
i = @array.length
|
436
|
+
@array.push(*nodes)
|
437
|
+
added_(*nodes)
|
438
|
+
adjust_indices_(i)
|
439
|
+
return self
|
440
|
+
end
|
441
|
+
def unshift *nodes
|
442
|
+
nodes = add_prep(nodes)
|
443
|
+
@array.unshift(*nodes)
|
444
|
+
added_(*nodes)
|
445
|
+
adjust_indices_(0)
|
446
|
+
return self
|
447
|
+
end
|
448
|
+
def pop *args
|
449
|
+
if args.empty?
|
450
|
+
ret = @array.pop
|
451
|
+
removed_(ret)
|
452
|
+
return ret
|
453
|
+
else
|
454
|
+
ret = @array.pop(*args)
|
455
|
+
removed_ *ret
|
456
|
+
return ret
|
457
|
+
end
|
458
|
+
end
|
459
|
+
def shift *args
|
460
|
+
if args.empty?
|
461
|
+
ret = @array.shift
|
462
|
+
removed_ ret
|
463
|
+
else
|
464
|
+
ret = @array.shift(*args)
|
465
|
+
removed_ *ret
|
466
|
+
end
|
467
|
+
adjust_indices_(0)
|
468
|
+
return ret
|
469
|
+
end
|
470
|
+
def insert i, *newnodes
|
471
|
+
(0..@array.length).include? i or
|
472
|
+
raise IndexError, "index #{i} out of NodeList (length #{@array.length})"
|
473
|
+
newnodes = add_prep(newnodes)
|
474
|
+
@array.insert(i, *newnodes)
|
475
|
+
added_(*newnodes)
|
476
|
+
adjust_indices_(i)
|
477
|
+
return self
|
478
|
+
end
|
479
|
+
def << newnode
|
480
|
+
newnode = *add_prep([newnode])
|
481
|
+
@array << newnode
|
482
|
+
added_(newnode)
|
483
|
+
adjust_indices_(@array.length - 1)
|
484
|
+
return self
|
485
|
+
end
|
486
|
+
def []= *args
|
487
|
+
newnodes = args.pop
|
488
|
+
i, n, splat = parse_index(*args)
|
489
|
+
oldnodes = @array[i, n] or
|
490
|
+
raise IndexError, "index #{i} out of NodeList"
|
491
|
+
if splat
|
492
|
+
newnodes = add_prep(newnodes, oldnodes)
|
493
|
+
else
|
494
|
+
## newnodes is a single node (not an Array)
|
495
|
+
newnodes = add_prep([newnodes], [oldnodes])
|
496
|
+
end
|
497
|
+
@array[i, n] = newnodes
|
498
|
+
if splat
|
499
|
+
removed_(*oldnodes)
|
500
|
+
added_(*newnodes)
|
501
|
+
else
|
502
|
+
removed_(oldnodes)
|
503
|
+
added_(newnodes)
|
504
|
+
end
|
505
|
+
adjust_indices_(i)
|
506
|
+
return newnodes
|
507
|
+
end
|
508
|
+
def concat other
|
509
|
+
other = other.to_a
|
510
|
+
other = add_prep(other)
|
511
|
+
len = @array.length
|
512
|
+
@array.concat(other)
|
513
|
+
added_(*other)
|
514
|
+
adjust_indices_(len)
|
515
|
+
return self
|
516
|
+
end
|
517
|
+
def delete_at index
|
518
|
+
if index < @array.length
|
519
|
+
ret = @array.delete_at(index)
|
520
|
+
removed_(ret)
|
521
|
+
adjust_indices_(index)
|
522
|
+
return ret
|
523
|
+
else
|
524
|
+
return nil
|
525
|
+
end
|
526
|
+
end
|
527
|
+
def clear
|
528
|
+
nodes = @array.dup
|
529
|
+
@array.clear
|
530
|
+
removed_(*nodes)
|
531
|
+
return self
|
532
|
+
end
|
533
|
+
def replace other
|
534
|
+
other = other.to_a
|
535
|
+
other = add_prep(other)
|
536
|
+
oldnodes = @array.dup
|
537
|
+
@array.replace(other)
|
538
|
+
removed_(*oldnodes)
|
539
|
+
added_(*@array)
|
540
|
+
adjust_indices_(0)
|
541
|
+
return self
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
class NodeChain
|
546
|
+
###
|
547
|
+
### const methods
|
548
|
+
###
|
549
|
+
def first n=nil
|
550
|
+
if n.nil?
|
551
|
+
return @first
|
552
|
+
else
|
553
|
+
n = length if n > length
|
554
|
+
node = @first
|
555
|
+
ret = ::Array.new(n) do
|
556
|
+
r = node
|
557
|
+
node = node.instance_variable_get(:@next)
|
558
|
+
r
|
559
|
+
end
|
560
|
+
return ret
|
561
|
+
end
|
562
|
+
end
|
563
|
+
def last n=nil
|
564
|
+
if n.nil?
|
565
|
+
return @last
|
566
|
+
else
|
567
|
+
n = length if n > length
|
568
|
+
node = @last
|
569
|
+
ret = ::Array.new(n)
|
570
|
+
(n-1).downto(0) do |i|
|
571
|
+
ret[i] = node
|
572
|
+
node = node.instance_variable_get(:@prev)
|
573
|
+
end
|
574
|
+
return ret
|
575
|
+
end
|
576
|
+
end
|
577
|
+
def length
|
578
|
+
@length
|
579
|
+
end
|
580
|
+
def each
|
581
|
+
node = @first
|
582
|
+
until node.nil?
|
583
|
+
yield node
|
584
|
+
node = node.instance_variable_get(:@next)
|
585
|
+
end
|
586
|
+
return self
|
587
|
+
end
|
588
|
+
def reverse_each
|
589
|
+
node = @last
|
590
|
+
until node.nil?
|
591
|
+
yield node
|
592
|
+
node = node.instance_variable_get(:@prev)
|
593
|
+
end
|
594
|
+
return self
|
595
|
+
end
|
596
|
+
def to_a
|
597
|
+
node = @first
|
598
|
+
ret = ::Array.new(@length) do
|
599
|
+
r = node
|
600
|
+
node = node.instance_variable_get(:@next)
|
601
|
+
r
|
602
|
+
end
|
603
|
+
return ret
|
604
|
+
end
|
605
|
+
def [] *args
|
606
|
+
i, n, splat = parse_index(*args)
|
607
|
+
return nil if i >= @length
|
608
|
+
node = get_(i)
|
609
|
+
if splat
|
610
|
+
## return an array of Nodes
|
611
|
+
n = length-i if n > length-i
|
612
|
+
ret = ::Array.new(n) do
|
613
|
+
r = node
|
614
|
+
node = node.next
|
615
|
+
r
|
616
|
+
end
|
617
|
+
return ret
|
618
|
+
else
|
619
|
+
## return a Node
|
620
|
+
return node
|
621
|
+
end
|
622
|
+
end
|
623
|
+
def each_index
|
624
|
+
@length.times{|i| yield i}
|
625
|
+
return self
|
626
|
+
end
|
627
|
+
def empty?
|
628
|
+
@length.zero?
|
629
|
+
end
|
630
|
+
def index node
|
631
|
+
curr = @first
|
632
|
+
i = 0
|
633
|
+
while curr
|
634
|
+
return i if curr == node
|
635
|
+
curr = curr.instance_variable_get(:@next)
|
636
|
+
i += 1
|
637
|
+
end
|
638
|
+
return nil
|
639
|
+
end
|
640
|
+
def rindex node
|
641
|
+
curr = @last
|
642
|
+
i = @length - 1
|
643
|
+
while curr
|
644
|
+
return i if curr == node
|
645
|
+
curr = curr.instance_variable_get(:@prev)
|
646
|
+
i -= 1
|
647
|
+
end
|
648
|
+
return nil
|
649
|
+
end
|
650
|
+
def values_at *args
|
651
|
+
args.map!{|i| self[i]}
|
652
|
+
end
|
653
|
+
def join *args
|
654
|
+
self.to_a.join(*args)
|
655
|
+
end
|
656
|
+
|
657
|
+
###
|
658
|
+
### non-const methods
|
659
|
+
###
|
660
|
+
def push *newnodes
|
661
|
+
newnodes = add_prep(newnodes)
|
662
|
+
added_(*newnodes)
|
663
|
+
link_(@last, newnodes, nil)
|
664
|
+
return self
|
665
|
+
end
|
666
|
+
def << newnode
|
667
|
+
return push(newnode)
|
668
|
+
end
|
669
|
+
def unshift *newnodes
|
670
|
+
newnodes = add_prep(newnodes)
|
671
|
+
added_(*newnodes)
|
672
|
+
link_(nil, newnodes, @first)
|
673
|
+
return self
|
674
|
+
end
|
675
|
+
def pop n=nil
|
676
|
+
if n
|
677
|
+
## return an Array of Nodes
|
678
|
+
ret = last(n)
|
679
|
+
return ret if ret.empty?
|
680
|
+
link2_(ret.first.instance_variable_get(:@prev), nil)
|
681
|
+
removed_(*ret)
|
682
|
+
return ret
|
683
|
+
else
|
684
|
+
return nil if empty?
|
685
|
+
## return a Node
|
686
|
+
ret = @last
|
687
|
+
link2_(@last.instance_variable_get(:@prev), nil)
|
688
|
+
removed_(ret)
|
689
|
+
return ret
|
690
|
+
end
|
691
|
+
end
|
692
|
+
def shift n=nil
|
693
|
+
if n
|
694
|
+
## return an Array of Nodes
|
695
|
+
ret = first(n)
|
696
|
+
return ret if ret.empty?
|
697
|
+
link2_(nil, ret.last.instance_variable_get(:@next))
|
698
|
+
removed_(*ret)
|
699
|
+
return ret
|
700
|
+
else
|
701
|
+
return nil if empty?
|
702
|
+
## return a Node
|
703
|
+
ret = @first
|
704
|
+
link2_(nil, @first.instance_variable_get(:@next))
|
705
|
+
removed_(ret)
|
706
|
+
return ret
|
707
|
+
end
|
708
|
+
end
|
709
|
+
def insert i, *newnodes
|
710
|
+
(0..@length).include? i or
|
711
|
+
raise IndexError, "index #{i} out of NodeList"
|
712
|
+
if i == @length
|
713
|
+
return push(*newnodes)
|
714
|
+
else
|
715
|
+
insert_before(self[i], *newnodes)
|
716
|
+
end
|
717
|
+
end
|
718
|
+
def []= *args
|
719
|
+
newnodes = args.pop
|
720
|
+
i, n, splat = parse_index(*args)
|
721
|
+
oldnodes = self[i, n] or
|
722
|
+
raise IndexError, "index #{i} out of NodeList"
|
723
|
+
unless n.zero?
|
724
|
+
prev_node = n.instance_variable_get(:@prev)
|
725
|
+
next_node = n.instance_variable_get(:@next)
|
726
|
+
link2_(prev, next_node)
|
727
|
+
removed_(*oldnodes)
|
728
|
+
end
|
729
|
+
if i == @length
|
730
|
+
if splat
|
731
|
+
push(*newnodes)
|
732
|
+
else
|
733
|
+
push(newnodes)
|
734
|
+
end
|
735
|
+
else
|
736
|
+
node = get_(i)
|
737
|
+
if splat
|
738
|
+
insert_before(node, *newnodes)
|
739
|
+
else
|
740
|
+
insert_before(node, newnodes)
|
741
|
+
end
|
742
|
+
end
|
743
|
+
return newnodes
|
744
|
+
end
|
745
|
+
def concat other
|
746
|
+
return push(*other.to_a)
|
747
|
+
end
|
748
|
+
def delete_at index
|
749
|
+
node = self[index]
|
750
|
+
remove_node(node)
|
751
|
+
return node
|
752
|
+
end
|
753
|
+
def clear
|
754
|
+
each{|n| set_parent(n, nil)}
|
755
|
+
@first = @last = nil
|
756
|
+
@length = 0
|
757
|
+
return self
|
758
|
+
end
|
759
|
+
def replace other
|
760
|
+
return clear.push(*other.to_a)
|
761
|
+
end
|
762
|
+
|
763
|
+
private
|
764
|
+
###
|
765
|
+
### Link up `nodes' between `a' and `b'.
|
766
|
+
###
|
767
|
+
def link_ a, nodes, b
|
768
|
+
if nodes.empty?
|
769
|
+
if a.nil?
|
770
|
+
@first = b
|
771
|
+
else
|
772
|
+
a.instance_variable_set(:@next, b)
|
773
|
+
end
|
774
|
+
if b.nil?
|
775
|
+
@last = a
|
776
|
+
else
|
777
|
+
b.instance_variable_set(:@prev, a)
|
778
|
+
end
|
779
|
+
else
|
780
|
+
## connect `a' and `b'
|
781
|
+
first = nodes.first
|
782
|
+
if a.nil?
|
783
|
+
@first = first
|
784
|
+
else
|
785
|
+
a.instance_variable_set(:@next, first)
|
786
|
+
end
|
787
|
+
last = nodes.last
|
788
|
+
if b.nil?
|
789
|
+
@last = last
|
790
|
+
else
|
791
|
+
b.instance_variable_set(:@prev, last)
|
792
|
+
end
|
793
|
+
|
794
|
+
## connect `nodes'
|
795
|
+
if nodes.length == 1
|
796
|
+
node = nodes[0]
|
797
|
+
node.instance_variable_set(:@prev, a)
|
798
|
+
node.instance_variable_set(:@next, b)
|
799
|
+
else
|
800
|
+
first.instance_variable_set(:@next, nodes[ 1])
|
801
|
+
first.instance_variable_set(:@prev, a)
|
802
|
+
last. instance_variable_set(:@prev, nodes[-2])
|
803
|
+
last. instance_variable_set(:@next, b)
|
804
|
+
(1...nodes.length-1).each do |i|
|
805
|
+
n = nodes[i]
|
806
|
+
n.instance_variable_set(:@prev, nodes[i-1])
|
807
|
+
n.instance_variable_set(:@next, nodes[i+1])
|
808
|
+
end
|
809
|
+
end
|
810
|
+
end
|
811
|
+
end
|
812
|
+
### Special case for 2
|
813
|
+
def link2_ a, b
|
814
|
+
if a.nil?
|
815
|
+
@first = b
|
816
|
+
else
|
817
|
+
a.instance_variable_set(:@next, b) unless a.nil?
|
818
|
+
end
|
819
|
+
if b.nil?
|
820
|
+
@last = a
|
821
|
+
else
|
822
|
+
b.instance_variable_set(:@prev, a) unless b.nil?
|
823
|
+
end
|
824
|
+
end
|
825
|
+
###
|
826
|
+
### Return the `i'th Node. Assume `i' is in 0...length.
|
827
|
+
###
|
828
|
+
def get_ i
|
829
|
+
## return a Node
|
830
|
+
if i < (@length >> 1)
|
831
|
+
## go from the beginning
|
832
|
+
node = @first
|
833
|
+
i.times{node = node.next}
|
834
|
+
else
|
835
|
+
## go from the end
|
836
|
+
node = @last
|
837
|
+
(@length - 1 - i).times{node = node.prev}
|
838
|
+
end
|
839
|
+
return node
|
840
|
+
end
|
841
|
+
end
|
842
|
+
end
|