5
src/classes/List.pir - Perl 6 List class and related functions
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'
16
p6meta.'add_role'($P0, 'to'=>listproto)
17
p6meta.'register'('ResizablePMCArray', 'parent'=>listproto, 'protoobject'=>listproto)
27
Smart-matches against the list.
32
.sub 'ACCEPTS' :method
36
$I0 = isa topic, 'List' # Catches Array too
38
# XXX When we have a Set type, need to handle that here too.
39
topic = topic.'list'()
43
.local pmc it_a, it_b, cur_a, cur_b
46
unless it_a goto it_loop_end
47
unless it_b goto it_loop_end
50
unless it_b goto it_loop_end
53
# If there curent thing is Whatever, need special handling.
54
$I0 = isa cur_a, ['Whatever']
55
unless $I0 goto not_whatever
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.
63
.local pmc looking_for
64
looking_for = shift it_a
65
$I0 = isa looking_for, ['Whatever']
66
if $I0 goto handle_whatever
68
$P0 = 'infix:==='(looking_for, cur_b)
69
if $P0 goto found_looking_for
70
unless it_b goto false
74
unless it_a goto it_loop_end
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)
85
unless it_a goto it_loop_end
87
$I0 = isa cur_a, ['Whatever']
88
if $I0 goto handle_whatever
89
unless it_b goto false
95
$P0 = get_hll_global [ 'Bool' ], 'True'
98
$P0 = get_hll_global [ 'Bool' ], 'False'
105
A List in item context becomes an Array.
111
.tailcall self.'Array'()
116
.param pmc values :slurpy
117
.tailcall values.'!flatten'()
123
Store the values from C<source> into C<self>.
128
.sub '!STORE' :method
131
## get the list of containers and sources
134
splice $P0, self, 0, 0
136
source = source.'list'()
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
149
unless i < $I0 goto mark_done
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
161
setprop cont, 'target', true
166
## now build our 'real' source list, cloning any targets we encounter
171
unless it goto source_done
173
$P1 = getprop 'target', $P0
174
if null $P1 goto source_next
181
## now perform the assignments, clearing targets as we go
186
unless it goto assign_done
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
197
if slist goto have_slist
215
=head2 Coercion methods
224
.sub 'Iterator' :method
233
A list in Scalar context becomes a Scalar containing an Array.
237
.sub 'Scalar' :method
239
$P0 = root_new ['parrot';'Perl6Scalar'], $P0
243
# FIXME: :vtable('get_string') is wrong here.
244
.sub 'Str' :method :vtable('get_string')
258
Return the number of elements in the list.
263
.sub 'elems' :method :multi() :vtable('get_number') :subid('list_elems')
269
.local pmc block, signature
270
.const 'Sub' $P0 = "list_elems"
272
signature = allocate_signature 1
273
setprop block, "$!signature", signature
274
$P0 = get_hll_global 'List'
276
set_signature_elem signature, 0, "self", SIG_ELEM_INVOCANT_AND_MULTI_INVOCANT, $P0, $P1, $P1, $P1, $P1, $P1
277
'!TOPERL6MULTISUB'(block)
283
=head2 Private methods
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.
295
.sub '!flatten' :method
296
.param int size :optional
297
.param int has_size :opt_flag
299
## we use the 'elements' opcode here because we want the true length
304
if i >= len goto flat_end
305
unless has_size goto flat_loop_1
306
if i >= size goto flat_end
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
335
elem = elem.'!flatten'()
336
splice self, elem, i, 1
342
$I0 = isa self, 'List'
354
# TODO Rewrite it. It's too naive.
358
.param pmc comparer :optional
359
.param int has_comparer :opt_flag
361
if has_comparer goto have_comparer
362
comparer = get_hll_global 'infix:eq'
366
$P0 = get_hll_global 'List'
369
.local pmc it_inner, it_outer, val
372
unless it_outer goto outer_done
374
it_inner = iter ulist
376
unless it_inner goto inner_done
378
$P1 = comparer(val, $P0)
379
if $P1 goto outer_loop
391
.sub 'uniq' :multi('Block')
393
.param pmc values :slurpy
395
.tailcall values.'uniq'(comparer)
399
.param pmc values :slurpy
401
.tailcall values.'uniq'()
411
=item C<infix:,(...)>
413
Operator form for building a list from its arguments.
419
.param pmc args :slurpy
420
.tailcall args.'list'()
424
=item C<infix:Z(...)>
431
.param pmc arglist :slurpy
434
# create a list to hold the results
435
result = new ['List']
437
unless arglist goto result_done
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
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
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.
457
.local pmc iterlist_it, reselem
458
iterlist_it = iter iterlist
459
reselem = new ['List']
461
unless iterlist_it goto iterlist_done
462
arg_it = shift iterlist_it
463
unless arg_it goto result_done
468
result.'push'(reselem)
476
=item C<infix:X(...)>
478
The non-hyper cross operator.
483
.param pmc args :slurpy
486
.local pmc res, outer, inner, it, val
489
## if the are no arguments, result is empty list
490
unless args goto done
492
## get the first arg in list context
494
outer = 'list'(outer)
496
## if this argument is empty, result is empty list
497
unless outer goto done
499
## if no more args, then build result from only arg
500
unless args goto one_arg
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
507
## otherwise, loop through all elements of our first arg
512
## add the value to a clone of each inner result list
515
unless $P1 goto outer_loop
516
## get a result list, clone it
519
## add our outer value to the beginning
521
## save it in the result list
525
## if call to infix:X had only one argument, our result
526
## is a list of 1-element lists.
542
=item C<infix:min(...)>
549
.param pmc args :slurpy
551
# If we have no arguments, undefined.
553
elems = elements args
554
if elems > 0 goto have_args
555
$P0 = root_new ['parrot';'Undef']
560
.local pmc cur_min, it
564
unless it goto find_min_loop_end
566
$I0 = 'infix:cmp'($P0, cur_min)
567
unless $I0 < 0 goto find_min_loop
576
=item C<infix:max(...)>
583
.param pmc args :slurpy
585
# If we have no arguments, undefined.
587
elems = elements args
588
if elems > 0 goto have_args
589
$P0 = root_new ['parrot';'Undef']
594
.local pmc cur_max, it
598
unless it goto find_max_loop_end
600
$I0 = 'infix:cmp'($P0, cur_max)
601
unless $I0 > 0 goto find_max_loop
619
# vim: expandtab shiftwidth=4 ft=pir: