~ubuntu-branches/ubuntu/precise/rakudo/precise

« back to all changes in this revision

Viewing changes to src/classes/List.pir

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghedini
  • Date: 2011-05-17 11:31:09 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20110517113109-rmfir654u1axbpt4
Tags: 0.1~2011.04-1
* New upstream release (Closes: #601862, #585762, #577502)
* New maintainer
* Switch to 3.0 (quilt) format
* Update dependencies (Closes: #584498)
* Update debian/copyright to lastest DEP5 revision
* Do not generate/install perl6 manpage (now done by the build system)
* Enable tests
* Bump Standards-Version to 3.9.2 (no changes needed)
* Do not install extra LICENSE files and duplicated docs
* Remove debian/clean (no more needed)
* Add Vcs-* fields in debian/control
* Rewrite (short) description
* Update upstream copyright years
* Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
## $Id$
2
 
 
3
 
=head1 NAME
4
 
 
5
 
src/classes/List.pir - Perl 6 List class and related functions
6
 
 
7
 
=cut
8
 
 
9
 
.namespace []
10
 
.sub '' :anon :load :init
11
 
    .local pmc p6meta, listproto
12
 
    p6meta = get_hll_global ['Perl6Object'], '$!P6META'
13
 
    listproto = p6meta.'new_class'('List', 'parent'=>'parrot;ResizablePMCArray Any')
14
 
    $P0 = get_hll_global 'Positional'
15
 
    $P0 = $P0.'!select'()
16
 
    p6meta.'add_role'($P0, 'to'=>listproto)
17
 
    p6meta.'register'('ResizablePMCArray', 'parent'=>listproto, 'protoobject'=>listproto)
18
 
 
19
 
.end
20
 
 
21
 
=head2 Methods
22
 
 
23
 
=over
24
 
 
25
 
=item ACCEPTS
26
 
 
27
 
Smart-matches against the list.
28
 
 
29
 
=cut
30
 
 
31
 
.namespace ['List']
32
 
.sub 'ACCEPTS' :method
33
 
    .param pmc topic
34
 
 
35
 
    # What do we have?
36
 
    $I0 = isa topic, 'List' # Catches Array too
37
 
    if $I0 goto array
38
 
    # XXX When we have a Set type, need to handle that here too.
39
 
    topic = topic.'list'()
40
 
 
41
 
    # Need to DWIM on *s.
42
 
  array:
43
 
    .local pmc it_a, it_b, cur_a, cur_b
44
 
    it_a = iter self
45
 
    it_b = iter topic
46
 
    unless it_a goto it_loop_end
47
 
    unless it_b goto it_loop_end
48
 
    cur_a = shift it_a
49
 
  it_loop:
50
 
    unless it_b goto it_loop_end
51
 
    cur_b = shift it_b
52
 
 
53
 
    # If there curent thing is Whatever, need special handling.
54
 
    $I0 = isa cur_a, ['Whatever']
55
 
    unless $I0 goto not_whatever
56
 
 
57
 
    # If we don't have anything left other than the Whatever, it matches any
58
 
    # ending. Otherwise, we see what we're next looking for, and keep pulling
59
 
    # from the topic until we see it, or until we run out of topic in which
60
 
    # case we can't get no satisfaction.
61
 
  handle_whatever:
62
 
    unless it_a goto true
63
 
    .local pmc looking_for
64
 
    looking_for = shift it_a
65
 
    $I0 = isa looking_for, ['Whatever']
66
 
    if $I0 goto handle_whatever
67
 
  whatever_loop:
68
 
    $P0 = 'infix:==='(looking_for, cur_b)
69
 
    if $P0 goto found_looking_for
70
 
    unless it_b goto false
71
 
    cur_b = shift it_b
72
 
    goto whatever_loop
73
 
  found_looking_for:
74
 
    unless it_a goto it_loop_end
75
 
    cur_a = shift it_a
76
 
    goto it_loop
77
 
 
78
 
  not_whatever:
79
 
    # Not whatever - check a against b, and pull another a for the next time
80
 
    # around the loop, unless we've run out of b (note that if it's a whatever
81
 
    # then it doesn't matter if we ran out of b; if it's not and we ran out of
82
 
    # list b then we fail).
83
 
    $I0 = 'infix:==='(cur_a, cur_b)
84
 
    unless $I0 goto false
85
 
    unless it_a goto it_loop_end
86
 
    cur_a = shift it_a
87
 
    $I0 = isa cur_a, ['Whatever']
88
 
    if $I0 goto handle_whatever
89
 
    unless it_b goto false
90
 
    goto it_loop
91
 
  it_loop_end:
92
 
    if it_a goto false
93
 
    if it_b goto false
94
 
  true:
95
 
    $P0 = get_hll_global [ 'Bool' ], 'True'
96
 
    .return ($P0)
97
 
  false:
98
 
    $P0 = get_hll_global [ 'Bool' ], 'False'
99
 
    .return ($P0)
100
 
.end
101
 
 
102
 
 
103
 
=item item
104
 
 
105
 
A List in item context becomes an Array.
106
 
 
107
 
=cut
108
 
 
109
 
.namespace ['List']
110
 
.sub 'item' :method
111
 
    .tailcall self.'Array'()
112
 
.end
113
 
 
114
 
.namespace []
115
 
.sub 'list'
116
 
    .param pmc values          :slurpy
117
 
    .tailcall values.'!flatten'()
118
 
.end
119
 
 
120
 
 
121
 
=item !STORE(source)
122
 
 
123
 
Store the values from C<source> into C<self>.
124
 
 
125
 
=cut
126
 
 
127
 
.namespace ['List']
128
 
.sub '!STORE' :method
129
 
    .param pmc source
130
 
 
131
 
    ##  get the list of containers and sources
132
 
    .local pmc list
133
 
    $P0 = new ['List']
134
 
    splice $P0, self, 0, 0
135
 
    list = $P0
136
 
    source = source.'list'()
137
 
    source.'!flatten'()
138
 
 
139
 
    ##  now, go through our list of containers, flattening
140
 
    ##  any intermediate lists we find, and marking each
141
 
    ##  container with a property so we can clone it in source
142
 
    ##  if needed
143
 
    .local pmc true
144
 
    .local int i
145
 
    true = box 1
146
 
    i = 0
147
 
  mark_loop:
148
 
    $I0 = elements list
149
 
    unless i < $I0 goto mark_done
150
 
    .local pmc cont
151
 
    cont = list[i]
152
 
    $I0 = isa cont, ['Perl6Scalar']
153
 
    if $I0 goto mark_next
154
 
    $I0 = isa cont, ['Perl6Array']
155
 
    if $I0 goto mark_next
156
 
    $I0 = does cont, 'array'
157
 
    unless $I0 goto mark_next
158
 
    splice list, cont, $I0, 1
159
 
    goto mark_loop
160
 
  mark_next:
161
 
    setprop cont, 'target', true
162
 
    inc i
163
 
    goto mark_loop
164
 
  mark_done:
165
 
 
166
 
    ## now build our 'real' source list, cloning any targets we encounter
167
 
    .local pmc slist, it
168
 
    slist = new ['List']
169
 
    it = iter source
170
 
  source_loop:
171
 
    unless it goto source_done
172
 
    $P0 = shift it
173
 
    $P1 = getprop 'target', $P0
174
 
    if null $P1 goto source_next
175
 
    $P0 = clone $P0
176
 
  source_next:
177
 
    push slist, $P0
178
 
    goto source_loop
179
 
  source_done:
180
 
 
181
 
    ## now perform the assignments, clearing targets as we go
182
 
    .local pmc pmcnull
183
 
    null pmcnull
184
 
    it = iter list
185
 
  assign_loop:
186
 
    unless it goto assign_done
187
 
    .local pmc cont
188
 
    cont = shift it
189
 
    setprop cont, 'target', pmcnull
190
 
    $I0 = isa cont, 'Perl6Scalar'
191
 
    if $I0 goto assign_scalar
192
 
    $I0 = isa cont, 'Perl6Array'
193
 
    if $I0 goto assign_array
194
 
    $I0 = isa cont, 'Perl6Hash'
195
 
    if $I0 goto assign_hash
196
 
  assign_scalar:
197
 
    if slist goto have_slist
198
 
    slist = new ['Nil']
199
 
  have_slist:
200
 
    $P0 = shift slist
201
 
    'infix:='(cont, $P0)
202
 
    goto assign_loop
203
 
  assign_array:
204
 
  assign_hash:
205
 
    cont.'!STORE'(slist)
206
 
    slist = new ['Nil']
207
 
    goto assign_loop
208
 
  assign_done:
209
 
    .return (list)
210
 
.end
211
 
 
212
 
 
213
 
=back
214
 
 
215
 
=head2 Coercion methods
216
 
 
217
 
=over
218
 
 
219
 
=item Iterator
220
 
 
221
 
=cut
222
 
 
223
 
.namespace ['List']
224
 
.sub 'Iterator' :method
225
 
    self.'!flatten'()
226
 
    $P0 = iter self
227
 
    .return ($P0)
228
 
.end
229
 
 
230
 
 
231
 
=item Scalar
232
 
 
233
 
A list in Scalar context becomes a Scalar containing an Array.
234
 
 
235
 
=cut
236
 
 
237
 
.sub 'Scalar' :method
238
 
    $P0 = self.'Array'()
239
 
    $P0 = root_new ['parrot';'Perl6Scalar'], $P0
240
 
    .return ($P0)
241
 
.end
242
 
 
243
 
# FIXME:  :vtable('get_string') is wrong here.
244
 
.sub 'Str' :method :vtable('get_string')
245
 
    self.'!flatten'()
246
 
    $S0 = join ' ', self
247
 
    .return ($S0)
248
 
.end
249
 
 
250
 
=back
251
 
 
252
 
=head2 Methods
253
 
 
254
 
=over
255
 
 
256
 
=item elems()
257
 
 
258
 
Return the number of elements in the list.
259
 
 
260
 
=cut
261
 
 
262
 
.namespace ['List']
263
 
.sub 'elems' :method :multi() :vtable('get_number') :subid('list_elems')
264
 
    self.'!flatten'()
265
 
    $I0 = elements self
266
 
    .return ($I0)
267
 
.end
268
 
.sub '' :init :load
269
 
    .local pmc block, signature
270
 
    .const 'Sub' $P0 = "list_elems"
271
 
    block = $P0
272
 
    signature = allocate_signature 1
273
 
    setprop block, "$!signature", signature
274
 
    $P0 = get_hll_global 'List'
275
 
    null $P1
276
 
    set_signature_elem signature, 0, "self", SIG_ELEM_INVOCANT_AND_MULTI_INVOCANT, $P0, $P1, $P1, $P1, $P1, $P1
277
 
    '!TOPERL6MULTISUB'(block)
278
 
.end
279
 
 
280
 
 
281
 
=back
282
 
 
283
 
=head2 Private methods
284
 
 
285
 
=over 4
286
 
 
287
 
=item !flatten()
288
 
 
289
 
Flatten the invocant, as in list context.  This doesn't necessarily
290
 
make the list eager, it just brings any nested Lists to the top
291
 
layer.  It will likely change substantially when we have lazy lists.
292
 
 
293
 
=cut
294
 
 
295
 
.sub '!flatten' :method
296
 
    .param int size            :optional
297
 
    .param int has_size        :opt_flag
298
 
 
299
 
    ##  we use the 'elements' opcode here because we want the true length
300
 
    .local int len, i
301
 
    len = elements self
302
 
    i = 0
303
 
  flat_loop:
304
 
    if i >= len goto flat_end
305
 
    unless has_size goto flat_loop_1
306
 
    if i >= size goto flat_end
307
 
  flat_loop_1:
308
 
    .local pmc elem
309
 
    elem = self[i]
310
 
    $I0 = isa elem, 'Perl6Scalar'
311
 
    if $I0 goto flat_next
312
 
    # always treat a Junction, Role and Whatever as one item, whether they can !flatten or not
313
 
    # XXX this is due to C<can> giving dubious answers due to auto-thread/pun/closure creation
314
 
    $I0 = isa elem, 'Junction'
315
 
    if $I0 goto flat_next
316
 
    $I0 = isa elem, 'Whatever'
317
 
    if $I0 goto flat_next
318
 
    $I0 = isa elem, 'Perl6Role'
319
 
    if $I0 goto flat_next
320
 
    $I0 = isa elem, 'P6role'
321
 
    if $I0 goto flat_next
322
 
    $I0 = isa elem, 'MultiSub'
323
 
    if $I0 goto flat_next
324
 
    $I0 = can elem, '!flatten'
325
 
    if $I0 goto flat_elem
326
 
    $I0 = does elem, 'array'
327
 
    unless $I0 goto flat_next
328
 
    splice self, elem, i, 1
329
 
    len = elements self
330
 
    goto flat_loop
331
 
  flat_next:
332
 
    inc i
333
 
    goto flat_loop
334
 
  flat_elem:
335
 
    elem = elem.'!flatten'()
336
 
    splice self, elem, i, 1
337
 
    $I0 = elements elem
338
 
    i += $I0
339
 
    len = elements self
340
 
    goto flat_loop
341
 
  flat_end:
342
 
    $I0 = isa self, 'List'
343
 
    if $I0 goto end
344
 
    self.'list'()
345
 
  end:
346
 
    .return (self)
347
 
.end
348
 
 
349
 
 
350
 
=item uniq(...)
351
 
 
352
 
=cut
353
 
 
354
 
# TODO Rewrite it. It's too naive.
355
 
 
356
 
.namespace ['List']
357
 
.sub 'uniq' :method
358
 
    .param pmc comparer :optional
359
 
    .param int has_comparer :opt_flag
360
 
 
361
 
    if has_comparer goto have_comparer
362
 
    comparer = get_hll_global 'infix:eq'
363
 
  have_comparer:
364
 
 
365
 
    .local pmc ulist
366
 
    $P0 = get_hll_global 'List'
367
 
    ulist = $P0.'new'()
368
 
 
369
 
    .local pmc it_inner, it_outer, val
370
 
    it_outer = iter self
371
 
  outer_loop:
372
 
    unless it_outer goto outer_done
373
 
    val = shift it_outer
374
 
    it_inner = iter ulist
375
 
  inner_loop:
376
 
    unless it_inner goto inner_done
377
 
    $P0 = shift it_inner
378
 
    $P1 = comparer(val, $P0)
379
 
    if $P1 goto outer_loop
380
 
    goto inner_loop
381
 
  inner_done:
382
 
    ulist.'push'(val)
383
 
    goto outer_loop
384
 
 
385
 
  outer_done:
386
 
    .return (ulist)
387
 
.end
388
 
 
389
 
 
390
 
.namespace []
391
 
.sub 'uniq' :multi('Block')
392
 
    .param pmc comparer
393
 
    .param pmc values :slurpy
394
 
    values.'!flatten'()
395
 
    .tailcall values.'uniq'(comparer)
396
 
.end
397
 
 
398
 
.sub 'uniq' :multi()
399
 
    .param pmc values :slurpy
400
 
    values.'!flatten'()
401
 
    .tailcall values.'uniq'()
402
 
.end
403
 
 
404
 
 
405
 
=back
406
 
 
407
 
=head1 Functions
408
 
 
409
 
=over 4
410
 
 
411
 
=item C<infix:,(...)>
412
 
 
413
 
Operator form for building a list from its arguments.
414
 
 
415
 
=cut
416
 
 
417
 
.namespace []
418
 
.sub 'infix:,'
419
 
    .param pmc args            :slurpy
420
 
    .tailcall args.'list'()
421
 
.end
422
 
 
423
 
 
424
 
=item C<infix:Z(...)>
425
 
 
426
 
The zip operator.
427
 
 
428
 
=cut
429
 
 
430
 
.sub 'infix:Z'
431
 
    .param pmc arglist :slurpy
432
 
    .local pmc result
433
 
 
434
 
    # create a list to hold the results
435
 
    result = new ['List']
436
 
 
437
 
    unless arglist goto result_done
438
 
 
439
 
    # create a set of iterators, one per argument
440
 
    .local pmc iterlist, arglist_it
441
 
    iterlist = root_new ['parrot';'ResizablePMCArray']
442
 
    arglist_it = iter arglist
443
 
  arglist_loop:
444
 
    unless arglist_it goto arglist_done
445
 
    .local pmc arg, arg_it
446
 
    arg = shift arglist_it
447
 
    arg_it = arg.'iterator'()
448
 
    push iterlist, arg_it
449
 
    goto arglist_loop
450
 
  arglist_done:
451
 
 
452
 
    # repeatedly loop through the argument iterators in parallel,
453
 
    # building result elements as we go.  When we reach
454
 
    # an argument iterator with no more elements, we're done.
455
 
 
456
 
  outer_loop:
457
 
    .local pmc iterlist_it, reselem
458
 
    iterlist_it = iter iterlist
459
 
    reselem = new ['List']
460
 
  iterlist_loop:
461
 
    unless iterlist_it goto iterlist_done
462
 
    arg_it = shift iterlist_it
463
 
    unless arg_it goto result_done
464
 
    $P0 = shift arg_it
465
 
    reselem.'push'($P0)
466
 
    goto iterlist_loop
467
 
  iterlist_done:
468
 
    result.'push'(reselem)
469
 
    goto outer_loop
470
 
 
471
 
  result_done:
472
 
    .return (result)
473
 
.end
474
 
 
475
 
 
476
 
=item C<infix:X(...)>
477
 
 
478
 
The non-hyper cross operator.
479
 
 
480
 
=cut
481
 
 
482
 
.sub 'infix:X'
483
 
    .param pmc args            :slurpy
484
 
    .local pmc res
485
 
 
486
 
    .local pmc res, outer, inner, it, val
487
 
    res = new ['List']
488
 
 
489
 
    ##  if the are no arguments, result is empty list
490
 
    unless args goto done
491
 
 
492
 
    ##  get the first arg in list context
493
 
    outer = shift args
494
 
    outer = 'list'(outer)
495
 
 
496
 
    ##  if this argument is empty, result is empty list
497
 
    unless outer goto done
498
 
 
499
 
    ##  if no more args, then build result from only arg
500
 
    unless args goto one_arg
501
 
 
502
 
    ##  There are more args, so recursively compute their cross.
503
 
    ##  If that list is empty, our cross is empty.
504
 
    inner = 'infix:X'(args :flat)
505
 
    unless inner goto done
506
 
 
507
 
    ##  otherwise, loop through all elements of our first arg
508
 
    it = iter outer
509
 
  outer_loop:
510
 
    unless it goto done
511
 
    val = shift it
512
 
    ##  add the value to a clone of each inner result list
513
 
    $P1 = iter inner
514
 
  inner_loop:
515
 
    unless $P1 goto outer_loop
516
 
    ##  get a result list, clone it
517
 
    $P0 = shift $P1
518
 
    $P0 = clone $P0
519
 
    ##  add our outer value to the beginning
520
 
    unshift $P0, val
521
 
    ##  save it in the result list
522
 
    push res, $P0
523
 
    goto inner_loop
524
 
 
525
 
    ##  if call to infix:X had only one argument, our result
526
 
    ##  is a list of 1-element lists.
527
 
  one_arg:
528
 
    it = iter outer
529
 
  one_arg_loop:
530
 
    unless it goto done
531
 
    val = shift it
532
 
    $P0 = new ['List']
533
 
    push $P0, val
534
 
    push res, $P0
535
 
    goto one_arg_loop
536
 
 
537
 
  done:
538
 
    .return (res)
539
 
.end
540
 
 
541
 
 
542
 
=item C<infix:min(...)>
543
 
 
544
 
The min operator.
545
 
 
546
 
=cut
547
 
 
548
 
.sub 'infix:min'
549
 
    .param pmc args :slurpy
550
 
 
551
 
    # If we have no arguments, undefined.
552
 
    .local int elems
553
 
    elems = elements args
554
 
    if elems > 0 goto have_args
555
 
    $P0 = root_new ['parrot';'Undef']
556
 
    .return($P0)
557
 
have_args:
558
 
 
559
 
    # Find minimum.
560
 
    .local pmc cur_min, it
561
 
    cur_min = args[0]
562
 
    it = iter args
563
 
find_min_loop:
564
 
    unless it goto find_min_loop_end
565
 
    $P0 = shift it
566
 
    $I0 = 'infix:cmp'($P0, cur_min)
567
 
    unless $I0 < 0 goto find_min_loop
568
 
    set cur_min, $P0
569
 
    goto find_min_loop
570
 
find_min_loop_end:
571
 
 
572
 
    .return(cur_min)
573
 
.end
574
 
 
575
 
 
576
 
=item C<infix:max(...)>
577
 
 
578
 
The max operator.
579
 
 
580
 
=cut
581
 
 
582
 
.sub 'infix:max'
583
 
    .param pmc args :slurpy
584
 
 
585
 
    # If we have no arguments, undefined.
586
 
    .local int elems
587
 
    elems = elements args
588
 
    if elems > 0 goto have_args
589
 
    $P0 = root_new ['parrot';'Undef']
590
 
    .return($P0)
591
 
have_args:
592
 
 
593
 
    # Find maximum.
594
 
    .local pmc cur_max, it
595
 
    cur_max = args[0]
596
 
    it = iter args
597
 
find_max_loop:
598
 
    unless it goto find_max_loop_end
599
 
    $P0 = shift it
600
 
    $I0 = 'infix:cmp'($P0, cur_max)
601
 
    unless $I0 > 0 goto find_max_loop
602
 
    set cur_max, $P0
603
 
    goto find_max_loop
604
 
find_max_loop_end:
605
 
 
606
 
    .return(cur_max)
607
 
.end
608
 
 
609
 
## TODO: zip
610
 
 
611
 
=back
612
 
 
613
 
=cut
614
 
 
615
 
# Local Variables:
616
 
#   mode: pir
617
 
#   fill-column: 100
618
 
# End:
619
 
# vim: expandtab shiftwidth=4 ft=pir: