5
src/builtins/guts.pir - subs that are part of the internals, not for users
11
=item !EXPORT(symbols, from :named('from') [, to :named('to')] )
13
Export symbols in namespace C<from> to the namespace given by C<to>.
14
If C<to> isn't given, then exports into the HLL global namespace.
15
This function differs somewhat from Parrot's C<Exporter> PMC in that
16
it understands how to properly merge C<MultiSub> PMCs.
23
.param pmc from :named('from')
24
.param pmc to :named('to') :optional
25
.param int has_to :opt_flag
26
.param int to_p6_multi :named('to_p6_multi') :optional
28
if has_to goto have_to
29
to = get_hll_namespace
33
list = split ',', symbols
35
unless list goto list_end
40
$I0 = isa value, 'MultiSub'
41
unless $I0 goto store_value
42
if to_p6_multi != 1 goto no_convert
44
'!TOPERL6MULTISUB'($P0)
48
if null $P0 goto store_value
49
$I0 = isa $P0, 'MultiSub'
50
unless $I0 goto err_type_conflict
52
splice $P0, value, $I0, 0
61
$S0 = concat "Unable to add Multisub '", symbol
62
$S0 .= "' to existing value"
67
=item !CALLMETHOD('method', obj)
69
Invoke a method on a possibly foreign object. If the object
70
supports the requested method, we use it, otherwise we assume
71
the object is foreign and try using the corresponding method
80
$I0 = isa obj, 'Perl6Scalar'
81
if $I0 goto any_method
83
unless $I0 goto any_method
84
.tailcall obj.method()
87
anyobj = get_global '$!ANY'
88
unless null anyobj goto any_method_1
90
set_global '$!ANY', anyobj
92
$P0 = find_method anyobj, method
97
=item !dispatch_method_indirect
99
Does an indirect method dispatch.
103
.sub '!dispatch_method_indirect'
106
.param pmc pos_args :slurpy
107
.param pmc name_args :slurpy :named
109
$I0 = isa methodish, 'P6Invocation'
110
if $I0 goto ready_to_dispatch
111
$P0 = get_hll_global 'Callable'
112
$I0 = $P0.'ACCEPTS'(methodish)
113
unless $I0 goto candidate_list
115
.tailcall methodish(obj, pos_args :flat, name_args :flat :named)
118
$P0 = root_new ['parrot';'P6Invocation'], methodish
119
.tailcall $P0(obj, pos_args :flat, name_args :flat :named)
123
=item !dispatch_dispatcher_parallel
125
Does a parallel method dispatch over an existing dispatcher. Just invokes the normal
126
dispatcher for each thingy we're dispatching over.
130
.sub '!dispatch_dispatcher_parallel'
132
.param string dispatcher
133
.param pmc pos_args :slurpy
134
.param pmc named_args :slurpy :named
136
.local pmc it, result, disp
137
disp = find_name dispatcher
138
result = new ['Perl6Array']
139
invocanty = invocanty.'list'()
142
unless it goto it_loop_done
144
$P0 = disp($P0, pos_args :flat, named_args :flat :named)
154
=item !dispatch_method_parallel
156
Does a parallel method dispatch. Invokes the method for each thing in the
161
.sub '!dispatch_method_parallel'
164
.param pmc pos_args :slurpy
165
.param pmc named_args :slurpy :named
167
.local pmc it, result
168
result = new ['Perl6Array']
169
invocanty = invocanty.'list'()
172
unless it goto it_loop_done
174
$P0 = $P0.name(pos_args :flat, named_args :flat :named)
186
Helper function for implementing the VAR and .VAR macros.
192
$I0 = isa variable, 'Perl6Scalar'
193
unless $I0 goto nothing
194
$P0 = root_new ['parrot';'MutableVAR'], variable
201
=item !SAMETYPE_EXACT
203
Takes two types and returns true if they match exactly (not accounting for any
204
subtyping relations, etc).
208
.sub '!SAMETYPE_EXACT'
212
# If they have equal address, obviously the same.
213
.local pmc t1meta, t2meta
216
eq_addr t1meta, t2meta, same
218
# If they are junctions, compare inside them recursively.
219
$I0 = isa t1, 'Junction'
220
unless $I0 goto not_junc
221
$I1 = isa t2, 'Junction'
222
unless $I0 == $I1 goto not_junc
225
j1 = t1.'eigenstates'()
226
j2 = t1.'eigenstates'()
230
if i >= max goto junc_loop_end
233
$I0 = '!SAMETYPE_EXACT'($P0, $P1)
234
unless $I0 goto not_same
247
=item !CREATE_SUBSET_TYPE
249
Creates a subset type. Basically, we make an anonymous subclass of the
250
original type, attach the refinement and override ACCEPTS. We also chase up
251
to find a real, non-subtype and stash that away for fast access later.
255
.sub '!CREATE_SUBSET_TYPE'
257
.param pmc refinement
260
p6meta = get_hll_global ['Perl6Object'], '$!P6META'
262
# Check if the refinee is a refinement type itself; if so, get the real
263
# base type we're refining.
264
.local pmc real_type, real_type_pc
265
real_type = getprop 'subtype_realtype', refinee
266
unless null $P0 goto got_real_type
270
# Create subclass. If it's a role, pun it.
271
.local pmc parrot_class, type_obj, subset
273
$I0 = isa type_obj, 'Perl6Role'
274
unless $I0 goto ambig_role_done
275
type_obj = type_obj.'!select'()
277
$I0 = isa type_obj, 'P6role'
278
unless $I0 goto role_done
279
type_obj = type_obj.'!pun'()
281
parrot_class = p6meta.'get_parrotclass'(type_obj)
282
subset = subclass parrot_class
285
.local pmc parrotclass
286
.const 'Sub' $P0 = "!SUBTYPE_ACCEPTS"
287
subset.'add_method'('ACCEPTS', $P0)
288
.const 'Sub' $P1 = "!SUBTYPE_PROTOOVERRIDES"
289
subset.'add_method'('PROTOOVERRIDES', $P1)
291
# It's an abstraction.
292
$P0 = get_hll_global 'Abstraction'
293
$P0 = $P0.'!select'()
294
subset.'add_role'($P0)
296
# Register it, creating a proto-object.
297
subset = p6meta.'register'(subset)
299
# Mark it a subtype and stash away real type, refinee and refinement.
300
$I0 = isa real_type, 'Perl6Role'
301
unless $I0 goto real_type_done
302
real_type = real_type.'!select'()
304
setprop subset, 'subtype_realtype', real_type
305
setprop subset, 'subtype_refinement', refinement
306
setprop subset, 'subtype_refinee', refinee
310
.sub "!SUBTYPE_ACCEPTS" :anon :method
313
# Get refinement and check against that.
314
.local pmc refinement
315
refinement = getprop 'subtype_refinement', self
316
$P0 = refinement(topic)
317
unless $P0 goto false
319
# Recurse up the tree.
321
refinee = getprop 'subtype_refinee', self
322
$P0 = refinee.'ACCEPTS'(topic)
323
unless $P0 goto false
326
$P0 = get_hll_global ['Bool'], 'True'
329
$P0 = get_hll_global ['Bool'], 'False'
332
.sub '!SUBTYPE_PROTOOVERRIDES' :anon :method
333
.return ('new', 'ACCEPTS')
337
=item !TOPERL6MULTISUB
339
At the moment, we don't have the abilility to have Parrot use our own MultiSub
340
type, nor are we ready to (because built-ins need to get Perl 6 signatures
341
first). So for now we just transform multis in user code like this.
345
.sub '!TOPERL6MULTISUB'
348
# Look up what's currently installed in the namespace for this sub; if it
349
# is already a Perl6MultiSub, leave it.
350
.local pmc namespace, current_thing
352
namespace = sub.'get_namespace'()
354
current_thing = namespace[name]
355
if null current_thing goto error
356
$S0 = typeof current_thing
357
if $S0 == 'MultiSub' goto not_perl6_multisub
359
# It's not a Perl6MultiSub, create one and put contents into it.
361
.local pmc p6multi, sub_iter
362
p6multi = root_new ['parrot';'Perl6MultiSub']
363
sub_iter = iter current_thing
365
unless sub_iter goto iter_loop_end
371
# Nor replace the current thing with the new data structure.
372
copy current_thing, p6multi
376
'die'('Sub lookup failed')
380
=item !clone_multi_for_lexical
384
.sub '!clone_multi_for_lexical'
386
if null existing goto fresh
387
unless existing goto fresh
388
$P0 = existing.'clone'()
391
$P0 = root_new ['parrot';'Perl6MultiSub']
405
if args goto start_main
409
## We're running as main program
410
## Remove program argument (0) and put it in $*PROGRAM_NAME, then set up
413
set_hll_global '$PROGRAM_NAME', $P0
414
args = args.'Array'()
415
set_hll_global '@ARGS', args
417
.local pmc result, MAIN
419
## if there's a MAIN sub in unitmain's namespace, run it also
420
$P0 = unitmain.'get_namespace'()
422
if null MAIN goto done
423
args = get_hll_global '@ARGS'
424
result = MAIN(args :flat)
432
Combine slurpy positional and slurpy named args into a list.
433
Note that original order may be lost -- that's the nature
439
.param pmc args :slurpy
440
.param pmc options :slurpy :named
441
unless options goto done
448
$P0 = 'infix:=>'($S0, $P0)
452
.tailcall args.'list'()
458
Adds a given role initializing multi-variant to a Role object, creating it
459
and putting it in the namespace if it doesn't already exist.
466
# Get short name of role.
468
.local string short_name
469
ns = variant.'get_namespace'()
473
setprop variant, "$!shortname", $P0
474
$I0 = index short_name, '['
475
if $I0 == -1 goto have_short_name
476
short_name = substr short_name, 0, $I0
479
# See if we have a Role object already.
481
role_obj = get_root_global ns, short_name
482
if null role_obj goto need_role_obj
483
$I0 = isa role_obj, 'NameSpace'
484
unless $I0 goto have_role_obj
486
role_obj = new ['Perl6Role']
487
transform_to_p6opaque role_obj
488
set_root_global ns, short_name, role_obj
490
setattribute role_obj, "$!shortname", $P0
494
role_obj.'!add_variant'(variant)
498
=item !meta_create(type, name, also)
500
Create a metaclass object for C<type> with the given C<name>.
501
This simply creates a handle on which we can hang methods, attributes,
502
traits, etc. -- the class itself isn't created until the class
503
is composed (see C<!meta_compose> below).
513
$P0 = get_hll_global [ 'Perl6';'Compiler' ], 'parse_name'
515
nsarray = $P0($P1, name)
517
if type == 'package' goto package
518
if type == 'module' goto package
519
if type == 'class' goto class
520
if type == 'grammar' goto class
521
if type == 'role' goto role
522
'die'("Unsupported package declarator ", type)
525
$P0 = get_hll_namespace nsarray
529
.local pmc parrotclass, metaclass, ns
530
ns = get_hll_namespace nsarray
532
parrotclass = newclass ns
534
setprop parrotclass, 'pkgtype', $P0
535
'!set_resolves_list'(parrotclass)
536
metaclass = new ['ClassHOW']
537
setattribute metaclass, 'parrotclass', parrotclass
540
parrotclass = get_class ns
541
metaclass = getprop 'metaclass', parrotclass
545
# This is a little fun. We only want to create the Parrot role and suck
546
# in the methods once per role definition. We do this and it is attached to
547
# the namespace. Then we attach this "master role" to a new one we create
548
# per invocation, so the methods can be newclosure'd and added into it in
550
.local pmc info, parrotrole
551
ns = get_hll_namespace nsarray
552
parrotrole = get_class ns
553
unless null parrotrole goto have_role
555
info = root_new ['parrot';'Hash']
558
info['namespace'] = nsarray
559
parrotrole = root_new ['parrot';'P6role'], info
562
# Copy list of roles done by the original role into this specific
564
.local pmc specific_role, tmp, it
565
specific_role = root_new ['parrot';'P6role']
566
setprop specific_role, '$!orig_role', parrotrole
567
tmp = parrotrole.'roles'()
570
unless it goto roles_loop_end
572
specific_role.'add_role'(tmp)
576
# Now create a meta-object (RoleHOW) to package this all up in.
578
metaclass = new ['RoleHOW']
579
setprop specific_role, 'metaclass', metaclass
580
setattribute metaclass, 'parrotclass', specific_role
581
setattribute metaclass, 'protoobject', specific_role
582
setattribute metaclass, 'shortname', $P0
584
setattribute metaclass, 'longname', $P1
589
=item !meta_compose(Class metaclass)
591
Compose the class. This includes resolving any inconsistencies
592
and creating the protoobjects.
599
p6meta = get_hll_global ['Perl6Object'], '$!P6META'
601
# If it's a RoleHOW or otherwise just not a ClassHOW, nothing to do.
602
$I0 = isa metaclass, 'RoleHOW'
603
if $I0 goto no_pkgtype
604
$I0 = isa metaclass, 'ClassHOW'
605
unless $I0 goto no_pkgtype
607
# Extract the parrotclass form the metaclass.
608
.local pmc parrotclass
609
parrotclass = getattribute metaclass, 'parrotclass'
611
# Parrot handles composing methods into roles, but we need to handle the
612
# attribute composition ourselves.
613
.local pmc roles, roles_it
614
roles = getprop '@!roles', parrotclass
615
if null roles goto roles_it_loop_end
616
roles = '!get_flattened_roles_list'(roles)
617
roles_it = iter roles
619
unless roles_it goto roles_it_loop_end
621
$I0 = does parrotclass, $P0
622
if $I0 goto roles_it_loop
623
parrotclass.'add_role'($P0)
624
'!compose_role_attributes'(parrotclass, $P0)
628
# We may need to set up invoke vtable if postcircumfix:<( )>
630
'!setup_invoke_vtable'(metaclass)
632
# Create proto-object with default parent being Any or Grammar, unless
633
# there already is a parent.
635
$P0 = parrotclass.'parents'()
637
if $I0 goto register_parent_set
639
$P0 = getprop 'pkgtype', parrotclass
640
if null $P0 goto no_pkgtype
641
if $P0 != 'grammar' goto register
644
proto = p6meta.'register'(parrotclass, 'parent'=>$S0, 'how'=>metaclass)
647
proto = p6meta.'register'(parrotclass, 'how'=>metaclass)
649
transform_to_p6opaque proto
656
=item !setup_invoke_vtable
658
If we override postcircumfix:<( )> then also add a
659
vtable override for invoke.
663
.sub '!setup_invoke_vtable'
665
.local pmc parrotclass
666
parrotclass = getattribute metaclass, 'parrotclass'
667
$P0 = parrotclass.'methods'()
668
$P0 = $P0['postcircumfix:( )']
669
if null $P0 goto no_invoke
670
.const 'Sub' $P1 = '!invoke_vtable_override_helper'
671
parrotclass.'add_vtable_override'('invoke', $P1)
674
.sub '' :subid('!invoke_vtable_override_helper')
675
.param pmc pos_args :slurpy
676
.param pmc named_args :slurpy :named
679
$P0 = getprop '$!self', $P0
680
.tailcall $P0.'postcircumfix:( )'(pos_args :flat, named_args :flat :named)
684
=item !get_flattened_roles_list
686
Flattens out the list of roles.
690
.sub '!get_flattened_roles_list'
691
.param pmc unflat_list
692
.local pmc flat_list, it, cur_role, nested_roles, nested_it
693
flat_list = root_new ['parrot';'ResizablePMCArray']
694
it = iter unflat_list
696
unless it goto it_loop_end
698
$I0 = isa cur_role, 'Role'
699
unless $I0 goto error_not_a_role
700
push flat_list, cur_role
701
nested_roles = getprop '@!roles', cur_role
702
if null nested_roles goto it_loop
703
nested_roles = '!get_flattened_roles_list'(nested_roles)
704
nested_it = iter nested_roles
706
unless nested_it goto it_loop
707
$P0 = shift nested_it
713
'die'('Can not compose a non-role.')
717
=item !meta_attribute(metaclass, name, itypename [, 'type'=>type] )
719
Add attribute C<name> to C<metaclass> with the given C<itypename>
724
.sub '!meta_attribute'
727
.param string itypename :optional
728
.param int has_itypename :opt_flag
729
.param pmc attr :slurpy :named
731
# twigil handling (for has &!foo, we just get name as !foo)
735
$S0 = substr name, 0, 1
736
if $S0 != '!' goto offset_done
739
twigil = substr name, offset, 1
740
if twigil == '.' goto twigil_public
741
if twigil == '!' goto twigil_done
742
substr name, offset, 0, '!'
745
substr name, offset, 1, '!'
748
# In the future, we'll want to have just called metaclass.add_attribute(...)
749
# here and let it handle all of this, but we ain't quite ready for that yet.
750
$I0 = isa metaclass, 'P6metaclass'
751
unless $I0 goto got_parrot_class
752
metaclass = getattribute metaclass, 'parrotclass'
755
$P0 = metaclass.'attributes'()
756
$I0 = exists $P0[name]
757
if $I0 goto attr_exists
758
addattribute metaclass, name
759
$P1 = getprop '@!attribute_list', metaclass
760
unless null $P1 goto have_attrlist
761
$P1 = root_new ['parrot';'ResizableStringArray']
762
setprop metaclass, '@!attribute_list', $P1
765
$P0 = metaclass.'attributes'()
768
.local pmc attrhash, it
771
# Set any itype for the attribute.
772
unless has_itypename goto itype_done
774
if itypename == 'Perl6Scalar' goto itype_pmc
775
itype = get_class itypename
778
$P0 = get_root_namespace ['parrot';'Perl6Scalar']
779
itype = get_class $P0
781
attrhash['itype'] = itype
784
# and set any other attributes that came in via the slurpy hash
787
unless it goto attr_done
794
# Anything to do with handles?
795
$P0 = attr['handles']
796
if null $P0 goto handles_done
798
# For the handles trait verb, we may have got a name or a list of names.
799
# If so, just generate methods with those names. Otherwise, need to store
800
# them as a property on the metaclass, so the dispatcher can smart-match
801
# against them later. Also, the % syntax is spec'd as reserved, so we give
802
# an error on that for now.
803
.const 'Sub' handles = '!handles'
804
.local pmc handles_it
805
$S0 = substr name, 0, 1
806
if $S0 == '%' goto reserved_syntax_error
808
if $I0 goto simple_handles
809
$I0 = isa $P0, 'List'
810
if $I0 goto simple_handles
811
$I0 = isa $P0, 'Perl6Pair'
812
if $I0 goto simple_handles
814
.local pmc class_handles_list, handles_hash
815
class_handles_list = getprop '@!handles_dispatchers', metaclass
816
unless null class_handles_list goto have_class_handles_list
817
class_handles_list = root_new ['parrot';'ResizablePMCArray']
818
setprop metaclass, '@!handles_dispatchers', class_handles_list
819
have_class_handles_list:
820
handles_hash = root_new ['parrot';'Hash']
821
handles_hash['attrname'] = name
822
handles_hash['match_against'] = $P0
823
push class_handles_list, handles_hash
828
handles_it = iter $P0
830
.local string visible_name
832
unless handles_it goto handles_done
835
setprop $P0, 'attrname', $P1
836
$P1 = shift handles_it
837
$I0 = isa $P1, 'Perl6Pair'
838
if $I0 goto handles_pair
843
visible_name = $P1.'key'()
844
orig_name = $P1.'value'()
846
setprop $P0, 'methodname', orig_name
847
metaclass.'add_method'(visible_name, $P0)
851
reserved_syntax_error:
852
'die'("The use of a %hash with the handles trait verb is reserved")
856
.sub '!handles' :method
857
.param pmc args :slurpy
858
.param pmc options :slurpy :named
859
.local pmc method, attribute
860
.local string attrname
863
$P1 = getprop 'attrname', method
865
attribute = getattribute self, attrname
866
$P1 = getprop 'methodname', method
868
$S0 = substr attrname, 0, 1
869
if $S0 != '@' goto single_dispatch
873
unless it goto it_loop_end
876
unless $I0 goto it_loop
877
.tailcall $P0.$S1(args :flat, options :flat :named)
879
'die'("You used handles on attribute ", attrname, ", but nothing in the array can do method ", $S1)
881
.tailcall attribute.$S1(args :flat, options :flat :named)
885
=item !set_resolves_list(class)
887
Gets all the methods that the class has and adds them to the resolves list.
891
.sub '!set_resolves_list'
893
.local pmc meths, it, res_list
894
meths = class.'methods'()
896
res_list = root_new ['parrot';'ResizableStringArray']
898
unless it goto it_loop_end
901
$I0 = isa $P0, 'MultiSub'
906
class.'resolve_method'(res_list)
910
=item !compose_role_attributes(class, role)
912
Helper method to compose the attributes of a role into a class.
916
.sub '!compose_role_attributes'
920
# Need to get hold of attribute order list for the class.
921
.local pmc attr_order_list
922
attr_order_list = getprop '@!attribute_list', class
923
unless null attr_order_list goto have_attr_order_list
924
attr_order_list = root_new ['parrot';'ResizableStringArray']
925
setprop class, '@!attribute_list', attr_order_list
926
have_attr_order_list:
928
.local pmc role_attrs, class_attrs, ra_iter, fixup_list
929
.local string cur_attr
930
role_attrs = inspect role, "attributes"
931
class_attrs = class."attributes"()
932
fixup_list = root_new ['parrot';'ResizableStringArray']
933
ra_iter = iter role_attrs
935
unless ra_iter goto ra_iter_loop_end
936
cur_attr = shift ra_iter
938
# Check that this attribute doesn't conflict with one already in the class.
939
$I0 = exists class_attrs[cur_attr]
940
unless $I0 goto no_conflict
942
# We have a name conflict. Let's compare the types. If they match, then we
943
# can merge the attributes.
944
.local pmc class_attr_type, role_attr_type
945
$P0 = class_attrs[cur_attr]
946
if null $P0 goto conflict
947
class_attr_type = $P0['type']
948
if null class_attr_type goto conflict
949
$P0 = role_attrs[cur_attr]
950
if null $P0 goto conflict
951
role_attr_type = $P0['type']
952
if null role_attr_type goto conflict
953
$I0 = '!SAMETYPE_EXACT'(class_attr_type, role_attr_type)
957
$S0 = "Conflict of attribute '"
958
$S0 = concat cur_attr
959
$S0 = concat "' in composition of role '"
966
addattribute class, cur_attr
967
push fixup_list, cur_attr
968
push attr_order_list, cur_attr
973
# Now we need, for any merged in attributes, to copy property data.
974
.local pmc fixup_iter, class_props, role_props, props_iter
975
class_attrs = class."attributes"()
976
fixup_iter = iter fixup_list
978
unless fixup_iter goto fixup_iter_loop_end
979
cur_attr = shift fixup_iter
980
role_props = role_attrs[cur_attr]
981
class_props = class_attrs[cur_attr]
982
props_iter = iter role_props
984
unless props_iter goto props_iter_loop_end
985
$S0 = shift props_iter
986
$P0 = role_props[$S0]
987
class_props[$S0] = $P0
995
=item !add_metaclass_method
999
.sub '!add_metaclass_method'
1000
.param pmc metaclass
1004
# Create role for the method and mix it into the meta-class.
1005
$P0 = root_new ['parrot';'P6role']
1007
addmethod $P0, $S0, method
1008
'infix:does'(metaclass, $P0)
1010
# Add forward method to the class itself.
1011
.lex '$meth_name', name
1012
.const 'Sub' $P1 = '!metaclass_method_forwarder'
1013
$P1 = newclosure $P1
1014
$P0 = getattribute metaclass, 'parrotclass'
1015
$P0.'add_method'(name, $P1)
1017
.sub '!metaclass_method_forwarder' :outer('!add_metaclass_method') :method :anon
1018
.param pmc pos_args :slurpy
1019
.param pmc named_args :slurpy :named
1021
$P1 = find_lex '$meth_name'
1023
.tailcall $P0.$S0(self, pos_args :flat, named_args :flat :named)
1027
=item !create_parametric_role
1029
Helper method for creating parametric roles.
1033
.sub '!create_parametric_role'
1035
'!meta_compose'(metarole)
1036
.local pmc parrotrole, orig_role, meths, meth_iter
1037
parrotrole = getattribute metarole, 'parrotclass'
1038
orig_role = getprop '$!orig_role', parrotrole
1039
meths = orig_role.'methods'()
1040
meth_iter = iter meths
1042
unless meth_iter goto it_loop_end
1043
$S0 = shift meth_iter
1046
$P2 = getprop '$!signature', $P0
1047
setprop $P1, '$!signature', $P2
1048
$I0 = isa $P0, 'Code'
1049
unless $I0 goto ret_pir_skip_rs
1050
$P2 = getattribute $P0, ['Sub'], 'proxy'
1051
$P2 = getprop '$!real_self', $P2
1052
$P3 = getattribute $P1, ['Sub'], 'proxy'
1053
setprop $P3, '$!real_self', $P2
1055
addmethod parrotrole, $S0, $P1
1058
.return (parrotrole)
1062
=item !create_simple_role(name)
1064
Internal helper method to create a role with a single parameterless variant.
1068
.sub '!create_simple_role'
1070
.local pmc info, role, helper
1072
# Create Parrot-level role. Need to make sure it gets its methods from
1073
# the right namespace.
1075
ns = split '::', name
1077
info = root_new ['parrot';'Hash']
1079
info['namespace'] = ns
1080
role = root_new ['parrot';'P6role'], info
1082
# Now we need to wrap it up as a Perl6Role.
1083
helper = find_name '!create_simple_role_helper'
1084
helper = clone helper
1085
setprop helper, '$!metarole', role
1086
$P0 = new ["Signature"]
1087
setprop helper, '$!signature', $P0
1088
role = new ['Perl6Role']
1089
transform_to_p6opaque role
1092
setattribute role, '$!shortname', $P0
1093
role.'!add_variant'(helper)
1095
# Store it in the namespace.
1098
set_hll_global ns, $S0, role
1101
.sub '!create_simple_role_helper'
1104
$P0 = getprop '$!metarole', $P0
1109
=item !create_anon_enum(value_list)
1111
Constructs a Mapping, based upon the values list.
1115
.sub '!create_anon_enum'
1118
# Put the values into list context, so case of a single valued enum works.
1119
values = values.'list'()
1121
# For now, we assume integer type, unless we have a first pair that says
1126
# Iterate over values and make mapping.
1127
.local pmc result, values_it, cur_item
1128
result = new ['Mapping']
1129
values_it = iter values
1131
unless values_it goto values_loop_end
1132
cur_item = shift values_it
1133
$I0 = isa cur_item, 'Perl6Pair'
1137
$P0 = 'postfix:++'(cur_val)
1138
result[cur_item] = $P0
1142
cur_val = cur_item.'value'()
1143
$P0 = cur_item.'key'()
1144
result[$P0] = cur_val
1145
cur_val = clone cur_val
1146
'postfix:++'(cur_val)
1154
=item !create_enum(name, type, value_list)
1156
Constructs an enumeration.
1164
# Use !create_anon_enum to associate all names with their underlying
1166
values = '!create_anon_enum'(values)
1168
# Create a role for the enumeration and mark it as an enum.
1169
.local pmc para_role, role
1170
para_role = '!create_simple_role'(name)
1171
role = para_role.'!select'()
1173
setprop role, '$!is_enum', $P0
1175
# Compute short name and add attribute to the role; type is this
1176
# role so that you can only store other enum elements in the slut.
1177
.local pmc ns, outer_ns
1178
.local string short_name, attr_name
1179
$P0 = get_hll_global [ 'Perl6';'Compiler' ], 'parse_name'
1183
short_name = pop outer_ns
1184
attr_name = concat "$!", short_name
1185
'!meta_attribute'(role, attr_name, 'Perl6Scalar', 'type'=>role)
1187
# Add an l-value accessor method for the attribute.
1188
.local pmc attr_name_pmc, accessor
1189
attr_name_pmc = box attr_name
1190
.lex '$attr_name', attr_name_pmc
1191
.const 'Sub' accessor = '!create_enum_helper_accessor'
1192
accessor = newclosure accessor
1193
addmethod role, short_name, accessor
1195
# Next, we need methods on the role for each variant, returning
1196
# a true or false value depending on if the current value of the
1197
# enum is set to that.
1198
.const 'Sub' checker_create = '!create_enum_helper_checker_create'
1199
.local pmc it, cur_value
1202
unless it goto checker_loop_end
1204
cur_value = values[$S0]
1205
$P0 = checker_create(attr_name, cur_value)
1206
addmethod role, $S0, $P0
1210
# We'll make a list of the values and the .pick method on the role will
1211
# use that (Enum.pick then just works through punning).
1212
.local pmc value_list
1213
.local string value_name
1214
value_list = root_new ['parrot';'ResizablePMCArray']
1215
.lex '@values', value_list
1216
.const 'Sub' pick = '!create_enum_helper_pick'
1217
pick = newclosure pick
1218
addmethod role, 'pick', pick
1220
# Go over all of the values...
1223
unless it goto value_loop_end
1224
value_name = shift it
1225
cur_value = values[value_name]
1227
# Mix the enum role into it, so Val ~~ Enum will work, and set the value
1228
# field to itself plus set it readonly.
1229
cur_value = 'infix:but'(cur_value, role)
1230
$P0 = cur_value.short_name()
1233
setprop $P0, 'readonly', $P1
1235
# It should also do Abstraction.
1236
$P0 = get_hll_global 'Abstraction'
1237
'infix:does'(cur_value, $P0)
1239
# Now create and mix in another role to provide .WHAT, .perl and .name.
1240
$S0 = concat name, '::'
1241
$S0 = concat value_name
1242
$P0 = '!create_enum_value_role'(role, $S0, value_name)
1243
'infix:does'(cur_value, $P0)
1245
# Put it onto the list for .pick and install it in the namespace(s).
1246
push value_list, cur_value
1247
set_hll_global ns, value_name, cur_value
1248
set_hll_global outer_ns, value_name, cur_value
1253
.sub '!create_enum_helper_accessor' :method :outer('!create_enum')
1254
$P0 = find_lex '$attr_name'
1256
$P0 = getattribute self, $S0
1259
.sub '!create_enum_helper_checker_create'
1260
.param pmc attr_name
1262
.lex '$attr_name', attr_name
1263
.lex '$value', value
1264
.const 'Sub' $P0 = '!create_enum_helper_checker'
1265
$P0 = newclosure $P0
1268
.sub '!create_enum_helper_checker' :method :outer('!create_enum_helper_checker_create')
1269
$P0 = find_lex '$attr_name'
1271
$P0 = getattribute self, $S0
1272
$P1 = find_lex '$value'
1273
.tailcall 'infix:eq'($P0, $P1)
1275
.sub '!create_enum_helper_pick' :method :outer('!create_enum')
1276
.param pmc pos_args :slurpy
1277
$P0 = find_lex '@values'
1278
$P0 = 'list'($P0 :flat)
1279
.tailcall $P0.'pick'(pos_args :flat)
1281
.sub '!create_enum_value_role'
1282
.param pmc enum_role
1283
.param pmc long_name
1284
.param pmc short_name
1285
.lex '$enum_role', enum_role
1286
.lex '$long_name', long_name
1287
.lex '$short_name', short_name
1288
$P0 = root_new ['parrot';'P6role']
1289
.const 'Sub' ACCEPTS = '!create_enum_value_role_ACCEPTS'
1290
ACCEPTS = newclosure ACCEPTS
1291
addmethod $P0, 'ACCEPTS', ACCEPTS
1292
.const 'Sub' WHAT = '!create_enum_value_role_WHAT'
1293
WHAT = newclosure WHAT
1294
addmethod $P0, 'WHAT', WHAT
1295
.const 'Sub' name = '!create_enum_value_role_name'
1296
name = newclosure name
1297
addmethod $P0, 'name', name
1298
.const 'Sub' perl = '!create_enum_value_role_perl'
1299
perl = newclosure perl
1300
addmethod $P0, 'perl', perl
1303
.sub '!create_enum_value_role_ACCEPTS' :method :outer('!create_enum_value_role')
1305
$P0 = find_lex '$enum_role'
1306
$I0 = does topic, $P0
1307
unless $I0 goto done
1308
$P0 = find_lex '$short_name'
1314
.sub '!create_enum_value_role_WHAT' :method :outer('!create_enum_value_role')
1315
$P0 = find_lex '$enum_role'
1318
.sub '!create_enum_value_role_name' :method :outer('!create_enum_value_role')
1319
$P0 = find_lex '$short_name'
1322
.sub '!create_enum_value_role_perl' :method :outer('!create_enum_value_role')
1323
$P0 = find_lex '$long_name'
1328
=item !fixup_routine_type(sub, new_type)
1330
Reblesses a sub into a new type.
1334
.sub '!fixup_routine_type'
1336
.param string new_type_name
1338
# Create the correct object and rebless the sub into that class.
1340
new_type = get_hll_global new_type_name
1341
$P0 = new_type.'new'()
1343
rebless_subclass sub, $P0
1345
# We also make sure the Parrot-level sub has a backlink to the
1346
# Rakudo-level object, since interpinfo only gives us the
1348
$P0 = getattribute sub, ['Sub'], 'proxy'
1349
setprop $P0, '$!real_self', sub
1353
=item !state_var_init
1355
Loads any existing values of state variables for a block.
1359
.sub '!state_var_init'
1360
.local pmc lexpad, state_store, names_it
1362
lexpad = $P0['lexpad'; 1]
1364
state_store = getprop '$!state_store', $P0
1365
unless null state_store goto have_state_store
1366
state_store = root_new ['parrot';'Hash']
1367
setprop $P0, '$!state_store', state_store
1370
names_it = iter state_store
1372
unless names_it goto names_loop_end
1373
$S0 = shift names_it
1374
$P0 = state_store[$S0]
1381
=item !state_var_inited
1383
Takes the name of a state variable and returns true if it's been
1384
initialized already.
1388
.sub '!state_var_inited'
1392
$P0 = getprop '$!state_store', $P0
1400
=item !MAKE_WHATEVER_CLOSURE
1402
Creates whatever closures (*.foo => { $_.foo })
1406
.sub '!MAKE_WHATEVER_CLOSURE'
1408
.param pmc pos_args :slurpy
1409
.param pmc named_args :slurpy :named
1413
name = getprop 'name', $P0
1415
.lex '$pos_args', pos_args
1416
.lex '$named_args', named_args
1417
.const 'Sub' $P0 = '!whatever_dispatch_helper'
1418
$P0 = newclosure $P0
1419
.const 'Sub' fixup = '!fixup_routine_type'
1423
.sub '!whatever_dispatch_helper' :outer('!MAKE_WHATEVER_CLOSURE')
1425
$P0 = find_lex '$name'
1427
$P1 = find_lex '$pos_args'
1428
$P2 = find_lex '$named_args'
1429
.tailcall obj.$S0($P1 :flat, $P2 :flat :named)
1433
=item !HANDLES_HELPER
1437
.sub '!HANDLES_DISPATCH_HELPER'
1439
.param pmc pos_args :slurpy
1440
.param pmc name_args :slurpy :named
1442
# Look up attribute and method name, and look up the attribute.
1444
.local string attrname, methodname
1447
$P1 = getprop 'methodname', $P0
1449
$P1 = getprop 'attrname', $P0
1451
attr = getattribute obj, attrname
1453
# If it's an array, need to iterate over the set of options. Otherwise,
1455
$S0 = substr attrname, 0, 1
1456
if $S0 == '@' goto handles_on_array
1457
.tailcall attr.methodname(pos_args :flat, name_args :flat :named)
1459
.local pmc handles_array_it
1460
handles_array_it = iter attr
1461
handles_array_it_loop:
1462
unless handles_array_it goto handles_array_it_loop_end
1463
$P0 = shift handles_array_it
1464
$I0 = $P0.'can'(methodname)
1465
unless $I0 goto handles_array_it_loop
1466
.tailcall $P0.methodname(pos_args :flat, name_args :flat :named)
1467
handles_array_it_loop_end:
1468
'die'("You used handles on attribute ", attrname, ", but nothing in the array can do method ", methodname)
1472
=item !make_type_fail_message
1474
Makes a type check failure error message, so we don't have to be doing so all
1475
over the rest of the code base.
1479
.sub '!make_type_fail_message'
1480
.param string what_failed
1482
.param pmc wanted_type
1485
.local string output
1486
output = concat what_failed, " type check failed; expected "
1488
# Work out what we were looking for and show that.
1489
$I0 = isa wanted_type, 'P6protoobject'
1490
if $I0 goto simple_type
1491
$I0 = isa wanted_type, 'Junction'
1492
if $I0 goto junc_wanted
1494
$P0 = wanted_type.'WHAT'()
1495
goto wanted_type_done
1497
$P0 = wanted_type.'eigenstates'()
1499
if $I0 > 1 goto wanted_type_done
1505
# Report what we actually got.
1506
output = concat ", but got "
1507
$P0 = got_type.'WHAT'()
1515
=item !bindability_checker
1517
Invokes a sub in bindability checking mode. Catches any exceptions that are
1518
thrown while trying to bind. If the bind fails, returns null. Otherwise, we
1519
return the resume continuation so we can continue execution after the bind.
1523
.sub '!bindability_checker'
1526
.param pmc named_args
1528
# Clone sub and attach a prop to say we're just doing a bindability check.
1530
sub = clone orig_sub
1531
.fixup_cloned_sub(orig_sub, sub)
1532
setprop sub, '$!bind_check_only', sub
1534
# Set up exception handler and invoke. We really should get an exception
1535
# whether it binds or not; if we don't, best we can do is hand back the
1536
# sub, but warn something may be very wrong.
1538
sub(pos_args :flat, named_args :flat :named)
1540
warn("Potential internal error: bindability check may have done more than just binding.")
1546
if ex == '__BIND_SUCCESSFUL__' goto success
1557
Used by P6invocation to help us get soft-failure semantics when no deferal
1562
.sub '!deferal_fail'
1563
.param pmc pos_args :slurpy
1564
.param pmc named_args :slurpy :named
1565
.lex '__CANDIDATE_LIST__', $P0
1566
.tailcall '!FAIL'('No method to defer to')
1577
# vim: expandtab shiftwidth=4 ft=pir: