5 Object - Perl 6 Object class
9 This file sets up the base classes and methods for Perl 6's
10 object system. Differences (and conflicts) between Parrot's
11 object model and the Perl 6 model means we have to do a little
12 name and method trickery here and there, and this file takes
21 Perform initializations and create the base classes.
26 .sub 'onload' :anon :init :load
28 load_bytecode 'P6object.pbc'
29 $P0 = get_root_global ['parrot'], 'P6metaclass'
30 $P0.'new_class'('Perl6Object', 'name'=>'Object')
32 set_hll_global ['Perl6Object'], '$!P6META', p6meta
35 =item infix:=(source) (assignment method)
37 Assigns C<source> to C<target>. We use the 'item' method to allow Lists
38 and Mappings to be converted into Array(ref) and Hash(ref).
42 .namespace ['Perl6Object']
43 .sub 'infix:=' :method
45 $I0 = can source, 'item'
46 unless $I0 goto have_source
47 source = source.'item'()
50 $I0 = isa self, 'Mutable'
57 getprop type, 'type', self
58 if null type goto do_assign
59 $I0 = type.'ACCEPTS'(source)
61 die "Type mismatch in assignment."
64 eq_addr self, source, end
79 Return the scalar as a Hash.
83 .namespace ['Perl6Object']
92 Return the scalar component of the invocant. For most objects,
93 this is simply the invocant itself.
101 unless $I0 == 1 goto have_x
105 unless $I0 goto have_item
111 .namespace ['Perl6Object']
119 Return the list component of the invocant. For most (Scalar)
120 objects, we create a List containing the invocant.
133 Return true if the object is defined.
137 .sub 'defined' :method
138 $P0 = get_hll_global ['Bool'], 'True'
142 .sub '' :method :vtable('defined')
143 $I0 = self.'defined'()
150 Create a new object having the same class as the invocant.
155 .param pmc init_parents :slurpy
156 .param pmc init_this :named :slurpy
160 p6meta = get_hll_global ['Perl6Object'], '$!P6META'
161 $P0 = p6meta.get_parrotclass(self)
164 # If this proto object has a WHENCE auto-vivification, we should use
165 # put any values it contains but that init_this does not into init_this.
167 whence = self.'WHENCE'()
168 unless whence goto no_whence
169 .local pmc this_whence_iter
170 this_whence_iter = new 'Iterator', whence
171 this_whence_iter_loop:
172 unless this_whence_iter goto no_whence
173 $S0 = shift this_whence_iter
174 $I0 = exists init_this[$S0]
175 if $I0 goto this_whence_iter_loop
178 goto this_whence_iter_loop
181 # Now we will initialize each attribute in the class itself and it's
182 # parents with an Undef or the specified initialization value. Note that
183 # the all_parents list includes ourself.
184 .local pmc all_parents, class_iter
185 all_parents = inspect $P0, "all_parents"
186 class_iter = new 'Iterator', all_parents
188 unless class_iter goto class_iter_loop_end
190 cur_class = shift class_iter
192 # If it's PMCProxy, then skip over it, since it's attribute is the delegate
193 # instance of a parent PMC class, which we should not change to Undef.
194 .local int is_pmc_proxy
195 is_pmc_proxy = isa cur_class, "PMCProxy"
196 if is_pmc_proxy goto class_iter_loop_end
198 # If this the current class?
199 .local pmc init_attribs
200 eq_addr cur_class, $P0, current_class
202 # If it's not the current class, need to see if we have any attributes.
203 # Go through the provided init_parents to see if we have anything that
205 .local pmc ip_iter, cur_ip
206 ip_iter = new 'Iterator', init_parents
208 unless ip_iter goto ip_iter_loop_end
209 cur_ip = shift ip_iter
211 # We will check if their HOW matches.
212 $P2 = p6meta.'get_parrotclass'(cur_ip)
213 eq_addr cur_class, $P2, found_parent_init
215 goto found_init_attribs
218 # If we get here, found nothing.
219 init_attribs = new 'Hash'
220 goto parent_init_search_done
222 # We found some parent init data, potentially.
224 init_attribs = cur_ip.WHENCE()
225 $I0 = 'defined'(init_attribs)
226 if $I0 goto parent_init_search_done
227 init_attribs = new 'Hash'
228 parent_init_search_done:
229 goto found_init_attribs
231 # If it's the current class, we will take the init_this hash.
233 init_attribs = init_this
236 # Now go through attributes of the current class and iternate over them.
237 .local pmc attribs, iter
238 attribs = inspect cur_class, "attributes"
239 iter = new 'Iterator', attribs
241 unless iter goto iter_end
244 # See if we have an init value; use Undef if not.
245 .local int got_init_value
247 got_init_value = exists init_attribs[$S1]
248 if got_init_value goto have_init_value
252 $P2 = init_attribs[$S1]
253 delete init_attribs[$S1]
256 # Is it a scalar? If so, want a scalar container with the type set on it.
258 sigil = substr $S0, 0, 1
259 if sigil != '$' goto no_scalar
260 .local pmc attr_info, type
261 attr_info = attribs[$S0]
262 if null attr_info goto set_attrib
263 type = attr_info['type']
264 if null type goto set_attrib
265 if got_init_value goto no_proto_init
266 $I0 = isa type, 'P6protoobject'
267 unless $I0 goto no_proto_init
270 $P2 = new 'Perl6Scalar', $P2
271 setprop $P2, 'type', type
275 # Is it an array? If so, initialize to Perl6Array.
276 if sigil != '@' goto no_array
277 $P2 = new 'Perl6Array'
281 # Is it a Hash? If so, initialize to Perl6Hash.
282 if sigil != '%' goto no_hash
283 $P2 = new 'Perl6Hash'
288 push_eh set_attrib_eh
289 setattribute $P1, cur_class, $S0, $P2
294 # Do we have anything left in the hash? If so, unknown.
295 $I0 = elements init_attribs
296 if $I0 == 0 goto init_attribs_ok
297 'die'("You passed an initialization parameter that does not have a matching attribute.")
309 Return the invocant's auto-vivification closure.
313 .sub 'WHENCE' :method
321 Define REJECTS methods for objects (this would normally
322 be part of the Pattern role, but we put it here for now
327 .sub 'REJECTS' :method
329 $P0 = self.'ACCEPTS'(topic)
336 Defines the .true method on all objects via C<prefix:?>.
341 .return 'prefix:?'(self)
344 =item get_bool (vtable)
346 Returns true if the object is defined, false otherwise.
350 .sub '' :vtable('get_bool')
351 $I0 = 'defined'(self)
364 $P0 = get_hll_global 'print'
369 $P0 = get_hll_global 'say'
375 Gets the memory address of the object.
386 Gets the object's identity value
391 # For normal objects, this can just be the memory address.
392 .return self.'WHERE'()
397 =head2 Private methods
401 =item !cloneattr(attrlist)
403 Create a clone of self, also cloning the attributes given by attrlist.
407 .sub '!cloneattr' :method
408 .param string attrlist
409 .local pmc p6meta, result
410 p6meta = get_hll_global ['Perl6Object'], '$!P6META'
411 $P0 = p6meta.'get_parrotclass'(self)
415 attr_it = split ' ', attrlist
417 unless attr_it goto attr_end
419 unless $S0 goto attr_loop
420 $P1 = getattribute self, $S0
422 setattribute result, $S0, $P1
430 .param string method_name
431 .param pmc pos_args :slurpy
432 .param pmc named_args :slurpy :named
434 # For now we won't worry about signature, just if a method exists.
435 $I0 = can self, method_name
437 $P0 = get_hll_global 'Failure'
440 # If we do have a method, call it.
442 .return self.method_name(pos_args :flat, named_args :named :flat)
447 .param string method_name
448 .param pmc pos_args :slurpy
449 .param pmc named_args :slurpy :named
451 # Return an empty list if no methods exist at all.
452 $I0 = can self, method_name
456 # Now find all methods and call them - since we know there are methods,
457 # we just pass on to infix:.+.
459 .return self.'!.+'(method_name, pos_args :flat, named_args :named :flat)
464 .param string method_name
465 .param pmc pos_args :slurpy
466 .param pmc named_args :slurpy :named
468 # We need to find all methods we could call with the right name.
469 .local pmc p6meta, result_list, class, mro, it, cap_class, failure_class
470 result_list = 'list'()
471 p6meta = get_hll_global ['Perl6Object'], '$!P6META'
473 class = p6meta.get_parrotclass(class)
474 mro = inspect class, 'all_parents'
476 cap_class = get_hll_global 'Capture'
477 failure_class = get_hll_global 'Failure'
479 unless it goto mro_loop_end
480 .local pmc cur_class, meths, cur_meth
482 meths = inspect cur_class, 'methods'
483 cur_meth = meths[method_name]
484 if null cur_meth goto mro_loop
486 # If we're here, found a method. Invoke it and add capture of the results
487 # to the result list.
488 .local pmc pos_res, named_res, cap
489 (pos_res :slurpy, named_res :named :slurpy) = cur_meth(self, pos_args :flat, named_args :named :flat)
490 cap = 'prefix:\\'(pos_res :flat, named_res :flat :named)
491 push result_list, cap
495 # Make sure we got some elements, or we have to die.
496 $I0 = elements result_list
497 if $I0 == 0 goto failure
498 .return (result_list)
500 $S0 = "Could not invoke method '"
501 concat $S0, method_name
502 concat $S0, "' on invocant of type '"
511 .param string method_name
512 .param pmc pos_args :slurpy
513 .param pmc named_args :slurpy :named
515 # Get the HOW or the object and do the call on that.
518 .return how.method_name(self, pos_args :flat, named_args :flat :named)
522 .namespace ['P6protoobject']
526 =head2 Methods on P6protoobject
532 Returns the protoobject's autovivification closure.
536 .sub 'WHENCE' :method
537 .local pmc props, whence
538 props = getattribute self, '%!properties'
539 if null props goto ret_undef
540 whence = props['WHENCE']
541 if null whence goto ret_undef
553 .sub 'defined' :method
554 $P0 = get_hll_global ['Bool'], 'False'
561 Returns itself in item context.
572 Returns a list containing itself in list context.
581 =item get_pmc_keyed(key) (vtable method)
583 Returns a proto-object with an autovivification closure attached to it.
587 .sub get_pmc_keyed :vtable :method
590 # We'll build auto-vivification hash of values.
591 .local pmc WHENCE, key, val
596 if $S0 == 'Pair' goto from_pair
597 if $S0 == 'List' goto from_list
598 'die'("Auto-vivification closure did not contain a Pair")
609 .local pmc list_iter, cur_pair
610 list_iter = new 'Iterator', what
612 unless list_iter goto done_whence
613 cur_pair = shift list_iter
614 key = cur_pair.'key'()
615 val = cur_pair.'value'()
620 # Now create a clone of the protoobject.
621 .local pmc protoclass, res, props, tmp
622 protoclass = class self
625 # Attach the WHENCE property.
626 props = getattribute self, '%!properties'
627 unless null props goto have_props
630 props['WHENCE'] = WHENCE
631 setattribute res, '%!properties', props
644 # vim: expandtab shiftwidth=4 ft=pir: