2 Copyright (C) 2001-2010, Parrot Foundation.
7 src/pmc/class.pmc - defines a class
11 This class implements the Class PMC, as outlined in
12 F<docs/pdds/pdd15_objects.pod>.
14 Class is not derived from any other PMC.
18 The Class PMC structure (C<Parrot_Class>) consists of twelve items:
24 The type number of the PMC.
28 The name of the class -- a STRING.
29 An empty STRING is allocated during initialization.
33 The namespace the class is associated with, if any.
34 A Null PMC is allocated during initialization.
38 A flag denoting whether this class has been instantiated since last
39 modification. A native integer with value zero is allocated during
44 An array of immediate parent classes.
45 An empty ResizablePMCArray PMC is allocated during initialization.
49 A cached array of ourself and all parent classes, in method resolution
50 order (MRO). A ResizablePMCArray PMC is allocated during initialization,
51 and is populated with the current class.
55 An array of the roles this class has been composed from.
56 An empty ResizablePMCArray PMC is allocated during initialization.
60 A directory of method names and method bodies this class provides.
61 An empty Hash PMC is allocated during initialization.
63 =item C<vtable_overrides>
65 A directory of vtable function names and method bodies this class overrides.
66 An empty Hash PMC is allocated during initialization.
68 =item C<attrib_metadata>
70 A directory of attribute names and attribute metadata this class contains.
71 An empty Hash PMC is allocated during initialization.
75 A lookup table for attributes in this class and parents.
76 A Null PMC is allocated during initialization.
80 A cache of visible attribute names to attribute indexes.
81 A Null PMC is allocated during initialization.
83 =item C<resolve_method>
85 A list of method names the class provides used for name conflict resolution.
86 An empty ResizablePMCArray PMC is allocated during initialization.
92 #define PARROT_IN_OBJECTS_C /* To get the vtable.h imports we want. */
93 #include "parrot/oo_private.h"
94 #include "pmc/pmc_object.h"
95 #include "pmc/pmc_namespace.h"
97 /* HEADERIZER HFILE: none */
98 /* HEADERIZER BEGIN: static */
99 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
101 static void build_attrib_index(PARROT_INTERP, ARGIN(PMC *self))
102 __attribute__nonnull__(1)
103 __attribute__nonnull__(2);
105 static int cache_class_attribs(PARROT_INTERP,
106 ARGIN(PMC *cur_class),
107 ARGIN(PMC *attrib_index),
110 __attribute__nonnull__(1)
111 __attribute__nonnull__(2)
112 __attribute__nonnull__(3)
113 __attribute__nonnull__(4);
115 static void calculate_mro(PARROT_INTERP,
118 __attribute__nonnull__(1)
119 __attribute__nonnull__(2);
121 static void init_class_from_hash(PARROT_INTERP,
123 ARGIN_NULLOK(PMC *info))
124 __attribute__nonnull__(1)
125 __attribute__nonnull__(2)
126 FUNC_MODIFIES(*self);
128 static void initialize_parents(PARROT_INTERP,
130 ARGIN(PMC *all_parents))
131 __attribute__nonnull__(1)
132 __attribute__nonnull__(2)
133 __attribute__nonnull__(3);
135 static void initialize_parents_pmc(PARROT_INTERP,
137 ARGIN(PMC *all_parents),
139 __attribute__nonnull__(1)
140 __attribute__nonnull__(2)
141 __attribute__nonnull__(3)
142 __attribute__nonnull__(4);
144 PARROT_CANNOT_RETURN_NULL
145 static STRING * make_class_name(PARROT_INTERP, ARGIN(PMC *SELF))
146 __attribute__nonnull__(1)
147 __attribute__nonnull__(2);
149 #define ASSERT_ARGS_build_attrib_index __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
150 PARROT_ASSERT_ARG(interp) \
151 , PARROT_ASSERT_ARG(self))
152 #define ASSERT_ARGS_cache_class_attribs __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
153 PARROT_ASSERT_ARG(interp) \
154 , PARROT_ASSERT_ARG(cur_class) \
155 , PARROT_ASSERT_ARG(attrib_index) \
156 , PARROT_ASSERT_ARG(cache))
157 #define ASSERT_ARGS_calculate_mro __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
158 PARROT_ASSERT_ARG(interp) \
159 , PARROT_ASSERT_ARG(SELF))
160 #define ASSERT_ARGS_init_class_from_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
161 PARROT_ASSERT_ARG(interp) \
162 , PARROT_ASSERT_ARG(self))
163 #define ASSERT_ARGS_initialize_parents __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
164 PARROT_ASSERT_ARG(interp) \
165 , PARROT_ASSERT_ARG(object) \
166 , PARROT_ASSERT_ARG(all_parents))
167 #define ASSERT_ARGS_initialize_parents_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
168 PARROT_ASSERT_ARG(interp) \
169 , PARROT_ASSERT_ARG(object) \
170 , PARROT_ASSERT_ARG(all_parents) \
171 , PARROT_ASSERT_ARG(init))
172 #define ASSERT_ARGS_make_class_name __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
173 PARROT_ASSERT_ARG(interp) \
174 , PARROT_ASSERT_ARG(SELF))
175 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
176 /* HEADERIZER END: static */
180 =item C<static int cache_class_attribs(PARROT_INTERP, PMC *cur_class, PMC
181 *attrib_index, PMC *cache, int cur_index)>
188 cache_class_attribs(PARROT_INTERP,
189 ARGIN(PMC *cur_class), ARGIN(PMC *attrib_index),
190 ARGIN(PMC *cache), int cur_index)
192 ASSERT_ARGS(cache_class_attribs)
193 /* The attribute metadata hash. */
194 Parrot_Class_attributes * const class_info = PARROT_CLASS(cur_class);
195 PMC * const attribs = class_info->attrib_metadata;
196 PMC * const iter = VTABLE_get_iter(interp, attribs);
198 /* Build a string representing the fully qualified class name. */
199 /* Retrieve the fully qualified class name for the class. */
200 STRING * const fq_class = VTABLE_get_string(interp, cur_class);
201 PMC * const class_cache = Parrot_pmc_new(interp, enum_class_Hash);
202 VTABLE_set_pmc_keyed_str(interp, cache, fq_class, class_cache);
204 /* Iterate over the attributes. */
205 while (VTABLE_get_bool(interp, iter)) {
207 PMC * const cur_attrib = VTABLE_get_pmc_keyed_str(interp,
208 attribs, VTABLE_shift_string(interp, iter));
210 /* Get attribute name and append it to the key. */
211 STRING * const name_str = CONST_STRING(interp, "name");
212 STRING * const attrib_name = VTABLE_get_string_keyed_str(
213 interp, cur_attrib, name_str);
215 STRING * const full_key = Parrot_str_concat(interp, fq_class, attrib_name);
217 /* Insert into hash, along with index. */
218 VTABLE_set_integer_keyed_str(interp, attrib_index, full_key, cur_index);
219 VTABLE_set_integer_keyed_str(interp, class_cache, attrib_name, cur_index);
228 =item C<static void build_attrib_index(PARROT_INTERP, PMC *self)>
230 This function builds the attribute index (table to map class name and
231 attribute name to an index) for the current class.
238 build_attrib_index(PARROT_INTERP, ARGIN(PMC *self))
240 ASSERT_ARGS(build_attrib_index)
241 Parrot_Class_attributes * const _class = PARROT_CLASS(self);
243 PMC * const attrib_index = Parrot_pmc_new(interp, enum_class_Hash);
244 PMC * const cache = Parrot_pmc_new(interp, enum_class_Hash);
245 const int num_classes = VTABLE_elements(interp, _class->all_parents);
248 /* Go over the list of all parents to construct the attribute index. */
249 for (i = 0; i < num_classes; ++i) {
250 /* Get the class and check that it respects the standard class interface
251 * (if not we don't know how it stores its attributes, so we'll have to
252 * delegate the lookup). */
253 PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp,
254 _class->all_parents, i);
256 if (PObj_is_class_TEST(cur_class))
257 cur_index = cache_class_attribs(interp, cur_class,
258 attrib_index, cache, cur_index);
261 /* Store built attribute index and invalidate cache. */
262 _class->attrib_index = attrib_index;
263 _class->attrib_cache = cache;
268 =item C<static void init_class_from_hash(PARROT_INTERP, PMC *self, PMC *info)>
270 Takes a hash and initializes the class based on it.
277 init_class_from_hash(PARROT_INTERP, ARGMOD(PMC *self), ARGIN_NULLOK(PMC *info))
279 ASSERT_ARGS(init_class_from_hash)
280 Parrot_Class_attributes * const _class = PARROT_CLASS(self);
281 STRING * const name_str = CONST_STRING(interp, "name");
282 STRING * const parents_str = CONST_STRING(interp, "parents");
283 STRING * const methods_str = CONST_STRING(interp, "methods");
284 STRING * const roles_str = CONST_STRING(interp, "roles");
285 STRING * const attrs_str = CONST_STRING(interp, "attributes");
287 STRING *resolve_method_str;
289 /* Ensure we actually have some initialization info. */
290 if (PMC_IS_NULL(info))
293 /* Take a copy of the current namespace the class is attached to. */
294 old_ns = _class->_namespace;
296 /* Check if we have a name/namespace. */
297 if (VTABLE_exists_keyed_str(interp, info, name_str)) {
300 PMC *name_arg = VTABLE_get_pmc_keyed_str(interp, info, name_str);
304 /* If we were passed a namespace PMC, set the namespace attribute
305 * directly. Otherwise, lookup or create the appropriate namespace. */
306 if (name_arg->vtable->base_type == enum_class_NameSpace) {
307 new_namespace = name_arg;
308 name_arg = Parrot_ns_get_name(interp, new_namespace);
309 VTABLE_shift_string(interp, name_arg);
312 PMC * const hll_ns = VTABLE_get_pmc_keyed_int(interp,
313 interp->HLL_namespace, Parrot_pcc_get_HLL(interp, CURRENT_CONTEXT(interp)));
314 new_namespace = Parrot_ns_make_namespace_keyed(interp, hll_ns, name_arg);
317 if (PMC_IS_NULL(new_namespace))
318 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
319 "Failed to set namespace for class.");
321 /* Set the name of the class to the name of the innermost namespace
322 * associated with the class. */
323 new_name = VTABLE_get_string(interp, new_namespace);
325 if (STRING_IS_NULL(new_name) || STRING_IS_EMPTY(new_name))
326 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
327 "Failed to set name for class.");
329 _class->_namespace = new_namespace;
330 _class->name = new_name;
332 /* At this point we know the class isn't anonymous */
333 CLASS_is_anon_CLEAR(self);
335 /* Register a type number for the class. */
336 type_num = Parrot_oo_register_type(interp, name_arg, new_namespace);
338 /* Link the type number with the class's vtable. */
339 new_vtable = Parrot_clone_vtable(interp, self->vtable);
341 new_vtable->base_type = type_num;
342 new_vtable->pmc_class = self;
343 new_vtable->whoami = VTABLE_get_string(interp, self);
344 new_vtable->mro = _class->all_parents;
345 new_vtable->ro_variant_vtable =
346 Parrot_clone_vtable(interp, self->vtable->ro_variant_vtable);
348 /* Store the class's vtable in the global table */
349 interp->vtables[type_num] = new_vtable;
351 _class->id = type_num;
354 /* If we were attached to a namespace and are now attached to a new one,
355 * need to unset ourselves in the old namespace. */
356 if (!PMC_IS_NULL(old_ns) && _class->_namespace != old_ns)
357 Parrot_pcc_invoke_method_from_c_args(interp, old_ns, CONST_STRING(interp, "set_class"), "P->", PMCNULL);
359 /* Link namespace to this class, if there is one. */
360 if (!PMC_IS_NULL(_class->_namespace)) {
361 STRING * const set_class_str = CONST_STRING(interp, "set_class");
362 Parrot_pcc_invoke_method_from_c_args(interp, _class->_namespace, set_class_str, "P->",
366 /* Initialize resolve_method. */
367 resolve_method_str = CONST_STRING(interp, "resolve_method");
368 if (VTABLE_exists_keyed_str(interp, info, resolve_method_str)) {
370 _class->resolve_method =
371 VTABLE_get_pmc_keyed_str(interp, info, resolve_method_str);
374 /* Initialize parents, if we have any. */
375 if (VTABLE_exists_keyed_str(interp, info, parents_str)) {
376 /* Loop over parents array and add them. */
377 PMC * const parent_list = VTABLE_get_pmc_keyed_str(interp, info,
379 const int parent_count = VTABLE_elements(interp, parent_list);
382 for (i = 0; i < parent_count; ++i)
383 VTABLE_add_parent(interp, self,
384 VTABLE_get_pmc_keyed_int(interp, parent_list, i));
387 /* Initialize roles, if we have any. */
388 if (VTABLE_exists_keyed_str(interp, info, roles_str)) {
389 /* Loop over roles array and compose them. */
390 PMC * const role_list = VTABLE_get_pmc_keyed_str(interp, info,
392 const int role_count = VTABLE_elements(interp, role_list);
395 for (i = 0; i < role_count; ++i)
396 VTABLE_add_role(interp, self,
397 VTABLE_get_pmc_keyed_int(interp, role_list, i));
400 /* Initialize attributes, if we have any. */
401 if (VTABLE_exists_keyed_str(interp, info, attrs_str)) {
402 /* Loop over attributes array and add them. */
403 PMC * const attrs_name_list = VTABLE_get_pmc_keyed_str(interp, info,
405 const int attrib_count = VTABLE_elements(interp, attrs_name_list);
408 for (i = 0; i < attrib_count; ++i) {
409 STRING * const attr_name = VTABLE_get_string_keyed_int(interp,
411 VTABLE_add_attribute(interp, self, attr_name, PMCNULL);
415 /* Initialize methods. */
416 if (VTABLE_exists_keyed_str(interp, info, methods_str)) {
417 /* Get the methods hash. */
418 PMC * const methods = VTABLE_get_pmc_keyed_str(interp, info,
421 /* Iterate over the list of methods. */
422 PMC * const iter = VTABLE_get_iter(interp, methods);
424 while (VTABLE_get_bool(interp, iter)) {
425 /* Add the method. */
426 STRING * const method_name = VTABLE_shift_string(interp, iter);
427 PMC * const method_pmc = VTABLE_get_pmc_keyed_str(interp,
428 methods, method_name);
429 VTABLE_add_method(interp, self, method_name, method_pmc);
433 /* Extract any methods from the namespace */
434 Parrot_oo_extract_methods_from_namespace(interp, self, _class->_namespace);
439 =item C<static void initialize_parents(PARROT_INTERP, PMC *object, PMC
447 initialize_parents(PARROT_INTERP, ARGIN(PMC *object), ARGIN(PMC *all_parents))
449 ASSERT_ARGS(initialize_parents)
450 INTVAL parent_index = VTABLE_elements(interp, all_parents) - 1;
451 STRING * const name = CONST_STRING(interp, "init");
453 /* Loop through the parents in reverse MRO order. */
454 for (; parent_index >= 0; --parent_index) {
456 PMC * const parent = VTABLE_get_pmc_keyed_int(interp,
457 all_parents, parent_index);
459 /* PMCProxy parents store an instance to delegate to */
460 if (parent->vtable->base_type == enum_class_PMCProxy) {
461 PMC *proxy = VTABLE_instantiate(interp, parent, PMCNULL);
462 STRING *proxy_str = CONST_STRING(interp, "proxy");
463 VTABLE_set_attr_keyed(interp, object, parent, proxy_str, proxy);
466 meth = Parrot_oo_find_vtable_override_for_class(interp, parent, name);
468 if (!PMC_IS_NULL(meth)) {
469 /* preserve current_object */
470 Parrot_ext_call(interp, meth, "Pi->", object);
477 =item C<static void initialize_parents_pmc(PARROT_INTERP, PMC *object, PMC
478 *all_parents, PMC *init)>
485 initialize_parents_pmc(PARROT_INTERP, ARGIN(PMC *object),
486 ARGIN(PMC *all_parents), ARGIN(PMC *init))
488 ASSERT_ARGS(initialize_parents_pmc)
489 INTVAL parent_index = VTABLE_elements(interp, all_parents) - 1;
490 STRING * const name = CONST_STRING(interp, "init_pmc");
492 /* Loop through the parents in reverse MRO order. */
493 for (; parent_index >= 0; --parent_index) {
495 PMC * const parent = VTABLE_get_pmc_keyed_int(interp,
496 all_parents, parent_index);
498 /* PMCProxy parents store an instance to delegate to */
499 if (parent->vtable->base_type == enum_class_PMCProxy) {
500 PMC * const proxy = VTABLE_instantiate(interp, parent, init);
501 STRING * const proxy_str = CONST_STRING(interp, "proxy");
502 VTABLE_set_attr_keyed(interp, object, parent, proxy_str, proxy);
505 meth = Parrot_oo_find_vtable_override_for_class(interp, parent, name);
507 if (!PMC_IS_NULL(meth))
508 Parrot_ext_call(interp, meth, "PiP->", object, init);
514 =item C<static STRING * make_class_name(PARROT_INTERP, PMC *SELF)>
516 This function makes and caches the name of this class, returning the string
517 directly. C<VTABLE_isa()> uses the name without copying it, for efficiency
518 reasons, as it does not modify the STRING. C<VTABLE_get_string()> makes a
519 copy of the STRING, so its callers are free to modify it.
525 PARROT_CANNOT_RETURN_NULL
527 make_class_name(PARROT_INTERP, ARGIN(PMC *SELF))
529 ASSERT_ARGS(make_class_name)
530 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
531 PMC * const _namespace = _class->_namespace;
533 if (!PMC_IS_NULL(_namespace)) {
534 if (_class->fullname)
535 return _class->fullname;
538 /* Call the 'get_name' method on the class's associated
539 * namespace to retrieve a fully qualified list of names, then
540 * join the list with a semicolon. */
541 PMC * const names = Parrot_ns_get_name(interp, _namespace);
543 if (!PMC_IS_NULL(names))
544 /* remove the HLL namespace name */
545 VTABLE_shift_string(interp, names);
546 _class->fullname = Parrot_str_join(interp, CONST_STRING(interp, ";"), names);
547 return _class->fullname;
551 /* Otherwise, copy the stored string name of the class. */
557 =item C<static void calculate_mro(PARROT_INTERP, PMC *SELF, INTVAL num_parents)>
559 Calculates the C3 method resolution order for this class. C3 is the name of an
560 algorithm used to calculate the method resolution order (MRO) to use in a
561 system with multiple inheritance. For more information see the documentation
562 associated with C<Parrot_ComputeMRO_C3>.
569 calculate_mro(PARROT_INTERP, ARGIN(PMC *SELF), INTVAL num_parents)
571 ASSERT_ARGS(calculate_mro)
572 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
574 /* SELF is already on the all_parents */
575 if (num_parents == 0)
578 if (num_parents == 1) {
579 STRING * const ap = CONST_STRING(interp, "all_parents");
580 PMC * const parent = VTABLE_get_pmc_keyed_int(interp,
582 PMC * const parent_mro = VTABLE_inspect_str(interp, parent, ap);
583 PMC * const mro = VTABLE_clone(interp, parent_mro);
584 VTABLE_unshift_pmc(interp, mro, SELF);
585 _class->all_parents = mro;
588 _class->all_parents = Parrot_ComputeMRO_C3(interp, SELF);
590 if (!CLASS_is_anon_TEST(SELF))
591 interp->vtables[VTABLE_type(interp, SELF)]->mro = _class->all_parents;
606 pmclass Class auto_attrs {
608 ATTR INTVAL id; /* The type number of the PMC. */
609 ATTR STRING *name; /* The name of the class. */
610 ATTR STRING *fullname; /* The name of the class. */
611 ATTR PMC *_namespace; /* The namespace it's linked to, if any. */
612 ATTR INTVAL instantiated; /* Any instantiations since last modification? */
613 ATTR PMC *parents; /* Immediate parent classes. */
614 ATTR PMC *all_parents; /* Cached list of ourself and all parents, in MRO order. */
615 ATTR PMC *roles; /* An array of roles. */
616 ATTR PMC *methods; /* Hash of method names to methods in this class. */
617 ATTR PMC *vtable_overrides; /* Hash of Parrot v-table methods we override. */
618 ATTR PMC *attrib_metadata; /* Hash of attributes in this class to hashes of metadata. */
619 ATTR PMC *attrib_index; /* Lookup table for attributes in this and parents. */
620 ATTR PMC *attrib_cache; /* Cache of visible attrib names to indexes. */
621 ATTR PMC *resolve_method; /* List of method names the class provides to resolve
622 * conflicts with methods from roles. */
623 ATTR PMC *parent_overrides;
624 ATTR PMC *meth_cache;
625 ATTR Hash *isa_cache;
631 Initializes a Class PMC.
633 =item C<void init_pmc(PMC *init_data)>
635 The actual class creation code, called from C<newclass> opcode. The C<init_data>
636 argument may be either the name of the class or a hash of initialization
637 arguments. The class is attached to the current HLL namespace.
644 Parrot_Class_attributes * const _class =
645 (Parrot_Class_attributes *) PMC_data(SELF);
647 /* Set flag for custom GC mark. */
648 PObj_custom_mark_destroy_SETALL(SELF);
650 /* Set up the object. */
651 _class->name = CONST_STRING(INTERP, "");
652 _class->_namespace = PMCNULL;
653 _class->parents = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
654 _class->all_parents = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
655 _class->roles = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
656 _class->methods = Parrot_pmc_new(INTERP, enum_class_Hash);
657 _class->attrib_metadata = Parrot_pmc_new(INTERP, enum_class_Hash);
658 _class->attrib_index = PMCNULL;
659 _class->attrib_cache = PMCNULL;
660 _class->meth_cache = PMCNULL;
661 _class->resolve_method = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
663 _class->vtable_overrides = Parrot_pmc_new(INTERP, enum_class_Hash);
664 _class->parent_overrides = Parrot_pmc_new(INTERP, enum_class_Hash);
666 _class->isa_cache = parrot_create_hash(INTERP,
667 enum_type_INTVAL, Hash_key_type_PMC_ptr);
670 /* We put ourself on the all parents list. */
671 VTABLE_push_pmc(INTERP, _class->all_parents, SELF);
673 /* We are a class. */
674 PObj_is_class_SET(SELF);
676 /* By default we're anonymous. */
677 CLASS_is_anon_SET(SELF);
680 VTABLE void init_pmc(PMC *init_data) {
682 const INTVAL arg_type = VTABLE_type(INTERP, init_data);
683 STRING * const name_str = CONST_STRING(INTERP, "name");
685 /* Set up the object. */
688 /* fast attempt to determine init_data type */
690 case enum_class_String:
692 case enum_class_ResizableStringArray:
693 case enum_class_NameSpace:
694 /* set only the name property */
695 arg = Parrot_pmc_new(INTERP, enum_class_Hash);
696 VTABLE_set_pmc_keyed_str(INTERP, arg, name_str, init_data);
699 case enum_class_Hash:
703 /* slow attempt to determine init_data type */
705 if (VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "String"))
706 || VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "Key"))
707 || VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "ResizableStringArray"))) {
708 /* set only the name property */
709 arg = Parrot_pmc_new(INTERP, enum_class_Hash);
710 VTABLE_set_pmc_keyed_str(INTERP, arg, name_str, init_data);
713 if (VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "Hash")))
716 Parrot_ex_throw_from_c_args(INTERP, NULL,
717 EXCEPTION_INVALID_OPERATION,
718 "Invalid class name key in init_pmc for Class");
722 /* Initialize the class with the supplied data. */
723 init_class_from_hash(INTERP, SELF, arg);
727 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
728 parrot_hash_destroy(INTERP, _class->isa_cache);
733 =item C<STRING *get_string()>
735 Returns the name of the class (without the HLL namespace).
741 VTABLE STRING *get_string() {
742 return make_class_name(INTERP, SELF);
749 Marks any referenced strings and PMCs in the structure as live.
756 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
757 Parrot_gc_mark_STRING_alive(INTERP, _class->name);
758 Parrot_gc_mark_STRING_alive(INTERP, _class->fullname);
759 Parrot_gc_mark_PMC_alive(INTERP, _class->_namespace);
760 Parrot_gc_mark_PMC_alive(INTERP, _class->parents);
761 Parrot_gc_mark_PMC_alive(INTERP, _class->all_parents);
762 Parrot_gc_mark_PMC_alive(INTERP, _class->roles);
763 Parrot_gc_mark_PMC_alive(INTERP, _class->methods);
764 Parrot_gc_mark_PMC_alive(INTERP, _class->vtable_overrides);
765 Parrot_gc_mark_PMC_alive(INTERP, _class->parent_overrides);
766 Parrot_gc_mark_PMC_alive(INTERP, _class->attrib_metadata);
767 Parrot_gc_mark_PMC_alive(INTERP, _class->attrib_index);
768 Parrot_gc_mark_PMC_alive(INTERP, _class->attrib_cache);
769 Parrot_gc_mark_PMC_alive(INTERP, _class->resolve_method);
770 Parrot_gc_mark_PMC_alive(INTERP, _class->meth_cache);
771 if (_class->isa_cache)
772 parrot_mark_hash(INTERP, _class->isa_cache);
778 =item C<void add_attribute(STRING *name, PMC *type)>
780 Adds the given attribute (C<name>) with an optional C<type>.
781 Throws an exception if the current class has been instantiated.
782 Enters the attribute in the C<attrib_metadata> table.
783 Returns an error if an attribute of C<name> already exists.
789 VTABLE void add_attribute(STRING *name, PMC *type) {
790 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
791 PMC * const new_attribute = Parrot_pmc_new(INTERP, enum_class_Hash);
793 /* If we've been instantiated already, not allowed. */
794 if (_class->instantiated)
795 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
796 "Modifications to classes are not allowed after instantiation.");
798 /* If we already have an attribute of this name, it's an error. */
799 if (VTABLE_exists_keyed_str(INTERP, _class->attrib_metadata, name))
800 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
801 "Attribute '%Ss' already exists in '%Ss'.", name,
802 VTABLE_get_string(INTERP, SELF));
804 /* Set name and type. */
805 VTABLE_set_string_keyed_str(INTERP, new_attribute, CONST_STRING(INTERP, "name"), name);
807 if (!PMC_IS_NULL(type))
808 VTABLE_set_pmc_keyed_str(INTERP, new_attribute, CONST_STRING(INTERP, "type"), type);
810 /* Enter the attribute in the attrib_metadata table. */
811 VTABLE_set_pmc_keyed_str(INTERP, _class->attrib_metadata, name,
817 =item C<void remove_attribute(STRING *name)>
819 Removes the given attribute (C<name>) from the class. Throws an exception if
820 the current class has been instantiated, or if the class has no attribute
827 VTABLE void remove_attribute(STRING *name) {
828 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
830 /* If we've been instantiated already, not allowed. */
831 if (_class->instantiated)
832 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
833 "Modifications to classes are not allowed after instantiation.");
835 /* If we don't have an attribute of this name, it's an error. */
836 if (!VTABLE_exists_keyed_str(INTERP, _class->attrib_metadata, name))
837 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
838 "Attribute '%Ss' cannot be removed, does not exist in '%Ss'.", name,
839 VTABLE_get_string(INTERP, SELF));
841 /* Remove the attribute from the attrib_metadata table. */
842 VTABLE_delete_keyed_str(INTERP, _class->attrib_metadata, name);
844 build_attrib_index(INTERP, SELF);
849 =item C<void add_method(STRING *name, PMC *sub)>
851 Adds the given sub PMC as a method with the given name.
856 VTABLE void add_method(STRING *name, PMC *sub) {
857 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
859 VTABLE_get_pmc_keyed_str(INTERP, _class->methods, name);
861 /* If we have already added a method with this name... */
862 if (!PMC_IS_NULL(method)) {
866 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
867 "A method named '%S' already exists in class '%S'. "
868 "It may have been supplied by a role.",
869 name, VTABLE_get_string(INTERP, SELF));
872 /* Enter it into the table. */
873 VTABLE_set_pmc_keyed_str(INTERP, _class->methods, name, sub);
878 =item C<void remove_method(STRING *name)>
880 Removes the method with the given name.
885 VTABLE void remove_method(STRING *name) {
886 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
887 if (VTABLE_exists_keyed_str(INTERP, _class->methods, name))
888 VTABLE_delete_keyed_str(INTERP, _class->methods, name);
890 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
891 "No method named '%S' to remove in class '%S'.",
892 name, VTABLE_get_string(INTERP, SELF));
897 =item C<void add_vtable_override(STRING *name, PMC *sub)>
899 Adds the given sub PMC as a vtable override with the given name.
904 VTABLE void add_vtable_override(STRING *name, PMC *sub) {
905 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
907 VTABLE_get_pmc_keyed_str(INTERP, _class->vtable_overrides, name);
909 /* If we have already added a vtable override with this name... */
910 if (!PMC_IS_NULL(vtable)) {
914 Parrot_ex_throw_from_c_args(INTERP, NULL,
915 EXCEPTION_INVALID_OPERATION,
916 "A vtable override named '%S' already exists in class '%S'. "
917 "It may have been supplied by a role.",
918 name, VTABLE_get_string(INTERP, SELF));
921 /* Check that the name is actually valid as a vtable override */
922 if (Parrot_get_vtable_index(INTERP, name) == -1)
923 Parrot_ex_throw_from_c_args(INTERP, NULL,
924 EXCEPTION_METHOD_NOT_FOUND,
925 "'%S' is not a valid vtable function name.", name);
927 /* Add it to vtable list. */
928 VTABLE_set_pmc_keyed_str(INTERP, _class->vtable_overrides, name, sub);
933 =item C<void add_parent(PMC *parent)>
935 Adds the supplied PMC to the list of parents for the class.
940 VTABLE void add_parent(PMC *parent) {
941 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
942 int parent_count, index;
944 /* If we've been instantiated already, not allowed. */
945 if (_class->instantiated)
946 Parrot_ex_throw_from_c_args(INTERP, NULL,
947 EXCEPTION_INVALID_OPERATION,
948 "Modifications to classes are not allowed after instantiation.");
950 /* Ensure it really is a class. */
951 if (!PObj_is_class_TEST(parent))
952 Parrot_ex_throw_from_c_args(INTERP, NULL,
953 EXCEPTION_INVALID_OPERATION, "Parent isn't a Class.");
955 /* Check is not self */
957 Parrot_ex_throw_from_c_args(INTERP, NULL,
958 EXCEPTION_INVALID_OPERATION, "Can't be own parent");
960 /* get number of direct parents */
961 parent_count = VTABLE_elements(INTERP, _class->parents);
963 /* iterate over all direct parents, check whether this class already has
964 * the parent being added. */
965 for (index = 0; index < parent_count; ++index) {
966 /* get the next parent */
967 PMC * const current_parent = VTABLE_get_pmc_keyed_int(INTERP,
968 _class->parents, index);
970 /* throw an exception if we already have this parent */
971 if (current_parent == parent)
972 Parrot_ex_throw_from_c_args(INTERP, NULL,
973 EXCEPTION_INVALID_OPERATION,
974 "The class '%S' already has a parent class '%S'. "
975 "It may have been supplied by a role.",
976 VTABLE_get_string(INTERP, SELF),
977 VTABLE_get_string(INTERP, parent));
980 /* Check that none of the parents is self */
981 parent_count = VTABLE_elements(INTERP, PARROT_CLASS(parent)->all_parents);
983 for (index = 0; index < parent_count; ++index) {
984 /* get the next parent */
985 PMC * const current_parent = VTABLE_get_pmc_keyed_int(INTERP,
986 PARROT_CLASS(parent)->all_parents, index);
988 if (current_parent == SELF)
989 Parrot_ex_throw_from_c_args(INTERP, NULL,
990 EXCEPTION_INVALID_OPERATION,
991 "Loop in class hierarchy: '%S' is an ancestor of '%S'.",
992 VTABLE_get_string(INTERP, SELF),
993 VTABLE_get_string(INTERP, parent));
996 /* Add to the lists of our immediate parents and all parents. */
997 VTABLE_push_pmc(INTERP, _class->parents, parent);
998 parrot_hash_put(INTERP, _class->isa_cache, (void *)parent, (void *)1);
999 calculate_mro(INTERP, SELF, parent_count + 1);
1004 =item C<void remove_parent(PMC *parent)>
1006 Remove the supplied class object from the list of parents for the class.
1007 Throws an exception if parent is null, is not a class, or is not a parent, or
1008 if the class has been instantiated.
1013 VTABLE void remove_parent(PMC *parent) {
1014 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1015 int parent_count, index;
1017 /* If we've been instantiated already, not allowed. */
1018 if (_class->instantiated)
1019 Parrot_ex_throw_from_c_args(INTERP, NULL,
1020 EXCEPTION_INVALID_OPERATION,
1021 "Modifications to classes are not allowed after instantiation.");
1023 /* Ensure it really is a class. */
1024 if (!PObj_is_class_TEST(parent))
1025 Parrot_ex_throw_from_c_args(INTERP, NULL,
1026 EXCEPTION_INVALID_OPERATION, "Parent isn't a Class.");
1028 /* get number of direct parents */
1029 parent_count = VTABLE_elements(INTERP, _class->parents);
1031 /* iterate over all direct parents, looking for the parent to remove */
1032 for (index = 0; index < parent_count; ++index) {
1033 /* get the next parent */
1034 PMC * const current_parent = VTABLE_get_pmc_keyed_int(INTERP,
1035 _class->parents, index);
1036 if (current_parent == parent)
1040 if (index >= parent_count)
1041 Parrot_ex_throw_from_c_args(INTERP, NULL,
1042 EXCEPTION_INVALID_OPERATION,
1043 "Can't remove_parent: is not a parent.");
1045 VTABLE_delete_keyed_int(INTERP, _class->parents, index);
1046 parrot_hash_put(INTERP, _class->isa_cache, (void *)parent, (void *)0);
1047 calculate_mro(INTERP, SELF, parent_count - 1);
1052 =item C<void add_role(PMC *role)>
1054 Adds the supplied PMC to the list of roles for the class, provided there are
1060 VTABLE void add_role(PMC *role) {
1061 const Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1063 /* Do the composition. */
1064 Parrot_ComposeRole(INTERP, role,
1065 _class->resolve_method, !PMC_IS_NULL(_class->resolve_method),
1066 PMCNULL, 0, _class->methods, _class->roles);
1071 =item C<PMC *inspect_str(STRING *what)>
1073 Provides introspection of a specific piece of information about the class. The
1074 available information is:
1080 String PMC containing the name of the class
1084 NameSpace PMC of the the namespace attached to the class.
1088 Hash keyed on attribute name, where the value is a hash describing it.
1092 Hash keyed on method name, value is an invokable PMC. Includes methods composed
1097 Array of Role PMCs. Includes roles done by the roles that were composed into
1102 Array of Class PMCs representing the direct parents of this class.
1109 VTABLE PMC *inspect_str(STRING *what) {
1110 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1112 /* What should we return? */
1115 if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "attributes"))) {
1116 found = _class->attrib_metadata;
1118 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "parents"))) {
1119 found = _class->parents;
1121 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "name"))) {
1122 found = Parrot_pmc_new(INTERP, enum_class_String);
1123 VTABLE_set_string_native(INTERP, found, _class->name);
1125 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "id"))) {
1126 found = Parrot_pmc_new_init_int(INTERP, enum_class_Integer, _class->id);
1128 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "namespace"))) {
1129 /* Should not clone this. */
1130 return _class->_namespace;
1132 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "attrib_index"))) {
1133 found = _class->attrib_index;
1135 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "methods"))) {
1136 found = _class->methods;
1138 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "vtable_overrides"))) {
1139 found = _class->vtable_overrides;
1141 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "all_parents"))) {
1142 found = _class->all_parents;
1144 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "roles"))) {
1145 found = _class->roles;
1147 else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "flags"))) {
1148 found = Parrot_pmc_new_init_int(INTERP, enum_class_Integer,
1149 (INTVAL)PObj_get_FLAGS(SELF));
1152 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
1153 "Unknown introspection value '%S'", what);
1155 /* return found value */
1156 if (PMC_IS_NULL(found))
1159 if (found->vtable->base_type == enum_class_Hash) {
1160 /* for Hash return values, create and return a shallow
1161 * clone because the VTABLE_clone does a deep clone */
1162 PMC * const hash = Parrot_pmc_new(INTERP, enum_class_Hash);
1163 Hash *src = (Hash *)VTABLE_get_pointer(interp, found);
1164 Hash *dest = (Hash *)VTABLE_get_pointer(interp, hash);
1166 parrot_hash_clone_prunable(interp, src, dest, 0);
1171 return VTABLE_clone(INTERP, found);
1176 =item C<PMC *inspect()>
1178 Returns a Hash describing the class, with key/value pairs as described in
1184 VTABLE PMC *inspect() {
1185 /* Create a hash, then use inspect_str to get all of the data to
1186 * fill it up with. */
1187 PMC * const metadata = Parrot_pmc_new(INTERP, enum_class_Hash);
1188 STRING * const name_str = CONST_STRING(INTERP, "name");
1189 STRING * const ns_str = CONST_STRING(INTERP, "namespace");
1190 STRING * const attrs_str = CONST_STRING(INTERP, "attributes");
1191 STRING * const meths_str = CONST_STRING(INTERP, "methods");
1192 STRING * const parents_str = CONST_STRING(INTERP, "parents");
1193 STRING * const roles_str = CONST_STRING(INTERP, "roles");
1194 STRING * const flags_str = CONST_STRING(INTERP, "flags");
1196 VTABLE_set_pmc_keyed_str(INTERP, metadata, name_str,
1197 VTABLE_inspect_str(INTERP, SELF, name_str));
1199 VTABLE_set_pmc_keyed_str(INTERP, metadata, ns_str,
1200 VTABLE_inspect_str(INTERP, SELF, ns_str));
1202 VTABLE_set_pmc_keyed_str(INTERP, metadata, attrs_str,
1203 VTABLE_inspect_str(INTERP, SELF, attrs_str));
1205 VTABLE_set_pmc_keyed_str(INTERP, metadata, meths_str,
1206 VTABLE_inspect_str(INTERP, SELF, meths_str));
1208 VTABLE_set_pmc_keyed_str(INTERP, metadata, parents_str,
1209 VTABLE_inspect_str(INTERP, SELF, parents_str));
1211 VTABLE_set_pmc_keyed_str(INTERP, metadata, roles_str,
1212 VTABLE_inspect_str(INTERP, SELF, roles_str));
1214 VTABLE_set_pmc_keyed_str(INTERP, metadata, flags_str,
1215 VTABLE_inspect_str(INTERP, SELF, flags_str));
1222 =item C<PMC *clone()>
1224 Returns an anonymous copy of the class (with no name and no link to a
1225 namespace). Unsets the instantiated flag, allowing modifications.
1231 VTABLE PMC *clone() {
1232 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1234 /* Create the new class PMC, of the same type of this one (we may
1235 * have been subclassed). */
1236 PMC * const copy = SUPER();
1238 /* Clone parents, roles, methods, attributes and resolve data. We do
1239 * not copy name/namespace related stuff (need anonymous clone) or
1240 * stuff that gets computed on the first instantiation. */
1242 Parrot_Class_attributes * const new_class = PARROT_CLASS(copy);
1244 new_class->name = CONST_STRING(INTERP, "");
1245 new_class->_namespace = PMCNULL;
1246 new_class->parents = VTABLE_clone(INTERP, _class->parents);
1247 new_class->roles = VTABLE_clone(INTERP, _class->roles);
1248 new_class->methods = VTABLE_clone(INTERP, _class->methods);
1249 new_class->vtable_overrides = VTABLE_clone(INTERP,
1250 _class->vtable_overrides);
1251 new_class->parent_overrides = VTABLE_clone(INTERP,
1252 _class->parent_overrides);
1253 new_class->attrib_metadata = VTABLE_clone(INTERP,
1254 _class->attrib_metadata);
1255 new_class->resolve_method = VTABLE_clone(INTERP,
1256 _class->resolve_method);
1258 /* Return cloned class. */
1264 =item C<PMC *clone_pmc(PMC *args)>
1266 Makes a copy of the class, then modifies or adds to it based upon the contents
1267 of the supplied initialization data. If a new name or namespace is not supplied
1268 in C<args> then the cloned class will be anonymous. The instantiated flag is
1269 unset to allow further modifications.
1275 VTABLE PMC *clone_pmc(PMC *args) {
1276 /* Do the standard clone. */
1277 PMC * const copy = SELF.clone();
1279 init_class_from_hash(INTERP, copy, args);
1286 =item C<PMC *instantiate(PMC *init)>
1288 Creates a new PMC object of the type of the class and calls init().
1294 VTABLE PMC *instantiate(PMC *init) {
1295 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1298 /* If we've not been instantiated before... */
1299 if (!_class->instantiated) {
1300 /* Check that we have all methods listed in resolve list. */
1301 const int resolve_count = VTABLE_elements(INTERP,
1302 _class->resolve_method);
1303 const INTVAL cur_hll = Parrot_pcc_get_HLL(INTERP, CURRENT_CONTEXT(INTERP));
1304 const INTVAL num_parents = VTABLE_elements(INTERP, _class->parents);
1308 /* don't use HLL mappings for internal-only data */
1309 Parrot_pcc_set_HLL(INTERP, CURRENT_CONTEXT(INTERP), 0);
1311 for (i = 0; i < resolve_count; ++i) {
1312 STRING * const check_meth =
1313 VTABLE_get_string_keyed_int(INTERP, _class->resolve_method, i);
1314 if (!VTABLE_exists_keyed_str(INTERP, _class->methods, check_meth))
1315 Parrot_ex_throw_from_c_args(INTERP, NULL,
1316 EXCEPTION_METHOD_NOT_FOUND, "The method '%S' was named "
1317 "in the resolve list, but not supplied", check_meth);
1320 /* Build full parents list.
1321 * TT #1256: Need pluggable MRO, for now always do C3. */
1322 calculate_mro(INTERP, SELF, num_parents);
1323 build_attrib_index(INTERP, SELF);
1325 if (PMC_IS_NULL(_class->attrib_index))
1328 /* See if we have any parents from other universes and if so set a
1329 * flag stating so. */
1330 mro_length = VTABLE_elements(INTERP, _class->all_parents);
1332 for (i = 0; i < mro_length; ++i) {
1333 PMC * const class_check = VTABLE_get_pmc_keyed_int(INTERP,
1334 _class->all_parents, i);
1335 if (class_check->vtable->base_type != enum_class_Class) {
1336 /* Found one; that's enough. */
1337 CLASS_has_alien_parents_SET(SELF);
1342 Parrot_pcc_set_HLL(INTERP, CURRENT_CONTEXT(INTERP), cur_hll);
1345 /* Set instantiated flag. */
1346 _class->instantiated = 1;
1348 /* Create object. */
1349 object = Parrot_pmc_new_noinit(INTERP, enum_class_Object);
1351 /* Set custom GC mark and destroy on the object. */
1352 PObj_custom_mark_destroy_SETALL(object);
1354 /* Flag that it is an object */
1355 PObj_is_object_SET(object);
1357 /* Initialize the object's underlying structure, pointing it to this
1359 /* TODO: this has been changed in order to use auto_attrs in the
1360 * Object PMC. Needs to be redone in a cleaner way. */
1362 Parrot_Object_attributes * const objattr =
1363 PMC_data_typed(object, Parrot_Object_attributes *);
1364 objattr->_class = SELF;
1365 objattr->attrib_store = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
1368 if (!PMC_IS_NULL(init)) {
1369 /* Initialize attributes with the supplied values. */
1370 PMC * const iter = VTABLE_get_iter(INTERP, init);
1372 while (VTABLE_get_bool(INTERP, iter)) {
1373 STRING * const name = VTABLE_shift_string(INTERP, iter);
1374 PMC * const value = VTABLE_get_pmc_keyed_str(INTERP, init,
1377 /* Set the attribute. */
1378 VTABLE_set_attr_str(INTERP, object, name, value);
1381 /* Check for overrides on the init_pmc vtable function */
1382 initialize_parents_pmc(INTERP, object, _class->all_parents, init);
1385 /* Check for overrides on the init vtable function */
1386 initialize_parents(INTERP, object, _class->all_parents);
1394 =item C<INTVAL isa_pmc(PMC *class)>
1396 Returns whether the class is or inherits from C<*class>.
1402 VTABLE INTVAL isa_pmc(PMC *lookup) {
1403 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1406 INTVAL i, num_classes, retval = 0;
1408 if (PMC_IS_NULL(lookup))
1411 if (PObj_is_class_TEST(lookup)) {
1418 classobj = Parrot_oo_get_class(INTERP, lookup);
1420 if (PMC_IS_NULL(classobj))
1423 /* Check if the class object is the same as self's class object */
1424 if (VTABLE_is_same(INTERP, SELF, classobj))
1427 if (_class->instantiated) {
1428 b = parrot_hash_get_bucket(INTERP, _class->isa_cache,
1431 return (INTVAL)b->value;
1434 /* this is effectively what the default PMC's isa_pmc does
1435 * ... but this can cheat and avoid COW STRINGs for the classobj
1436 * only in these two, very specific and common cases */
1437 if (classobj->vtable->base_type == enum_class_Class
1438 || classobj->vtable->base_type == enum_class_PMCProxy) {
1439 STRING *classname = make_class_name(INTERP, classobj);
1440 PARROT_ASSERT(SELF->vtable->isa_hash);
1441 if (parrot_hash_exists(INTERP, SELF->vtable->isa_hash, classname))
1445 /* Iterate over all the parents and check if they respond true
1446 * for 'isa' on the original comparison. */
1447 num_classes = VTABLE_elements(INTERP, _class->parents);
1449 for (i = 0; i < num_classes; ++i) {
1450 PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP,
1451 _class->parents, i);
1453 if (VTABLE_isa_pmc(INTERP, cur_class, lookup))
1458 if (_class->instantiated)
1459 parrot_hash_put(INTERP, _class->isa_cache, (void *)classobj,
1465 goto cache_and_return;
1470 =item C<INTVAL isa(STRING *classname)>
1472 Returns whether the class is or inherits from C<*classname>.
1478 VTABLE INTVAL isa(STRING *classname) {
1481 /* hard-code this one exception right away */
1482 if (Parrot_str_equal(INTERP, classname, CONST_STRING(INTERP, "Class")))
1485 want_class = Parrot_oo_get_class_str(INTERP, classname);
1487 if (PMC_IS_NULL(want_class))
1490 if (SELF == want_class)
1493 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1495 INTVAL num_classes = VTABLE_elements(INTERP, _class->all_parents);
1498 for (i = 1; i < num_classes; ++i) {
1499 PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP,
1500 _class->all_parents, i);
1502 if (VTABLE_is_same(INTERP, want_class, cur_class))
1512 =item C<INTVAL does(STRING *role_name)>
1514 Returns whether the class does the role with the given C<*role_name>.
1519 VTABLE INTVAL does(STRING *role_name) {
1520 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1521 PMC * const role_list = _class->roles;
1527 count = VTABLE_elements(INTERP, role_list);
1529 for (i = 0; i < count; ++i) {
1530 PMC * const role = VTABLE_get_pmc_keyed_int(INTERP, role_list, i);
1532 if (VTABLE_does(INTERP, role, role_name))
1536 /* Iterate over all the parents and check if they respond true
1537 * for 'does' on the original comparison. */
1538 count = VTABLE_elements(INTERP, _class->parents);
1540 for (i = 0; i < count; ++i) {
1541 PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP,
1542 _class->parents, i);
1544 if (VTABLE_does(INTERP, cur_class, role_name))
1548 return VTABLE_isa(INTERP, SELF, role_name);
1553 =item C<INTVAL does_pmc(PMC *role)>
1555 Returns whether the class does the given C<*role>.
1560 VTABLE INTVAL does_pmc(PMC *role) {
1561 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1562 PMC * const role_list = _class->roles;
1563 INTVAL i, role_count, count;
1568 role_count = VTABLE_elements(INTERP, role_list);
1570 for (i = 0; i < role_count; ++i) {
1571 PMC * const test_role = VTABLE_get_pmc_keyed_int(INTERP, role_list, i);
1572 if (VTABLE_does_pmc(INTERP, test_role, role))
1576 /* Iterate over all the parents and check if they respond true
1577 * for 'does' on the original comparison. */
1578 count = VTABLE_elements(INTERP, _class->parents);
1580 for (i = 0; i < count; ++i) {
1581 PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP,
1582 _class->parents, i);
1584 if (VTABLE_does_pmc(INTERP, cur_class, role))
1588 return VTABLE_isa_pmc(INTERP, SELF, role);
1593 =item C<INTVAL type()>
1595 Returns the integer type of the class.
1601 VTABLE INTVAL type() {
1602 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1608 =item C<void visit(PMC *info)>
1610 This is used by freeze/thaw to visit the contents of the class.
1612 C<*info> is the visit info, (see F<include/parrot/pmc_freeze.h>).
1618 VTABLE void visit(PMC *info) {
1619 /* 1) visit the attribute description hash */
1620 VISIT_PMC_ATTR(INTERP, info, SELF, Class, attrib_metadata);
1622 /* 2) visit list of parents */
1623 VISIT_PMC_ATTR(INTERP, info, SELF, Class, parents);
1625 /* 3) visit list of roles */
1626 VISIT_PMC_ATTR(INTERP, info, SELF, Class, roles);
1628 /* 4) visit hash of methods */
1629 VISIT_PMC_ATTR(INTERP, info, SELF, Class, methods);
1631 /* 5) visit hash of vtable overrides */
1632 VISIT_PMC_ATTR(INTERP, info, SELF, Class, vtable_overrides);
1634 /* 6) visit list of resolve methods */
1635 VISIT_PMC_ATTR(INTERP, info, SELF, Class, resolve_method);
1640 =item C<void freeze(PMC *info)>
1642 Used to archive the class.
1648 VTABLE void freeze(PMC *info) {
1649 Parrot_Class_attributes * const class_data = PARROT_CLASS(SELF);
1650 STRING *serial_namespace = CONST_STRING(INTERP, "");
1652 /* 1) freeze class id */
1653 VTABLE_push_integer(INTERP, info, class_data->id);
1655 /* 2) freeze class name */
1656 VTABLE_push_string(INTERP, info, class_data->name);
1658 /* 3) serialize namespace name, including HLL */
1659 if (!PMC_IS_NULL(class_data->_namespace)) {
1660 PMC * const names = Parrot_ns_get_name(INTERP,
1661 class_data->_namespace);
1662 if (!PMC_IS_NULL(names))
1663 serial_namespace = Parrot_str_join(INTERP, CONST_STRING(INTERP, ";"), names);
1665 VTABLE_push_string(INTERP, info, serial_namespace);
1670 =item C<void thaw(PMC *info)>
1672 Used to unarchive the class.
1678 VTABLE void thaw(PMC *info) {
1679 /* The class might already exist in the interpreter, so create it as an
1680 * anonymous class and later decide whether to link it into the
1683 /* 1) thaw class id */
1684 const INTVAL id = VTABLE_shift_integer(INTERP, info);
1686 /* 2) thaw class name */
1687 STRING * const name = VTABLE_shift_string(INTERP, info);
1689 /* 3) deserialize namespace name, including HLL */
1690 STRING * const serial_namespace = VTABLE_shift_string(INTERP, info);
1691 STRING * const semicolon_str = CONST_STRING(INTERP, ";");
1692 PMC * const namespace_array =
1693 Parrot_str_split(INTERP, semicolon_str, serial_namespace);
1694 PMC *ns = Parrot_ns_get_namespace_keyed(INTERP,
1695 INTERP->root_namespace, namespace_array);
1697 /* If the namespace doesn't exist, we create it, and initialize
1698 * ourselves in it */
1699 if (PMC_IS_NULL(ns)) {
1700 ns = Parrot_ns_make_namespace_keyed(INTERP,
1701 INTERP->root_namespace, namespace_array);
1704 /* If the namespace exists already, we point to it, but otherwise
1705 * act as an anonymous class. */
1708 PARROT_CLASS(SELF)->_namespace = ns;
1711 /* Set the class's short name to the frozen name */
1712 PARROT_CLASS(SELF)->name = name;
1714 /* Set the class's id the frozen id */
1715 PARROT_CLASS(SELF)->id = id;
1720 =item C<INTVAL get_integer()>
1722 This is just a temporary hack. Type ID numbers shouldn't be externally
1723 visible to the average PIR user. However, we need this for now to interface
1724 with functions like Parrot_pmc_new and pmc_reuse, which take type ID numbers still.
1730 VTABLE INTVAL get_integer() {
1731 return PARROT_CLASS(SELF)->id;
1736 =item C<void thawfinish(PMC *info)>
1738 Called after the class has been thawed.
1744 VTABLE void thawfinish(PMC *info) {
1745 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1748 /* Recalculate full MRO from thawed parents */
1749 _class->all_parents = Parrot_ComputeMRO_C3(INTERP, SELF);
1750 _class->parent_overrides = Parrot_pmc_new(INTERP, enum_class_Hash);
1752 /* Rebuild attribute index from thawed attribute metadata */
1753 build_attrib_index(INTERP, SELF);
1756 /* **********************************************************************
1757 * Below here are methods that eventually will go in a role
1758 * that is composed into here to optionally give a nice interface from
1759 * PIR (ParrotClass isa Class does ClassMethods or something like this).
1760 * **********************************************************************/
1764 =item C<void name(STRING *name :optional, int has_name :opt_flag)>
1766 Sets the name of the class, and updates the namespace accordingly.
1771 METHOD name(STRING *name :optional, int has_name :opt_flag) {
1772 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1776 /* We'll build a hash just containing the name, then give this to
1777 * init_class_from_hash - saves some code duplication. */
1778 PMC * const naming_hash = Parrot_pmc_new(INTERP, enum_class_Hash);
1779 STRING * const name_str = CONST_STRING(INTERP, "name");
1781 VTABLE_set_string_keyed_str(INTERP, naming_hash, name_str, name);
1782 init_class_from_hash(INTERP, SELF, naming_hash);
1785 ret_name = _class->name;
1786 RETURN(STRING *ret_name);
1791 =item C<void get_namespace()>
1793 Gets the namespace that this class is attached to.
1798 METHOD get_namespace(PMC *_namespace :optional, int has_name :opt_flag) {
1799 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1800 PMC * const ret_namespace = _class->_namespace;
1803 RETURN(PMC *ret_namespace);
1808 =item C<void resolve_method()>
1810 Sets the list of method names that the class provides to resolve conflicts in
1811 methods from roles. When called with no parameter, returns the list.
1816 METHOD resolve_method(PMC *resolve_list :optional, int has_list :opt_flag) {
1817 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1822 _class->resolve_method = resolve_list;
1824 ret_list = _class->resolve_method;
1825 RETURN(PMC *ret_list);
1830 =item C<void new(PMC *args :slurpy :named)>
1832 Creates an instance of the object. Initializes any attributes specified in the
1838 METHOD new(PMC *args :slurpy :named) {
1839 /* Check if any arguments are in the slurpy hash, don't pass an empty
1840 * hash to instantiate */
1842 VTABLE_elements(INTERP, args) > 0
1843 ? VTABLE_instantiate(INTERP, SELF, args)
1844 : VTABLE_instantiate(INTERP, SELF, PMCNULL);
1851 =item C<void attributes()>
1853 Return a hash where the keys are attribute names and the values are hashes
1854 providing a set of key/value pairs describing the attribute.
1859 METHOD attributes() {
1860 STRING * const attr_str = CONST_STRING(INTERP, "attributes");
1861 PMC * const ret_attrib_metadata = SELF.inspect_str(attr_str);
1863 RETURN(PMC *ret_attrib_metadata);
1868 =item C<void add_attribute()>
1870 Add an attribute to the class. Requires a name and, optionally, a type.
1875 METHOD add_attribute(STRING *attribute_name,
1876 PMC *attribute_type :optional, int has_type :opt_flag) {
1877 PMC * const type = has_type ? attribute_type : PMCNULL;
1878 SELF.add_attribute(attribute_name, type);
1883 =item C<void methods()>
1885 Return a hash where the keys are method names and the values are methods.
1891 PMC * const ret_methods = SELF.inspect_str(CONST_STRING(INTERP, "methods"));
1893 RETURN(PMC *ret_methods);
1898 =item C<void add_method(STRING *name, PMC *sub)>
1900 Adds the given sub PMC as a method with the given name. Delegates to the
1901 C<add_method> vtable.
1906 METHOD add_method(STRING *name, PMC *sub) {
1907 SELF.add_method(name, sub);
1912 =item C<void add_vtable_override(STRING *name, PMC *sub)>
1914 Adds the given sub PMC as a vtable override with the given name. Delegates to
1915 the C<add_vtable_override> vtable.
1920 METHOD add_vtable_override(STRING *name, PMC *sub) {
1921 VTABLE_add_vtable_override(INTERP, SELF, name, sub);
1926 =item C<void remove_method(STRING *name)>
1928 Removes the method with the given name.
1933 METHOD remove_method(STRING *name) {
1934 VTABLE_remove_method(INTERP, SELF, name);
1939 =item C<PMC *find_method(STRING *name)>
1941 Walks the MRO of the class and finds the method with the given name.
1947 METHOD find_method(STRING *name) {
1948 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1951 /* Walk and search. One day, we'll use the cache first. */
1952 const int num_classes = VTABLE_elements(INTERP, _class->all_parents);
1954 for (i = 0; i < num_classes; ++i) {
1955 /* Get the class and see if it has the method. */
1956 PMC * const cur_class =
1957 VTABLE_get_pmc_keyed_int(INTERP, _class->all_parents, i);
1958 const Parrot_Class_attributes * const class_info = PARROT_CLASS(cur_class);
1961 if (VTABLE_exists_keyed_str(INTERP, class_info->methods, name)) {
1962 PMC * const ret = VTABLE_get_pmc_keyed_str(INTERP, class_info->methods, name);
1967 RETURN(PMC *PMCNULL);
1972 =item C<void parents()>
1974 Returns the parents array PMC.
1980 PMC * const ret_parents = SELF.inspect_str(CONST_STRING(INTERP, "parents"));
1982 RETURN(PMC *ret_parents);
1987 =item C<void add_parent(PMC *parent)>
1989 Adds the supplied PMC to the list of parents for the class.
1994 METHOD add_parent(PMC *parent) {
1995 SELF.add_parent(parent);
2000 =item C<void roles()>
2002 Returns the roles array PMC.
2008 PMC * const ret_roles = SELF.inspect_str(CONST_STRING(INTERP, "roles"));
2010 RETURN(PMC *ret_roles);
2015 =item C<void add_role(PMC *role, PMC *exclude :optional :named("exclude"),
2016 PMC *alias :optional :named("alias"))>
2018 Composes a role into a class with the given exclusions and aliases.
2023 METHOD add_role(PMC *role,
2024 PMC *exclude_method :optional :named("exclude_method"),
2025 int has_exclude_method :opt_flag,
2026 PMC *alias_method :optional :named("alias_method"),
2027 int has_alias_method :opt_flag) {
2029 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
2031 /* Add everything on the resolve list to the exclude list; if we have
2032 * no exclude list, pass along the resolve list in its place if it has
2033 * any methods listed in it. */
2034 if (!has_exclude_method) {
2035 if (VTABLE_elements(INTERP, _class->resolve_method) != 0) {
2036 exclude_method = _class->resolve_method;
2037 has_exclude_method = 1;
2041 const int resolve_count = VTABLE_elements(INTERP, _class->resolve_method);
2044 for (i = 0; i < resolve_count; ++i) {
2045 STRING * const meth_name = VTABLE_get_string_keyed_int(INTERP,
2046 _class->resolve_method, i);
2047 VTABLE_push_string(INTERP, exclude_method, meth_name);
2051 /* Do the composition. */
2052 Parrot_ComposeRole(INTERP, role, exclude_method, has_exclude_method,
2053 alias_method, has_alias_method,
2054 _class->methods, _class->roles);
2059 =item C<void inspect(STRING *what :optional)>
2061 Gets all introspection data for the class or, if the optional string
2062 parameter is supplied, a particular item of introspection data.
2067 METHOD inspect(STRING *what :optional, int has_what :opt_flag) {
2070 /* Just delegate to the appropriate vtable. */
2072 found = SELF.inspect_str(what);
2074 found = SELF.inspect();
2081 =item C<void isa(STRING *class_name)>
2083 Returns true if this object is or derives from the class named in
2084 C<class_name>, false otherwise.
2089 METHOD isa(STRING *class_name) {
2090 const INTVAL isa = SELF.isa(class_name);
2097 =item C<void does(STRING *role_name)>
2099 Returns true if this object or one of its parents performs the named role,
2105 METHOD does(STRING *role_name) {
2106 const INTVAL does = VTABLE_does(INTERP, SELF, role_name);
2107 RETURN(INTVAL does);
2110 METHOD clear_method_cache() {
2111 Parrot_Class_attributes * const attrs = PARROT_CLASS(SELF);
2112 PMC * const cache = attrs->meth_cache;
2114 attrs->meth_cache = PMCNULL;
2117 METHOD get_method_cache() {
2118 Parrot_Class_attributes * const attrs = PARROT_CLASS(SELF);
2119 PMC * cache = attrs->meth_cache;
2121 cache = Parrot_pmc_new(INTERP, enum_class_Hash);
2122 attrs->meth_cache = cache;
2135 F<docs/pdds/pdd15_objects.pod>.
2143 * c-file-style: "parrot"
2145 * vim: expandtab shiftwidth=4: