1/* 2Copyright (C) 2001-2014, Parrot Foundation. 3 4=head1 NAME 5 6src/pmc/class.pmc - Class PMC 7 8=head1 DESCRIPTION 9 10This class implements the Class PMC, as outlined in 11F<docs/pdds/pdd15_objects.pod>. 12 13Class is not derived from any other PMC. 14 15=head2 Structure 16 17The Class PMC structure (C<Parrot_Class>) consists of twelve items: 18 19=over 4 20 21=item C<id> 22 23The type number of the PMC. 24 25=item C<name> 26 27The name of the class -- a STRING. 28An empty STRING is allocated during initialization. 29 30=item C<namespace> 31 32The namespace the class is associated with, if any. 33A Null PMC is allocated during initialization. 34 35=item C<instantiated> 36 37A flag denoting whether this class has been instantiated since last 38modification. A native integer with value zero is allocated during 39initialization. 40 41=item C<parents> 42 43An array of immediate parent classes. 44An empty ResizablePMCArray PMC is allocated during initialization. 45 46=item C<all_parents> 47 48A cached array of ourself and all parent classes, in method resolution 49order (MRO). A ResizablePMCArray PMC is allocated during initialization, 50and is populated with the current class. 51 52=item C<roles> 53 54An array of the roles this class has been composed from. 55An empty ResizablePMCArray PMC is allocated during initialization. 56 57=item C<methods> 58 59A directory of method names and method bodies this class provides. 60An empty Hash PMC is allocated during initialization. 61 62=item C<vtable_overrides> 63 64A directory of vtable function names and method bodies this class overrides. 65An empty Hash PMC is allocated during initialization. 66 67=item C<attrib_metadata> 68 69A directory of attribute names and attribute metadata this class contains. 70An empty Hash PMC is allocated during initialization. 71 72=item C<attrib_index> 73 74A lookup table for attributes in this class and parents. 75A Null PMC is allocated during initialization. 76 77=item C<attrib_cache> 78 79A cache of visible attribute names to attribute indexes. 80A Null PMC is allocated during initialization. 81 82=item C<resolve_method> 83 84A list of method names the class provides used for name conflict resolution. 85An empty ResizablePMCArray PMC is allocated during initialization. 86 87=cut 88 89*/ 90 91#include "parrot/oo_private.h" 92#include "pmc/pmc_object.h" 93#include "pmc/pmc_namespace.h" 94 95/* HEADERIZER HFILE: none */ 96/* HEADERIZER BEGIN: static */ 97/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ 98 99static void build_attrib_index(PARROT_INTERP, ARGIN(PMC *self)) 100 __attribute__nonnull__(1) 101 __attribute__nonnull__(2); 102 103static int cache_class_attribs(PARROT_INTERP, 104 ARGIN(PMC *cur_class), 105 ARGIN(PMC *attrib_index), 106 ARGIN(PMC *cache), 107 int cur_index) 108 __attribute__nonnull__(1) 109 __attribute__nonnull__(2) 110 __attribute__nonnull__(3) 111 __attribute__nonnull__(4); 112 113static void calculate_mro(PARROT_INTERP, 114 ARGIN(PMC *SELF), 115 INTVAL num_parents) 116 __attribute__nonnull__(1) 117 __attribute__nonnull__(2); 118 119static void init_class_from_hash(PARROT_INTERP, 120 ARGMOD(PMC *self), 121 ARGIN_NULLOK(PMC *info)) 122 __attribute__nonnull__(1) 123 __attribute__nonnull__(2) 124 FUNC_MODIFIES(*self); 125 126static void initialize_parents(PARROT_INTERP, 127 ARGIN(PMC *object), 128 ARGIN(PMC *all_parents)) 129 __attribute__nonnull__(1) 130 __attribute__nonnull__(2) 131 __attribute__nonnull__(3); 132 133static void initialize_parents_pmc(PARROT_INTERP, 134 ARGIN(PMC *object), 135 ARGIN(PMC *all_parents), 136 ARGIN(PMC *init)) 137 __attribute__nonnull__(1) 138 __attribute__nonnull__(2) 139 __attribute__nonnull__(3) 140 __attribute__nonnull__(4); 141 142PARROT_CANNOT_RETURN_NULL 143static STRING * make_class_name(PARROT_INTERP, ARGIN(PMC *SELF)) 144 __attribute__nonnull__(1) 145 __attribute__nonnull__(2); 146 147#define ASSERT_ARGS_build_attrib_index __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 148 PARROT_ASSERT_ARG(interp) \ 149 , PARROT_ASSERT_ARG(self)) 150#define ASSERT_ARGS_cache_class_attribs __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 151 PARROT_ASSERT_ARG(interp) \ 152 , PARROT_ASSERT_ARG(cur_class) \ 153 , PARROT_ASSERT_ARG(attrib_index) \ 154 , PARROT_ASSERT_ARG(cache)) 155#define ASSERT_ARGS_calculate_mro __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 156 PARROT_ASSERT_ARG(interp) \ 157 , PARROT_ASSERT_ARG(SELF)) 158#define ASSERT_ARGS_init_class_from_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 159 PARROT_ASSERT_ARG(interp) \ 160 , PARROT_ASSERT_ARG(self)) 161#define ASSERT_ARGS_initialize_parents __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 162 PARROT_ASSERT_ARG(interp) \ 163 , PARROT_ASSERT_ARG(object) \ 164 , PARROT_ASSERT_ARG(all_parents)) 165#define ASSERT_ARGS_initialize_parents_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 166 PARROT_ASSERT_ARG(interp) \ 167 , PARROT_ASSERT_ARG(object) \ 168 , PARROT_ASSERT_ARG(all_parents) \ 169 , PARROT_ASSERT_ARG(init)) 170#define ASSERT_ARGS_make_class_name __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 171 PARROT_ASSERT_ARG(interp) \ 172 , PARROT_ASSERT_ARG(SELF)) 173/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ 174/* HEADERIZER END: static */ 175 176/* 177 178=item C<static int cache_class_attribs(PARROT_INTERP, PMC *cur_class, PMC 179*attrib_index, PMC *cache, int cur_index)> 180 181Create a cached map of all attributes (including those inherited from parent 182types), where the name of each attribute is mapped to an integer index into 183a storage array. 184 185=cut 186 187*/ 188 189static int 190cache_class_attribs(PARROT_INTERP, 191 ARGIN(PMC *cur_class), ARGIN(PMC *attrib_index), 192 ARGIN(PMC *cache), int cur_index) 193{ 194 ASSERT_ARGS(cache_class_attribs) 195 /* The attribute metadata hash. */ 196 Parrot_Class_attributes * const class_info = PARROT_CLASS(cur_class); 197 PMC * const attribs = class_info->attrib_metadata; 198 PMC * const iter = VTABLE_get_iter(interp, attribs); 199 200 /* Build a string representing the fully qualified class name. */ 201 /* Retrieve the fully qualified class name for the class. */ 202 STRING * const fq_class = VTABLE_get_string(interp, cur_class); 203 PMC * const class_cache = Parrot_pmc_new(interp, enum_class_Hash); 204 VTABLE_set_pmc_keyed_str(interp, cache, fq_class, class_cache); 205 206 /* Iterate over the attributes. */ 207 while (VTABLE_get_bool(interp, iter)) { 208 /* Get attribute. */ 209 PMC * const cur_attrib = VTABLE_get_pmc_keyed_str(interp, 210 attribs, VTABLE_shift_string(interp, iter)); 211 212 /* Get attribute name and append it to the key. */ 213 STRING * const name_str = CONST_STRING(interp, "name"); 214 STRING * const attrib_name = VTABLE_get_string_keyed_str( 215 interp, cur_attrib, name_str); 216 217 STRING * const full_key = Parrot_str_concat(interp, fq_class, attrib_name); 218 219 /* Insert into hash, along with index. */ 220 VTABLE_set_integer_keyed_str(interp, attrib_index, full_key, cur_index); 221 VTABLE_set_integer_keyed_str(interp, class_cache, attrib_name, cur_index); 222 ++cur_index; 223 } 224 225 return cur_index; 226} 227 228/* 229 230=item C<static void build_attrib_index(PARROT_INTERP, PMC *self)> 231 232This function builds the attribute index (table to map class name and 233attribute name to an index) for the current class. 234 235=cut 236 237*/ 238 239static void 240build_attrib_index(PARROT_INTERP, ARGIN(PMC *self)) 241{ 242 ASSERT_ARGS(build_attrib_index) 243 Parrot_Class_attributes * const _class = PARROT_CLASS(self); 244 int cur_index = 0; 245 PMC * const attrib_index = Parrot_pmc_new(interp, enum_class_Hash); 246 PMC * const cache = Parrot_pmc_new_init_int(interp, 247 enum_class_Hash, enum_type_INTVAL); 248 const int num_classes = VTABLE_elements(interp, _class->all_parents); 249 int i; 250 251 /* Go over the list of all parents to construct the attribute index. */ 252 for (i = 0; i < num_classes; ++i) { 253 /* Get the class and check that it respects the standard class interface 254 * (if not we don't know how it stores its attributes, so we'll have to 255 * delegate the lookup). */ 256 PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp, 257 _class->all_parents, i); 258 259 if (PObj_is_class_TEST(cur_class)) 260 cur_index = cache_class_attribs(interp, cur_class, 261 attrib_index, cache, cur_index); 262 } 263 264 /* Store built attribute index and invalidate cache. */ 265 _class->attrib_index = attrib_index; 266 _class->attrib_cache = cache; 267 268 PARROT_GC_WRITE_BARRIER(interp, self); 269} 270 271/* 272 273=item C<static void init_class_from_hash(PARROT_INTERP, PMC *self, PMC *info)> 274 275Takes a hash and initializes the class based on it. 276 277=cut 278 279*/ 280 281static void 282init_class_from_hash(PARROT_INTERP, ARGMOD(PMC *self), ARGIN_NULLOK(PMC *info)) 283{ 284 ASSERT_ARGS(init_class_from_hash) 285 Parrot_Class_attributes * const _class = PARROT_CLASS(self); 286 STRING * const name_str = CONST_STRING(interp, "name"); 287 STRING * const parents_str = CONST_STRING(interp, "parents"); 288 STRING * const methods_str = CONST_STRING(interp, "methods"); 289 STRING * const roles_str = CONST_STRING(interp, "roles"); 290 STRING * const attrs_str = CONST_STRING(interp, "attributes"); 291 STRING * const resolve_method_str = CONST_STRING(interp, "resolve_method"); 292 STRING * const set_class_str = CONST_STRING(interp, "set_class"); 293 PMC *old_ns; 294 295 /* Ensure we actually have some initialization info. */ 296 if (PMC_IS_NULL(info)) 297 return; 298 299 /* Take a copy of the current namespace the class is attached to. */ 300 old_ns = _class->_namespace; 301 302 /* Check if we have a name/namespace. */ 303 if (VTABLE_exists_keyed_str(interp, info, name_str)) { 304 STRING *new_name; 305 PMC *new_namespace; 306 PMC *name_arg = VTABLE_get_pmc_keyed_str(interp, info, name_str); 307 VTABLE *new_vtable; 308 INTVAL type_num; 309 310 /* If we were passed a namespace PMC, set the namespace attribute 311 * directly. Otherwise, lookup or create the appropriate namespace. */ 312 if (name_arg->vtable->base_type == enum_class_NameSpace) { 313 new_namespace = name_arg; 314 name_arg = Parrot_ns_get_name(interp, new_namespace); 315 VTABLE_shift_string(interp, name_arg); 316 } 317 else { 318 PMC * const hll_ns = VTABLE_get_pmc_keyed_int(interp, 319 interp->HLL_namespace, Parrot_pcc_get_HLL(interp, CURRENT_CONTEXT(interp))); 320 new_namespace = Parrot_ns_make_namespace_keyed(interp, hll_ns, name_arg); 321 } 322 323 if (PMC_IS_NULL(new_namespace)) 324 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_INVALID_OPERATION, 325 "Failed to set namespace for class"); 326 327 /* Set the name of the class to the name of the innermost namespace 328 * associated with the class. */ 329 new_name = VTABLE_get_string(interp, new_namespace); 330 331 if (STRING_IS_NULL(new_name) || STRING_IS_EMPTY(new_name)) 332 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_INVALID_OPERATION, 333 "Failed to set name for class"); 334 335 _class->_namespace = new_namespace; 336 _class->name = new_name; 337 338 /* At this point we know the class isn't anonymous */ 339 CLASS_is_anon_CLEAR(self); 340 341 /* Register a type number for the class. */ 342 type_num = Parrot_oo_register_type(interp, name_arg, new_namespace); 343 344 /* Link the type number with the class's vtable. */ 345 new_vtable = Parrot_vtbl_clone_vtable(interp, self->vtable); 346 347 new_vtable->base_type = type_num; 348 new_vtable->pmc_class = self; 349 new_vtable->whoami = VTABLE_get_string(interp, self); 350 new_vtable->mro = _class->all_parents; 351 new_vtable->ro_variant_vtable = 352 Parrot_vtbl_clone_vtable(interp, self->vtable->ro_variant_vtable); 353 354 /* Store the class's vtable in the global table */ 355 interp->vtables[type_num] = new_vtable; 356 357 _class->id = type_num; 358 } 359 360 /* If we were attached to a namespace and are now attached to a new one, 361 * need to unset ourselves in the old namespace. */ 362 if (!PMC_IS_NULL(old_ns) && _class->_namespace != old_ns) 363 Parrot_pcc_invoke_method_from_c_args(interp, old_ns, 364 set_class_str, 365 "P->", PMCNULL); 366 367 /* Link namespace to this class, if there is one. */ 368 if (!PMC_IS_NULL(_class->_namespace)) { 369 Parrot_pcc_invoke_method_from_c_args(interp, _class->_namespace, 370 set_class_str, 371 "P->", self); 372 } 373 374 /* Initialize resolve_method. */ 375 if (VTABLE_exists_keyed_str(interp, info, resolve_method_str)) { 376 /* Set it. */ 377 _class->resolve_method = 378 VTABLE_get_pmc_keyed_str(interp, info, resolve_method_str); 379 } 380 381 /* Initialize parents, if we have any. */ 382 if (VTABLE_exists_keyed_str(interp, info, parents_str)) { 383 /* Loop over parents array and add them. */ 384 PMC * const parent_list = VTABLE_get_pmc_keyed_str(interp, info, 385 parents_str); 386 const int parent_count = VTABLE_elements(interp, parent_list); 387 int i; 388 389 for (i = 0; i < parent_count; ++i) 390 VTABLE_add_parent(interp, self, 391 VTABLE_get_pmc_keyed_int(interp, parent_list, i)); 392 } 393 394 /* Initialize roles, if we have any. */ 395 if (VTABLE_exists_keyed_str(interp, info, roles_str)) { 396 /* Loop over roles array and compose them. */ 397 PMC * const role_list = VTABLE_get_pmc_keyed_str(interp, info, 398 roles_str); 399 const int role_count = VTABLE_elements(interp, role_list); 400 int i; 401 402 for (i = 0; i < role_count; ++i) 403 VTABLE_add_role(interp, self, 404 VTABLE_get_pmc_keyed_int(interp, role_list, i)); 405 } 406 407 /* Initialize attributes, if we have any. */ 408 if (VTABLE_exists_keyed_str(interp, info, attrs_str)) { 409 /* Loop over attributes array and add them. */ 410 PMC * const attrs_name_list = VTABLE_get_pmc_keyed_str(interp, info, 411 attrs_str); 412 const int attrib_count = VTABLE_elements(interp, attrs_name_list); 413 int i; 414 415 for (i = 0; i < attrib_count; ++i) { 416 STRING * const attr_name = VTABLE_get_string_keyed_int(interp, 417 attrs_name_list, i); 418 VTABLE_add_attribute(interp, self, attr_name, PMCNULL); 419 } 420 } 421 422 /* Initialize methods. */ 423 if (VTABLE_exists_keyed_str(interp, info, methods_str)) { 424 /* Get the methods hash. */ 425 PMC * const methods = VTABLE_get_pmc_keyed_str(interp, info, 426 methods_str); 427 428 /* Iterate over the list of methods. */ 429 PMC * const iter = VTABLE_get_iter(interp, methods); 430 431 while (VTABLE_get_bool(interp, iter)) { 432 /* Add the method. */ 433 STRING * const method_name = VTABLE_shift_string(interp, iter); 434 PMC * const method_pmc = VTABLE_get_pmc_keyed_str(interp, 435 methods, method_name); 436 VTABLE_add_method(interp, self, method_name, method_pmc); 437 } 438 } 439 440 /* Extract any methods from the namespace */ 441 Parrot_oo_extract_methods_from_namespace(interp, self, _class->_namespace); 442} 443 444/* 445 446=item C<static void initialize_parents(PARROT_INTERP, PMC *object, PMC 447*all_parents)> 448 449Loop over all parents in the MRO, setting up delegate objects if necessary and 450calling C<init> vtables on them, if necessary. 451 452=cut 453 454*/ 455 456static void 457initialize_parents(PARROT_INTERP, ARGIN(PMC *object), ARGIN(PMC *all_parents)) 458{ 459 ASSERT_ARGS(initialize_parents) 460 INTVAL parent_index = VTABLE_elements(interp, all_parents) - 1; 461 STRING * const name = CONST_STRING(interp, "init"); 462 463 /* Loop through the parents in reverse MRO order. */ 464 for (; parent_index >= 0; --parent_index) { 465 PMC *meth; 466 PMC * const parent = VTABLE_get_pmc_keyed_int(interp, 467 all_parents, parent_index); 468 469 /* PMCProxy parents store an instance to delegate to */ 470 if (parent->vtable->base_type == enum_class_PMCProxy) { 471 PMC *proxy = VTABLE_instantiate(interp, parent, PMCNULL); 472 STRING *proxy_str = CONST_STRING(interp, "proxy"); 473 VTABLE_set_attr_keyed(interp, object, parent, proxy_str, proxy); 474 } 475 476 meth = Parrot_oo_find_vtable_override_for_class(interp, parent, name); 477 478 if (!PMC_IS_NULL(meth)) { 479 /* preserve current_object */ 480 Parrot_ext_call(interp, meth, "Pi->", object); 481 } 482 } 483} 484 485/* 486 487=item C<static void initialize_parents_pmc(PARROT_INTERP, PMC *object, PMC 488*all_parents, PMC *init)> 489 490Loop over all parents in the MRO, setting up delegate objects if necessary and 491calling C<init_pmc> vtables on them, if necessary. 492 493=cut 494 495*/ 496 497static void 498initialize_parents_pmc(PARROT_INTERP, ARGIN(PMC *object), 499 ARGIN(PMC *all_parents), ARGIN(PMC *init)) 500{ 501 ASSERT_ARGS(initialize_parents_pmc) 502 INTVAL parent_index = VTABLE_elements(interp, all_parents) - 1; 503 STRING * const name = CONST_STRING(interp, "init_pmc"); 504 505 /* Loop through the parents in reverse MRO order. */ 506 for (; parent_index >= 0; --parent_index) { 507 PMC *meth; 508 PMC * const parent = VTABLE_get_pmc_keyed_int(interp, 509 all_parents, parent_index); 510 511 /* PMCProxy parents store an instance to delegate to */ 512 if (parent->vtable->base_type == enum_class_PMCProxy) { 513 PMC * const proxy = VTABLE_instantiate(interp, parent, init); 514 STRING * const proxy_str = CONST_STRING(interp, "proxy"); 515 VTABLE_set_attr_keyed(interp, object, parent, proxy_str, proxy); 516 } 517 518 meth = Parrot_oo_find_vtable_override_for_class(interp, parent, name); 519 520 if (!PMC_IS_NULL(meth)) 521 Parrot_ext_call(interp, meth, "PiP->", object, init); 522 } 523} 524 525/* 526 527=item C<static STRING * make_class_name(PARROT_INTERP, PMC *SELF)> 528 529This function makes and caches the name of this class, returning the string 530directly. C<VTABLE_isa()> uses the name without copying it, for efficiency 531reasons, as it does not modify the STRING. C<VTABLE_get_string()> makes a 532copy of the STRING, so its callers are free to modify it. 533 534=cut 535 536*/ 537 538PARROT_CANNOT_RETURN_NULL 539static STRING * 540make_class_name(PARROT_INTERP, ARGIN(PMC *SELF)) 541{ 542 ASSERT_ARGS(make_class_name) 543 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 544 PMC * const _namespace = _class->_namespace; 545 546 if (!PMC_IS_NULL(_namespace)) { 547 if (_class->fullname) 548 return _class->fullname; 549 else { 550 551 /* Call the 'get_name' method on the class's associated 552 * namespace to retrieve a fully qualified list of names, then 553 * join the list with a semicolon. */ 554 PMC * const names = Parrot_ns_get_name(interp, _namespace); 555 556 if (!PMC_IS_NULL(names)) 557 /* remove the HLL namespace name */ 558 VTABLE_shift_string(interp, names); 559 PARROT_GC_WRITE_BARRIER(interp, SELF); 560 _class->fullname = Parrot_str_join(interp, CONST_STRING(interp, ";"), names); 561 return _class->fullname; 562 } 563 } 564 565 /* Otherwise, copy the stored string name of the class. */ 566 return _class->name; 567} 568 569/* 570 571=item C<static void calculate_mro(PARROT_INTERP, PMC *SELF, INTVAL num_parents)> 572 573Calculates the C3 method resolution order for this class. C3 is the name of an 574algorithm used to calculate the method resolution order (MRO) to use in a 575system with multiple inheritance. For more information see the documentation 576associated with C<Parrot_ComputeMRO_C3>. 577 578=cut 579 580*/ 581 582static void 583calculate_mro(PARROT_INTERP, ARGIN(PMC *SELF), INTVAL num_parents) 584{ 585 ASSERT_ARGS(calculate_mro) 586 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 587 588 /* SELF is already on the all_parents */ 589 if (num_parents == 0) 590 return; 591 592 if (num_parents == 1) { 593 STRING * const ap = CONST_STRING(interp, "all_parents"); 594 PMC * const parent = VTABLE_get_pmc_keyed_int(interp, 595 _class->parents, 0); 596 PMC * const parent_mro = VTABLE_inspect_str(interp, parent, ap); 597 PMC * const mro = VTABLE_clone(interp, parent_mro); 598 VTABLE_unshift_pmc(interp, mro, SELF); 599 PARROT_GC_WRITE_BARRIER(interp, SELF); 600 _class->all_parents = mro; 601 } 602 else { 603 PARROT_GC_WRITE_BARRIER(interp, SELF); 604 _class->all_parents = Parrot_ComputeMRO_C3(interp, SELF); 605 } 606 607 if (!CLASS_is_anon_TEST(SELF)) 608 interp->vtables[VTABLE_type(interp, SELF)]->mro = _class->all_parents; 609} 610 611/* 612 613=back 614 615=head2 Functions 616 617=over 4 618 619=cut 620 621*/ 622 623pmclass Class auto_attrs { 624 625 ATTR INTVAL id; /* The type number of the PMC. */ 626 ATTR STRING *name; /* The name of the class. */ 627 ATTR STRING *fullname; /* The name of the class. */ 628 ATTR PMC *_namespace; /* The namespace it's linked to, if any. */ 629 ATTR INTVAL instantiated; /* Any instantiations since last modification? */ 630 ATTR PMC *parents; /* Immediate parent classes. */ 631 ATTR PMC *all_parents; /* Cached list of ourself and all parents, in MRO order. */ 632 ATTR PMC *roles; /* An array of roles. */ 633 ATTR PMC *methods; /* Hash of method names to methods in this class. */ 634 ATTR PMC *vtable_overrides; /* Hash of Parrot v-table methods we override. */ 635 ATTR PMC *attrib_metadata; /* Hash of attributes in this class to hashes of metadata. */ 636 ATTR PMC *attrib_index; /* Lookup table for attributes in this and parents. */ 637 ATTR PMC *attrib_cache; /* Cache of visible attrib names to indexes. */ 638 ATTR PMC *resolve_method; /* List of method names the class provides to resolve 639 * conflicts with methods from roles. */ 640 ATTR PMC *parent_overrides; 641 ATTR PMC *meth_cache; 642 ATTR Hash *isa_cache; 643 644/* 645 646=item C<void init()> 647 648Initializes a Class PMC. 649 650=item C<void init_pmc(PMC *init_data)> 651 652The actual class creation code, called from C<newclass> opcode. The C<init_data> 653argument may be either the name of the class or a hash of initialization 654arguments. The class is attached to the current HLL namespace. 655 656=cut 657 658*/ 659 660 VTABLE void init() { 661 Parrot_Class_attributes * const _class = 662 (Parrot_Class_attributes *) PMC_data(SELF); 663 664 /* Set flag for custom GC mark. */ 665 PObj_custom_mark_destroy_SETALL(SELF); 666 667 /* Set up the object. */ 668 _class->name = CONST_STRING(INTERP, ""); 669 _class->_namespace = PMCNULL; 670 _class->parents = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray); 671 _class->all_parents = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray); 672 _class->roles = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray); 673 _class->methods = Parrot_pmc_new(INTERP, enum_class_Hash); 674 _class->attrib_metadata = Parrot_pmc_new(INTERP, enum_class_Hash); 675 _class->attrib_index = PMCNULL; 676 _class->attrib_cache = PMCNULL; 677 _class->meth_cache = PMCNULL; 678 _class->resolve_method = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray); 679 680 _class->vtable_overrides = Parrot_pmc_new(INTERP, enum_class_Hash); 681 _class->parent_overrides = Parrot_pmc_new(INTERP, enum_class_Hash); 682 683 _class->isa_cache = Parrot_hash_create(INTERP, 684 enum_type_INTVAL, Hash_key_type_PMC_ptr); 685 686 687 /* We put ourself on the all parents list. */ 688 VTABLE_push_pmc(INTERP, _class->all_parents, SELF); 689 690 /* We are a class. */ 691 PObj_is_class_SET(SELF); 692 693 /* By default we're anonymous. */ 694 CLASS_is_anon_SET(SELF); 695 } 696 697 VTABLE void init_pmc(PMC *init_data) { 698 PMC *arg; 699 const INTVAL arg_type = VTABLE_type(INTERP, init_data); 700 STRING * const name_str = CONST_STRING(INTERP, "name"); 701 702 /* Set up the object. */ 703 SELF.init(); 704 705 /* fast attempt to determine init_data type */ 706 switch (arg_type) { 707 case enum_class_String: 708 case enum_class_Key: 709 case enum_class_ResizableStringArray: 710 case enum_class_NameSpace: 711 /* set only the name property */ 712 arg = Parrot_pmc_new(INTERP, enum_class_Hash); 713 VTABLE_set_pmc_keyed_str(INTERP, arg, name_str, init_data); 714 break; 715 716 case enum_class_Hash: 717 arg = init_data; 718 break; 719 720 /* slow attempt to determine init_data type */ 721 default: 722 if (VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "String")) 723 || VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "Key")) 724 || VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "ResizableStringArray"))) { 725 /* set only the name property */ 726 arg = Parrot_pmc_new(INTERP, enum_class_Hash); 727 VTABLE_set_pmc_keyed_str(INTERP, arg, name_str, init_data); 728 } 729 730 if (VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "Hash"))) 731 arg = init_data; 732 else 733 Parrot_ex_throw_from_c_noargs(INTERP, 734 EXCEPTION_INVALID_OPERATION, 735 "Invalid class name key in init_pmc for Class"); 736 break; 737 } 738 739 /* Initialize the class with the supplied data. */ 740 init_class_from_hash(INTERP, SELF, arg); 741 } 742 743 void destroy() { 744 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 745 Parrot_hash_destroy(INTERP, _class->isa_cache); 746 } 747 748/* 749 750=item C<STRING *get_string()> 751 752Returns the name of the class (without the HLL namespace). 753 754=cut 755 756*/ 757 758 VTABLE STRING *get_string() :no_wb { 759 return make_class_name(INTERP, SELF); 760 } 761 762/* 763 764=item C<void mark()> 765 766Marks any referenced strings and PMCs in the structure as live. 767 768=cut 769 770*/ 771 772 VTABLE void mark() :no_wb { 773 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 774 Parrot_gc_mark_STRING_alive(INTERP, _class->name); 775 Parrot_gc_mark_STRING_alive(INTERP, _class->fullname); 776 Parrot_gc_mark_PMC_alive(INTERP, _class->_namespace); 777 Parrot_gc_mark_PMC_alive(INTERP, _class->parents); 778 Parrot_gc_mark_PMC_alive(INTERP, _class->all_parents); 779 Parrot_gc_mark_PMC_alive(INTERP, _class->roles); 780 Parrot_gc_mark_PMC_alive(INTERP, _class->methods); 781 Parrot_gc_mark_PMC_alive(INTERP, _class->vtable_overrides); 782 Parrot_gc_mark_PMC_alive(INTERP, _class->parent_overrides); 783 Parrot_gc_mark_PMC_alive(INTERP, _class->attrib_metadata); 784 Parrot_gc_mark_PMC_alive(INTERP, _class->attrib_index); 785 Parrot_gc_mark_PMC_alive(INTERP, _class->attrib_cache); 786 Parrot_gc_mark_PMC_alive(INTERP, _class->resolve_method); 787 Parrot_gc_mark_PMC_alive(INTERP, _class->meth_cache); 788 if (_class->isa_cache) 789 Parrot_hash_mark(INTERP, _class->isa_cache); 790 } 791 792 793/* 794 795=item C<void add_attribute(STRING *name, PMC *type)> 796 797Adds the given attribute (C<name>) with an optional C<type>. 798Throws an exception if the current class has been instantiated. 799Enters the attribute in the C<attrib_metadata> table. 800Returns an error if an attribute of C<name> already exists. 801 802=cut 803 804*/ 805 806 VTABLE void add_attribute(STRING *name, PMC *type) { 807 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 808 PMC * const new_attribute = Parrot_pmc_new(INTERP, enum_class_Hash); 809 810 /* If we've been instantiated already, not allowed. */ 811 if (_class->instantiated) 812 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION, 813 "Modifications to classes are not allowed after instantiation"); 814 815 /* If we already have an attribute of this name, it's an error. */ 816 if (VTABLE_exists_keyed_str(INTERP, _class->attrib_metadata, name)) 817 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 818 "Attribute '%Ss' already exists in '%Ss'", name, 819 VTABLE_get_string(INTERP, SELF)); 820 821 /* Set name and type. */ 822 VTABLE_set_string_keyed_str(INTERP, new_attribute, CONST_STRING(INTERP, "name"), name); 823 824 if (!PMC_IS_NULL(type)) 825 VTABLE_set_pmc_keyed_str(INTERP, new_attribute, CONST_STRING(INTERP, "type"), type); 826 827 /* Enter the attribute in the attrib_metadata table. */ 828 VTABLE_set_pmc_keyed_str(INTERP, _class->attrib_metadata, name, 829 new_attribute); 830 } 831 832/* 833 834=item C<void remove_attribute(STRING *name)> 835 836Removes the given attribute (C<name>) from the class. Throws an exception if 837the current class has been instantiated, or if the class has no attribute 838C<name>. 839 840=cut 841 842*/ 843 844 VTABLE void remove_attribute(STRING *name) :manual_wb { 845 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 846 847 /* If we've been instantiated already, not allowed. */ 848 if (_class->instantiated) 849 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION, 850 "Modifications to classes are not allowed after instantiation"); 851 852 /* If we don't have an attribute of this name, it's an error. */ 853 if (!VTABLE_exists_keyed_str(INTERP, _class->attrib_metadata, name)) 854 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 855 "Attribute '%Ss' cannot be removed, does not exist in '%Ss'", name, 856 VTABLE_get_string(INTERP, SELF)); 857 858 /* Remove the attribute from the attrib_metadata table. */ 859 VTABLE_delete_keyed_str(INTERP, _class->attrib_metadata, name); 860 861 build_attrib_index(INTERP, SELF); /* calls WB */ 862 } 863 864/* 865 866=item C<void add_method(STRING *name, PMC *sub)> 867 868Adds the given sub PMC as a method with the given name. 869 870=cut 871 872*/ 873 VTABLE void add_method(STRING *name, PMC *sub) { 874 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 875 PMC * const method = 876 VTABLE_get_pmc_keyed_str(INTERP, _class->methods, name); 877 878 /* If we have already added a method with this name... */ 879 if (!PMC_IS_NULL(method)) { 880 if (method == sub) 881 return; 882 883 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 884 "A method named '%S' already exists in class '%S'. " 885 "It may have been supplied by a role", 886 name, VTABLE_get_string(INTERP, SELF)); 887 } 888 889 /* Enter it into the table. */ 890 VTABLE_set_pmc_keyed_str(INTERP, _class->methods, name, sub); 891 } 892 893/* 894 895=item C<void remove_method(STRING *name)> 896 897Removes the method with the given name. 898 899=cut 900 901*/ 902 VTABLE void remove_method(STRING *name) { 903 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 904 if (VTABLE_exists_keyed_str(INTERP, _class->methods, name)) 905 VTABLE_delete_keyed_str(INTERP, _class->methods, name); 906 else 907 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 908 "No method named '%S' to remove in class '%S'", 909 name, VTABLE_get_string(INTERP, SELF)); 910 } 911 912/* 913 914=item C<void add_vtable_override(STRING *name, PMC *sub)> 915 916Adds the given sub PMC as a vtable override with the given name. 917 918=cut 919 920*/ 921 VTABLE void add_vtable_override(STRING *name, PMC *sub) { 922 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 923 924 /* Check that the name is actually valid as a vtable override */ 925 if (Parrot_get_vtable_index(INTERP, name) == -1) 926 Parrot_ex_throw_from_c_args(INTERP, NULL, 927 EXCEPTION_METHOD_NOT_FOUND, 928 "'%S' is not a valid vtable function name", name); 929 930 /* Add it to vtable list. */ 931 VTABLE_set_pmc_keyed_str(INTERP, _class->vtable_overrides, name, sub); 932 } 933 934/* 935 936=item C<void add_parent(PMC *parent)> 937 938Adds the supplied PMC to the list of parents for the class. 939 940=cut 941 942*/ 943 VTABLE void add_parent(PMC *parent) { 944 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 945 int parent_count, index; 946 947 /* If we've been instantiated already, not allowed. */ 948 if (_class->instantiated) 949 Parrot_ex_throw_from_c_noargs(INTERP, 950 EXCEPTION_INVALID_OPERATION, 951 "Modifications to classes are not allowed after instantiation"); 952 953 if (PMC_IS_NULL(parent)) { 954 STRING * const me_str = make_class_name(INTERP, SELF); 955 Parrot_ex_throw_from_c_args(INTERP, NULL, 956 EXCEPTION_UNEXPECTED_NULL, "Parent of '%Ss' is null", me_str); 957 } 958 959 /* Ensure it really is a class. */ 960 if (!PObj_is_class_TEST(parent)) { 961 STRING * const pstr = VTABLE_get_string(INTERP, parent); 962 STRING * me_str = make_class_name(INTERP, SELF); 963 Parrot_ex_throw_from_c_args(INTERP, NULL, 964 EXCEPTION_INVALID_OPERATION, 965 "Parent '%Ss' of '%Ss' isn't a Class", pstr, me_str); 966 } 967 968 /* Check is not self */ 969 if (parent == SELF) 970 Parrot_ex_throw_from_c_noargs(INTERP, 971 EXCEPTION_INVALID_OPERATION, "Can't be own parent"); 972 973 /* get number of direct parents */ 974 parent_count = VTABLE_elements(INTERP, _class->parents); 975 976 /* iterate over all direct parents, check whether this class already has 977 * the parent being added. */ 978 for (index = 0; index < parent_count; ++index) { 979 /* get the next parent */ 980 PMC * const current_parent = VTABLE_get_pmc_keyed_int(INTERP, 981 _class->parents, index); 982 983 /* throw an exception if we already have this parent */ 984 if (current_parent == parent) 985 Parrot_ex_throw_from_c_args(INTERP, NULL, 986 EXCEPTION_INVALID_OPERATION, 987 "The class '%S' already has a parent class '%S'. " 988 "It may have been supplied by a role", 989 VTABLE_get_string(INTERP, SELF), 990 VTABLE_get_string(INTERP, parent)); 991 } 992 993 /* Check that none of the parents is self */ 994 parent_count = VTABLE_elements(INTERP, PARROT_CLASS(parent)->all_parents); 995 996 for (index = 0; index < parent_count; ++index) { 997 /* get the next parent */ 998 PMC * const current_parent = VTABLE_get_pmc_keyed_int(INTERP, 999 PARROT_CLASS(parent)->all_parents, index); 1000 1001 if (current_parent == SELF) 1002 Parrot_ex_throw_from_c_args(INTERP, NULL, 1003 EXCEPTION_INVALID_OPERATION, 1004 "Loop in class hierarchy: '%S' is an ancestor of '%S'", 1005 VTABLE_get_string(INTERP, SELF), 1006 VTABLE_get_string(INTERP, parent)); 1007 } 1008 1009 /* Add to the lists of our immediate parents and all parents. */ 1010 VTABLE_push_pmc(INTERP, _class->parents, parent); 1011 Parrot_hash_put(INTERP, _class->isa_cache, (void *)parent, (void *)1); 1012 calculate_mro(INTERP, SELF, parent_count + 1); 1013 } 1014 1015/* 1016 1017=item C<void remove_parent(PMC *parent)> 1018 1019Remove the supplied class object from the list of parents for the class. 1020Throws an exception if parent is null, is not a class, or is not a parent, or 1021if the class has been instantiated. 1022 1023=cut 1024 1025*/ 1026 VTABLE void remove_parent(PMC *parent) { 1027 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1028 int parent_count, index; 1029 1030 /* If we've been instantiated already, not allowed. */ 1031 if (_class->instantiated) 1032 Parrot_ex_throw_from_c_noargs(INTERP, 1033 EXCEPTION_INVALID_OPERATION, 1034 "Modifications to classes are not allowed after instantiation"); 1035 1036 /* Ensure it really is a class. */ 1037 if (!PObj_is_class_TEST(parent)) 1038 Parrot_ex_throw_from_c_noargs(INTERP, 1039 EXCEPTION_INVALID_OPERATION, "Parent isn't a Class"); 1040 1041 /* get number of direct parents */ 1042 parent_count = VTABLE_elements(INTERP, _class->parents); 1043 1044 /* iterate over all direct parents, looking for the parent to remove */ 1045 for (index = 0; index < parent_count; ++index) { 1046 /* get the next parent */ 1047 PMC * const current_parent = VTABLE_get_pmc_keyed_int(INTERP, 1048 _class->parents, index); 1049 if (current_parent == parent) 1050 break; 1051 } 1052 1053 if (index >= parent_count) 1054 Parrot_ex_throw_from_c_noargs(INTERP, 1055 EXCEPTION_INVALID_OPERATION, 1056 "Can't remove_parent: is not a parent"); 1057 1058 VTABLE_delete_keyed_int(INTERP, _class->parents, index); 1059 Parrot_hash_put(INTERP, _class->isa_cache, (void *)parent, (void *)0); 1060 calculate_mro(INTERP, SELF, parent_count - 1); 1061 } 1062 1063/* 1064 1065=item C<void add_role(PMC *role)> 1066 1067Adds the supplied PMC to the list of roles for the class, provided there are 1068no conflicts. 1069 1070=cut 1071 1072*/ 1073 VTABLE void add_role(PMC *role) { 1074 const Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1075 1076 /* Do the composition. */ 1077 Parrot_ComposeRole(INTERP, role, 1078 _class->resolve_method, !PMC_IS_NULL(_class->resolve_method), 1079 PMCNULL, 0, _class->methods, _class->roles); 1080 } 1081 1082/* 1083 1084=item C<PMC *inspect_str(STRING *what)> 1085 1086Provides introspection of a specific piece of information about the class. The 1087available information is: 1088 1089=over 8 1090 1091=item name 1092 1093String PMC containing the name of the class 1094 1095=item namespace 1096 1097NameSpace PMC of the namespace attached to the class. 1098 1099=item attributes 1100 1101Hash keyed on attribute name, where the value is a hash describing it. 1102 1103=item methods 1104 1105Hash keyed on method name, value is an invokable PMC. Includes methods composed 1106in from roles. 1107 1108=item roles 1109 1110Array of Role PMCs. Includes roles done by the roles that were composed into 1111this class. 1112 1113=item parents 1114 1115Array of Class PMCs representing the direct parents of this class. 1116 1117=back 1118 1119=cut 1120 1121*/ 1122 VTABLE PMC *inspect_str(STRING *what) :no_wb { 1123 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1124 1125 /* What should we return? */ 1126 PMC *found; 1127 1128 if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "attributes"))) { 1129 found = _class->attrib_metadata; 1130 } 1131 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "parents"))) { 1132 found = _class->parents; 1133 } 1134 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "name"))) { 1135 found = Parrot_pmc_new(INTERP, enum_class_String); 1136 VTABLE_set_string_native(INTERP, found, _class->name); 1137 } 1138 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "id"))) { 1139 found = Parrot_pmc_new_init_int(INTERP, enum_class_Integer, _class->id); 1140 } 1141 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "namespace"))) { 1142 /* Should not clone this. */ 1143 return _class->_namespace; 1144 } 1145 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "attrib_index"))) { 1146 found = _class->attrib_index; 1147 } 1148 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "methods"))) { 1149 found = _class->methods; 1150 } 1151 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "vtable_overrides"))) { 1152 found = _class->vtable_overrides; 1153 } 1154 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "all_parents"))) { 1155 found = _class->all_parents; 1156 } 1157 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "roles"))) { 1158 found = _class->roles; 1159 } 1160 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "flags"))) { 1161 found = Parrot_pmc_new_init_int(INTERP, enum_class_Integer, 1162 (INTVAL)PObj_get_FLAGS(SELF)); 1163 } 1164 else 1165 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 1166 "Unknown introspection value '%S'", what); 1167 1168 /* return found value */ 1169 if (PMC_IS_NULL(found)) 1170 return PMCNULL; 1171 1172 if (found->vtable->base_type == enum_class_Hash) { 1173 /* for Hash return values, create and return a shallow 1174 * clone because the VTABLE_clone does a deep clone */ 1175 PMC * const hash = Parrot_pmc_new(INTERP, enum_class_Hash); 1176 Hash *src = (Hash *)VTABLE_get_pointer(interp, found); 1177 Hash *dest = (Hash *)VTABLE_get_pointer(interp, hash); 1178 1179 Parrot_hash_clone_prunable(interp, src, dest, 0); 1180 1181 return hash; 1182 } 1183 1184 return VTABLE_clone(INTERP, found); 1185 } 1186 1187/* 1188 1189=item C<PMC *inspect()> 1190 1191Returns a Hash describing the class, with key/value pairs as described in 1192inspect_str. 1193 1194=cut 1195 1196*/ 1197 VTABLE PMC *inspect() :no_wb { 1198 /* Create a hash, then use inspect_str to get all of the data to 1199 * fill it up with. */ 1200 PMC * const metadata = Parrot_pmc_new(INTERP, enum_class_Hash); 1201 STRING * const name_str = CONST_STRING(INTERP, "name"); 1202 STRING * const ns_str = CONST_STRING(INTERP, "namespace"); 1203 STRING * const attrs_str = CONST_STRING(INTERP, "attributes"); 1204 STRING * const meths_str = CONST_STRING(INTERP, "methods"); 1205 STRING * const parents_str = CONST_STRING(INTERP, "parents"); 1206 STRING * const roles_str = CONST_STRING(INTERP, "roles"); 1207 STRING * const flags_str = CONST_STRING(INTERP, "flags"); 1208 1209 VTABLE_set_pmc_keyed_str(INTERP, metadata, name_str, 1210 VTABLE_inspect_str(INTERP, SELF, name_str)); 1211 1212 VTABLE_set_pmc_keyed_str(INTERP, metadata, ns_str, 1213 VTABLE_inspect_str(INTERP, SELF, ns_str)); 1214 1215 VTABLE_set_pmc_keyed_str(INTERP, metadata, attrs_str, 1216 VTABLE_inspect_str(INTERP, SELF, attrs_str)); 1217 1218 VTABLE_set_pmc_keyed_str(INTERP, metadata, meths_str, 1219 VTABLE_inspect_str(INTERP, SELF, meths_str)); 1220 1221 VTABLE_set_pmc_keyed_str(INTERP, metadata, parents_str, 1222 VTABLE_inspect_str(INTERP, SELF, parents_str)); 1223 1224 VTABLE_set_pmc_keyed_str(INTERP, metadata, roles_str, 1225 VTABLE_inspect_str(INTERP, SELF, roles_str)); 1226 1227 VTABLE_set_pmc_keyed_str(INTERP, metadata, flags_str, 1228 VTABLE_inspect_str(INTERP, SELF, flags_str)); 1229 1230 return metadata; 1231 } 1232 1233/* 1234 1235=item C<PMC *clone()> 1236 1237Returns an anonymous copy of the class (with no name and no link to a 1238namespace). Unsets the instantiated flag, allowing modifications. 1239 1240=cut 1241 1242*/ 1243 1244 VTABLE PMC *clone() :no_wb { 1245 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1246 1247 /* Create the new class PMC, of the same type of this one (we may 1248 * have been subclassed). */ 1249 PMC * const copy = SUPER(); 1250 1251 /* Clone parents, roles, methods, attributes and resolve data. We do 1252 * not copy name/namespace related stuff (need anonymous clone) or 1253 * stuff that gets computed on the first instantiation. */ 1254 1255 Parrot_Class_attributes * const new_class = PARROT_CLASS(copy); 1256 1257 new_class->name = CONST_STRING(INTERP, ""); 1258 new_class->_namespace = PMCNULL; 1259 new_class->parents = VTABLE_clone(INTERP, _class->parents); 1260 new_class->roles = VTABLE_clone(INTERP, _class->roles); 1261 new_class->methods = VTABLE_clone(INTERP, _class->methods); 1262 new_class->vtable_overrides = VTABLE_clone(INTERP, 1263 _class->vtable_overrides); 1264 new_class->parent_overrides = VTABLE_clone(INTERP, 1265 _class->parent_overrides); 1266 new_class->attrib_metadata = VTABLE_clone(INTERP, 1267 _class->attrib_metadata); 1268 new_class->resolve_method = VTABLE_clone(INTERP, 1269 _class->resolve_method); 1270 1271 /* Return cloned class. */ 1272 return copy; 1273 } 1274 1275/* 1276 1277=item C<PMC *clone_pmc(PMC *args)> 1278 1279Makes a copy of the class, then modifies or adds to it based upon the contents 1280of the supplied initialization data. If a new name or namespace is not supplied 1281in C<args> then the cloned class will be anonymous. The instantiated flag is 1282unset to allow further modifications. 1283 1284=cut 1285 1286*/ 1287 1288 VTABLE PMC *clone_pmc(PMC *args) :no_wb { 1289 /* Do the standard clone. */ 1290 PMC * const copy = SELF.clone(); 1291 1292 init_class_from_hash(INTERP, copy, args); 1293 1294 return copy; 1295 } 1296 1297/* 1298 1299=item C<PMC *instantiate(PMC *init)> 1300 1301Creates a new PMC object of the type of the class and calls init(). 1302 1303=cut 1304 1305*/ 1306 1307 VTABLE PMC *instantiate(PMC *init) :manual_wb { 1308 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1309 PMC *object; 1310 1311 /* If we've not been instantiated before... */ 1312 if (!_class->instantiated) { 1313 /* Check that we have all methods listed in resolve list. */ 1314 const int resolve_count = VTABLE_elements(INTERP, 1315 _class->resolve_method); 1316 const INTVAL cur_hll = Parrot_pcc_get_HLL(INTERP, CURRENT_CONTEXT(INTERP)); 1317 const INTVAL num_parents = VTABLE_elements(INTERP, _class->parents); 1318 INTVAL mro_length; 1319 int i; 1320 1321 /* don't use HLL mappings for internal-only data */ 1322 Parrot_pcc_set_HLL(INTERP, CURRENT_CONTEXT(INTERP), 0); 1323 1324 for (i = 0; i < resolve_count; ++i) { 1325 STRING * const check_meth = 1326 VTABLE_get_string_keyed_int(INTERP, _class->resolve_method, i); 1327 if (!VTABLE_exists_keyed_str(INTERP, _class->methods, check_meth)) 1328 Parrot_ex_throw_from_c_args(INTERP, NULL, 1329 EXCEPTION_METHOD_NOT_FOUND, "The method '%S' was named " 1330 "in the resolve list, but not supplied", check_meth); 1331 } 1332 1333 /* Build full parents list. */ 1334 calculate_mro(INTERP, SELF, num_parents); 1335 build_attrib_index(INTERP, SELF); 1336 1337 if (PMC_IS_NULL(_class->attrib_index)) { 1338 return PMCNULL; 1339 } 1340 1341 /* See if we have any parents from other universes and if so set a 1342 * flag stating so. */ 1343 mro_length = VTABLE_elements(INTERP, _class->all_parents); 1344 1345 for (i = 0; i < mro_length; ++i) { 1346 PMC * const class_check = VTABLE_get_pmc_keyed_int(INTERP, 1347 _class->all_parents, i); 1348 if (class_check->vtable->base_type != enum_class_Class) { 1349 /* Found one; that's enough. */ 1350 CLASS_has_alien_parents_SET(SELF); 1351 break; 1352 } 1353 } 1354 1355 Parrot_pcc_set_HLL(INTERP, CURRENT_CONTEXT(INTERP), cur_hll); 1356 } 1357 1358 /* Set instantiated flag. */ 1359 _class->instantiated = 1; 1360 1361 /* Create object. */ 1362 object = Parrot_pmc_new_noinit(INTERP, enum_class_Object); 1363 1364 /* Set custom GC mark and destroy on the object. */ 1365 PObj_custom_mark_destroy_SETALL(object); 1366 1367 /* Flag that it is an object */ 1368 PObj_is_object_SET(object); 1369 1370 /* Initialize the object's underlying structure, pointing it to this 1371 * class. */ 1372 /* TODO: this has been changed in order to use auto_attrs in the 1373 * Object PMC. Needs to be redone in a cleaner way. */ 1374 { 1375 Parrot_Object_attributes * const objattr = 1376 PMC_data_typed(object, Parrot_Object_attributes *); 1377 objattr->_class = SELF; 1378 /* Big L1 Instr fetch miss */ 1379 objattr->attrib_store = 1380 Parrot_pmc_new_init_int(INTERP, enum_class_ResizablePMCArray, 1381 VTABLE_elements(INTERP, _class->attrib_index)); 1382 PARROT_GC_WRITE_BARRIER(INTERP, object); 1383 } 1384 1385 if (!PMC_IS_NULL(init)) { 1386 /* Initialize attributes with the supplied values. */ 1387 PMC * const iter = VTABLE_get_iter(INTERP, init); 1388 1389 while (VTABLE_get_bool(INTERP, iter)) { 1390 STRING * const name = VTABLE_shift_string(INTERP, iter); 1391 PMC * const value = VTABLE_get_pmc_keyed_str(INTERP, init, 1392 name); 1393 1394 /* Set the attribute. */ 1395 VTABLE_set_attr_str(INTERP, object, name, value); 1396 } 1397 1398 /* Check for overrides on the init_pmc vtable function */ 1399 initialize_parents_pmc(INTERP, object, _class->all_parents, init); 1400 } 1401 else 1402 /* Check for overrides on the init vtable function */ 1403 initialize_parents(INTERP, object, _class->all_parents); 1404 1405 return object; 1406 } 1407 1408 1409/* 1410 1411=item C<INTVAL isa_pmc(PMC *class)> 1412 1413Returns whether the class is or inherits from C<*class>. 1414 1415=cut 1416 1417*/ 1418 1419 VTABLE INTVAL isa_pmc(PMC *lookup) :manual_wb { 1420 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1421 PMC *classobj; 1422 HashBucket *b; 1423 INTVAL i, num_classes, retval = 0; 1424 1425 if (PMC_IS_NULL(lookup)) 1426 return 0; 1427 1428 if (PObj_is_class_TEST(lookup)) { 1429 if (lookup == SELF) 1430 return 1; 1431 else 1432 classobj = lookup; 1433 } 1434 else 1435 classobj = Parrot_oo_get_class(INTERP, lookup); 1436 1437 if (PMC_IS_NULL(classobj)) 1438 return 0; 1439 1440 /* Check if the class object is the same as self's class object */ 1441 if (VTABLE_is_same(INTERP, SELF, classobj)) 1442 goto found; 1443 1444 if (_class->instantiated) { 1445 b = Parrot_hash_get_bucket(INTERP, _class->isa_cache, 1446 (void *)classobj); 1447 if (b) 1448 return PTR2INTVAL(b->value); 1449 } 1450 1451 /* this is effectively what the default PMC's isa_pmc does 1452 * ... but this can cheat and avoid COW STRINGs for the classobj 1453 * only in these two, very specific and common cases */ 1454 if (classobj->vtable->base_type == enum_class_Class 1455 || classobj->vtable->base_type == enum_class_PMCProxy) { 1456 STRING *classname = make_class_name(INTERP, classobj); 1457 PARROT_ASSERT(SELF->vtable->isa_hash); 1458 if (Parrot_hash_exists(INTERP, SELF->vtable->isa_hash, classname)) 1459 goto found; 1460 } 1461 1462 /* Iterate over all the parents and check if they respond true 1463 * for 'isa' on the original comparison. */ 1464 num_classes = VTABLE_elements(INTERP, _class->parents); 1465 1466 for (i = 0; i < num_classes; ++i) { 1467 PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP, 1468 _class->parents, i); 1469 1470 if (VTABLE_isa_pmc(INTERP, cur_class, lookup)) 1471 goto found; 1472 } 1473 1474 cache_and_return: 1475 if (_class->instantiated) { 1476 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 1477 Parrot_hash_put(INTERP, _class->isa_cache, (void *)classobj, 1478 INTVAL2PTR(void *, retval)); 1479 } 1480 return retval; 1481 1482 found: 1483 retval = 1; 1484 goto cache_and_return; 1485 } 1486 1487/* 1488 1489=item C<INTVAL isa(STRING *classname)> 1490 1491Returns whether the class is or inherits from C<*classname>. 1492 1493=cut 1494 1495*/ 1496 1497 VTABLE INTVAL isa(STRING *classname) :no_wb { 1498 PMC *want_class; 1499 1500 /* hard-code this one exception right away */ 1501 if (STRING_equal(INTERP, classname, CONST_STRING(INTERP, "Class"))) 1502 return 1; 1503 1504 want_class = Parrot_oo_get_class_str(INTERP, classname); 1505 1506 if (PMC_IS_NULL(want_class)) 1507 return 0; 1508 1509 if (SELF == want_class) 1510 return 1; 1511 else { 1512 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1513 1514 const INTVAL num_classes = VTABLE_elements(INTERP, _class->all_parents); 1515 int i; 1516 1517 for (i = 1; i < num_classes; ++i) { 1518 PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP, 1519 _class->all_parents, i); 1520 1521 if (VTABLE_is_same(INTERP, want_class, cur_class)) 1522 return 1; 1523 } 1524 } 1525 1526 return 0; 1527 } 1528 1529/* 1530 1531=item C<INTVAL does(STRING *role_name)> 1532 1533Returns whether the class does the role with the given C<*role_name>. 1534 1535=cut 1536 1537*/ 1538 VTABLE INTVAL does(STRING *role_name) :no_wb { 1539 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1540 PMC * const role_list = _class->roles; 1541 INTVAL i, count; 1542 1543 if (!role_list) 1544 return 0; 1545 1546 count = VTABLE_elements(INTERP, role_list); 1547 1548 for (i = 0; i < count; ++i) { 1549 PMC * const role = VTABLE_get_pmc_keyed_int(INTERP, role_list, i); 1550 1551 if (VTABLE_does(INTERP, role, role_name)) 1552 return 1; 1553 } 1554 1555 /* Iterate over all the parents and check if they respond true 1556 * for 'does' on the original comparison. */ 1557 count = VTABLE_elements(INTERP, _class->parents); 1558 1559 for (i = 0; i < count; ++i) { 1560 PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP, 1561 _class->parents, i); 1562 1563 if (VTABLE_does(INTERP, cur_class, role_name)) 1564 return 1; 1565 } 1566 1567 return VTABLE_isa(INTERP, SELF, role_name); 1568 } 1569 1570/* 1571 1572=item C<INTVAL does_pmc(PMC *role)> 1573 1574Returns whether the class does the given C<*role>. 1575 1576=cut 1577 1578*/ 1579 VTABLE INTVAL does_pmc(PMC *role) :no_wb { 1580 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1581 PMC * const role_list = _class->roles; 1582 INTVAL i, role_count, count; 1583 1584 if (!role_list) 1585 return 0; 1586 1587 role_count = VTABLE_elements(INTERP, role_list); 1588 1589 for (i = 0; i < role_count; ++i) { 1590 PMC * const test_role = VTABLE_get_pmc_keyed_int(INTERP, role_list, i); 1591 if (VTABLE_does_pmc(INTERP, test_role, role)) 1592 return 1; 1593 } 1594 1595 /* Iterate over all the parents and check if they respond true 1596 * for 'does' on the original comparison. */ 1597 count = VTABLE_elements(INTERP, _class->parents); 1598 1599 for (i = 0; i < count; ++i) { 1600 PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP, 1601 _class->parents, i); 1602 1603 if (VTABLE_does_pmc(INTERP, cur_class, role)) 1604 return 1; 1605 } 1606 1607 return VTABLE_isa_pmc(INTERP, SELF, role); 1608 } 1609 1610 VTABLE INTVAL is_equal(PMC * p) :no_wb { 1611 UNUSED(INTERP) 1612 return p == SELF; 1613 } 1614 1615/* 1616 1617=item C<INTVAL type()> 1618 1619Returns the integer type of the class. 1620 1621=cut 1622 1623*/ 1624 1625 VTABLE INTVAL type() :no_wb { 1626 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1627 UNUSED(INTERP) 1628 return _class->id; 1629 } 1630 1631/* 1632 1633=item C<void visit(PMC *info)> 1634 1635This is used by freeze/thaw to visit the contents of the class. 1636 1637C<*info> is the visit info, (see F<include/parrot/pmc_freeze.h>). 1638 1639=cut 1640 1641*/ 1642 1643 VTABLE void visit(PMC *info) :no_wb { 1644 /* 1) visit the attribute description hash */ 1645 VISIT_PMC_ATTR(INTERP, info, SELF, Class, attrib_metadata); 1646 1647 /* 2) visit list of parents */ 1648 VISIT_PMC_ATTR(INTERP, info, SELF, Class, parents); 1649 1650 /* 3) visit list of roles */ 1651 VISIT_PMC_ATTR(INTERP, info, SELF, Class, roles); 1652 1653 /* 4) visit hash of methods */ 1654 VISIT_PMC_ATTR(INTERP, info, SELF, Class, methods); 1655 1656 /* 5) visit hash of vtable overrides */ 1657 VISIT_PMC_ATTR(INTERP, info, SELF, Class, vtable_overrides); 1658 1659 /* 6) visit list of resolve methods */ 1660 VISIT_PMC_ATTR(INTERP, info, SELF, Class, resolve_method); 1661 } 1662 1663/* 1664 1665=item C<void freeze(PMC *info)> 1666 1667Used to archive the class. 1668 1669=cut 1670 1671*/ 1672 1673 VTABLE void freeze(PMC *info) :no_wb { 1674 Parrot_Class_attributes * const class_data = PARROT_CLASS(SELF); 1675 STRING *serial_namespace = CONST_STRING(INTERP, ""); 1676 1677 /* 1) freeze class id */ 1678 VTABLE_push_integer(INTERP, info, class_data->id); 1679 1680 /* 2) freeze class name */ 1681 VTABLE_push_string(INTERP, info, class_data->name); 1682 1683 /* 3) serialize namespace name, including HLL */ 1684 if (!PMC_IS_NULL(class_data->_namespace)) { 1685 PMC * const names = Parrot_ns_get_name(INTERP, 1686 class_data->_namespace); 1687 if (!PMC_IS_NULL(names)) 1688 serial_namespace = Parrot_str_join(INTERP, CONST_STRING(INTERP, ";"), names); 1689 } 1690 VTABLE_push_string(INTERP, info, serial_namespace); 1691 /* PARROT_GC_WRITE_BARRIER(INTERP, info); */ 1692 } 1693 1694/* 1695 1696=item C<void thaw(PMC *info)> 1697 1698Used to unarchive the class. 1699 1700=cut 1701 1702*/ 1703 1704 VTABLE void thaw(PMC *info) { 1705 /* The class might already exist in the interpreter, so create it as an 1706 * anonymous class and later decide whether to link it into the 1707 * namespace. */ 1708 1709 /* 1) thaw class id */ 1710 const INTVAL id = VTABLE_shift_integer(INTERP, info); 1711 1712 /* 2) thaw class name */ 1713 STRING * const name = VTABLE_shift_string(INTERP, info); 1714 1715 /* 3) deserialize namespace name, including HLL */ 1716 STRING * const serial_namespace = VTABLE_shift_string(INTERP, info); 1717 STRING * const semicolon_str = CONST_STRING(INTERP, ";"); 1718 PMC * const namespace_array = 1719 Parrot_str_split(INTERP, semicolon_str, serial_namespace); 1720 PMC *ns = Parrot_ns_get_namespace_keyed(INTERP, 1721 INTERP->root_namespace, namespace_array); 1722 1723 /* If the namespace doesn't exist, we create it, and initialize 1724 * ourselves in it */ 1725 if (PMC_IS_NULL(ns)) { 1726 ns = Parrot_ns_make_namespace_keyed(INTERP, 1727 INTERP->root_namespace, namespace_array); 1728 SELF.init_pmc(ns); 1729 } 1730 /* If the namespace exists already, we point to it, but otherwise 1731 * act as an anonymous class. */ 1732 else { 1733 SELF.init(); 1734 PARROT_CLASS(SELF)->_namespace = ns; 1735 } 1736 1737 /* Set the class's short name to the frozen name */ 1738 PARROT_CLASS(SELF)->name = name; 1739 1740 /* Set the class's id the frozen id */ 1741 PARROT_CLASS(SELF)->id = id; 1742 } 1743 1744/* 1745 1746=item C<INTVAL get_integer()> 1747 1748This is just a temporary hack. Type ID numbers shouldn't be externally 1749visible to the average PIR user. However, we need this for now to interface 1750with functions like Parrot_pmc_new and pmc_reuse, which take type ID numbers still. 1751 1752=cut 1753 1754*/ 1755 1756 VTABLE INTVAL get_integer() :no_wb { 1757 UNUSED(INTERP) 1758 return PARROT_CLASS(SELF)->id; 1759 } 1760 1761/* 1762 1763=item C<void thawfinish(PMC *info)> 1764 1765Called after the class has been thawed. 1766 1767=cut 1768 1769*/ 1770 1771 VTABLE void thawfinish(PMC *info) :manual_wb { 1772 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1773 UNUSED(info) 1774 1775 /* Recalculate full MRO from thawed parents */ 1776 _class->all_parents = Parrot_ComputeMRO_C3(INTERP, SELF); 1777 _class->parent_overrides = Parrot_pmc_new(INTERP, enum_class_Hash); 1778 1779 /* Rebuild attribute index from thawed attribute metadata */ 1780 build_attrib_index(INTERP, SELF); /* calls PARROT_GC_WRITE_BARRIER */ 1781 } 1782 1783 /* ********************************************************************** 1784 * Below here are methods that eventually will go in a role 1785 * that is composed into here to optionally give a nice interface from 1786 * PIR (ParrotClass isa Class does ClassMethods or something like this). 1787 * **********************************************************************/ 1788 1789/* 1790 1791=item C<void name(STRING *name :optional, int has_name :opt_flag)> 1792 1793Sets the name of the class, and updates the namespace accordingly. 1794 1795=cut 1796 1797*/ 1798 METHOD name(STRING *name :optional, int has_name :opt_flag) :manual_wb { 1799 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1800 STRING *ret_name; 1801 1802 if (has_name) { 1803 /* We'll build a hash just containing the name, then give this to 1804 * init_class_from_hash - saves some code duplication. */ 1805 PMC * const naming_hash = Parrot_pmc_new(INTERP, enum_class_Hash); 1806 STRING * const name_str = CONST_STRING(INTERP, "name"); 1807 1808 VTABLE_set_string_keyed_str(INTERP, naming_hash, name_str, name); 1809 init_class_from_hash(INTERP, SELF, naming_hash); 1810 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 1811 } 1812 1813 ret_name = _class->name; 1814 RETURN(STRING *ret_name); 1815 } 1816 1817/* 1818 1819=item C<void get_namespace()> 1820 1821Gets the namespace that this class is attached to. 1822 1823=cut 1824 1825*/ 1826 METHOD get_namespace(PMC *_namespace :optional, int has_name :opt_flag) :no_wb { 1827 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1828 PMC * const ret_namespace = _class->_namespace; 1829 UNUSED(_namespace); 1830 UNUSED(has_name); 1831 RETURN(PMC *ret_namespace); 1832 } 1833 1834/* 1835 1836=item C<void resolve_method()> 1837 1838Sets the list of method names that the class provides to resolve conflicts in 1839methods from roles. When called with no parameter, returns the list. 1840 1841=cut 1842 1843*/ 1844 METHOD resolve_method(PMC *resolve_list :optional, int has_list :opt_flag) :manual_wb { 1845 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1846 PMC *ret_list; 1847 1848 /* Store list. */ 1849 if (has_list) { 1850 _class->resolve_method = resolve_list; 1851 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 1852 } 1853 1854 ret_list = _class->resolve_method; 1855 RETURN(PMC *ret_list); 1856 } 1857 1858/* 1859 1860=item C<void new(PMC *args :slurpy :named)> 1861 1862Creates an instance of the object. Initializes any attributes specified in the 1863parameter list. 1864 1865=cut 1866 1867*/ 1868 METHOD new(PMC *args :slurpy :named) { 1869 /* Check if any arguments are in the slurpy hash, don't pass an empty 1870 * hash to instantiate */ 1871 PMC * const obj = 1872 VTABLE_elements(INTERP, args) > 0 1873 ? VTABLE_instantiate(INTERP, SELF, args) 1874 : VTABLE_instantiate(INTERP, SELF, PMCNULL); 1875 1876 RETURN(PMC *obj); 1877 } 1878 1879/* 1880 1881=item C<void attributes()> 1882 1883Return a hash where the keys are attribute names and the values are hashes 1884providing a set of key/value pairs describing the attribute. 1885 1886=cut 1887 1888*/ 1889 METHOD attributes() { 1890 STRING * const attr_str = CONST_STRING(INTERP, "attributes"); 1891 PMC * const ret_attrib_metadata = SELF.inspect_str(attr_str); 1892 1893 RETURN(PMC *ret_attrib_metadata); 1894 } 1895 1896/* 1897 1898=item C<void add_attribute()> 1899 1900Add an attribute to the class. Requires a name and, optionally, a type. 1901 1902=cut 1903 1904*/ 1905 METHOD add_attribute(STRING *attribute_name, 1906 PMC *attribute_type :optional, int has_type :opt_flag) { 1907 PMC * const type = has_type ? attribute_type : PMCNULL; 1908 SELF.add_attribute(attribute_name, type); 1909 } 1910 1911/* 1912 1913=item C<void methods()> 1914 1915Return a hash where the keys are method names and the values are methods. 1916 1917=cut 1918 1919*/ 1920 METHOD methods() :no_wb { 1921 PMC * const ret_methods = SELF.inspect_str(CONST_STRING(INTERP, "methods")); 1922 1923 RETURN(PMC *ret_methods); 1924 } 1925 1926/* 1927 1928=item C<void add_method(STRING *name, PMC *sub)> 1929 1930Adds the given sub PMC as a method with the given name. Delegates to the 1931C<add_method> vtable. 1932 1933=cut 1934 1935*/ 1936 METHOD add_method(STRING *name, PMC *sub) :manual_wb { 1937 SELF.add_method(name, sub); 1938 } 1939 1940/* 1941 1942=item C<void add_vtable_override(STRING *name, PMC *sub)> 1943 1944Adds the given sub PMC as a vtable override with the given name. Delegates to 1945the C<add_vtable_override> vtable. 1946 1947=cut 1948 1949*/ 1950 METHOD add_vtable_override(STRING *name, PMC *sub) :manual_wb { 1951 VTABLE_add_vtable_override(INTERP, SELF, name, sub); 1952 } 1953 1954/* 1955 1956=item C<void remove_method(STRING *name)> 1957 1958Removes the method with the given name. 1959 1960=cut 1961 1962*/ 1963 METHOD remove_method(STRING *name) :manual_wb { 1964 VTABLE_remove_method(INTERP, SELF, name); 1965 } 1966 1967/* 1968 1969=item C<PMC *find_method(STRING *name)> 1970 1971Walks the MRO of the class and finds the method with the given name. 1972 1973=cut 1974 1975*/ 1976 1977 METHOD find_method(STRING *name) :no_wb { 1978 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 1979 int i; 1980 1981 /* Walk and search. One day, we'll use the cache first. */ 1982 const int num_classes = VTABLE_elements(INTERP, _class->all_parents); 1983 1984 for (i = 0; i < num_classes; ++i) { 1985 /* Get the class and see if it has the method. */ 1986 PMC * const cur_class = 1987 VTABLE_get_pmc_keyed_int(INTERP, _class->all_parents, i); 1988 const Parrot_Class_attributes * const class_info = PARROT_CLASS(cur_class); 1989 1990 /* Found it! */ 1991 if (VTABLE_exists_keyed_str(INTERP, class_info->methods, name)) { 1992 PMC * const ret = VTABLE_get_pmc_keyed_str(INTERP, class_info->methods, name); 1993 RETURN(PMC *ret); 1994 } 1995 } 1996 1997 RETURN(PMC *PMCNULL); 1998 } 1999 2000/* 2001 2002=item C<void parents()> 2003 2004Returns the parents array PMC. 2005 2006=cut 2007 2008*/ 2009 METHOD parents() :no_wb { 2010 PMC * const ret_parents = SELF.inspect_str(CONST_STRING(INTERP, "parents")); 2011 2012 RETURN(PMC *ret_parents); 2013 } 2014 2015/* 2016 2017=item C<void add_parent(PMC *parent)> 2018 2019Adds the supplied PMC to the list of parents for the class. 2020 2021=cut 2022 2023*/ 2024 METHOD add_parent(PMC *parent) :manual_wb { 2025 SELF.add_parent(parent); 2026 } 2027 2028/* 2029 2030=item C<void roles()> 2031 2032Returns the roles array PMC. 2033 2034=cut 2035 2036*/ 2037 METHOD roles() :no_wb { 2038 PMC * const ret_roles = SELF.inspect_str(CONST_STRING(INTERP, "roles")); 2039 2040 RETURN(PMC *ret_roles); 2041 } 2042 2043/* 2044 2045=item C<void add_role(PMC *role, PMC *exclude :optional :named("exclude"), 2046PMC *alias :optional :named("alias"))> 2047 2048Composes a role into a class with the given exclusions and aliases. 2049 2050=cut 2051 2052*/ 2053 METHOD add_role(PMC *role, 2054 PMC *exclude_method :optional :named("exclude_method"), 2055 int has_exclude_method :opt_flag, 2056 PMC *alias_method :optional :named("alias_method"), 2057 int has_alias_method :opt_flag) { 2058 2059 Parrot_Class_attributes * const _class = PARROT_CLASS(SELF); 2060 2061 /* Add everything on the resolve list to the exclude list; if we have 2062 * no exclude list, pass along the resolve list in its place if it has 2063 * any methods listed in it. */ 2064 if (!has_exclude_method) { 2065 if (VTABLE_elements(INTERP, _class->resolve_method) != 0) { 2066 exclude_method = _class->resolve_method; 2067 has_exclude_method = 1; 2068 } 2069 } 2070 else { 2071 const int resolve_count = VTABLE_elements(INTERP, _class->resolve_method); 2072 int i; 2073 2074 for (i = 0; i < resolve_count; ++i) { 2075 STRING * const meth_name = VTABLE_get_string_keyed_int(INTERP, 2076 _class->resolve_method, i); 2077 VTABLE_push_string(INTERP, exclude_method, meth_name); 2078 } 2079 } 2080 2081 /* Do the composition. */ 2082 Parrot_ComposeRole(INTERP, role, exclude_method, has_exclude_method, 2083 alias_method, has_alias_method, 2084 _class->methods, _class->roles); 2085 } 2086 2087/* 2088 2089=item C<void inspect(STRING *what :optional)> 2090 2091Gets all introspection data for the class or, if the optional string 2092parameter is supplied, a particular item of introspection data. 2093 2094=cut 2095 2096*/ 2097 METHOD inspect(STRING *what :optional, int has_what :opt_flag) :no_wb { 2098 PMC *found; 2099 2100 /* Just delegate to the appropriate vtable. */ 2101 if (has_what) 2102 found = SELF.inspect_str(what); 2103 else 2104 found = SELF.inspect(); 2105 2106 RETURN(PMC *found); 2107 } 2108 2109/* 2110 2111=item C<void isa(STRING *class_name)> 2112 2113Returns true if this object is or derives from the class named in 2114C<class_name>, false otherwise. 2115 2116=cut 2117 2118*/ 2119 METHOD isa(STRING *class_name) :no_wb { 2120 const INTVAL isa = SELF.isa(class_name); 2121 2122 RETURN(INTVAL isa); 2123 } 2124 2125/* 2126 2127=item C<void does(STRING *role_name)> 2128 2129Returns true if this object or one of its parents performs the named role, 2130false otherwise. 2131 2132=cut 2133 2134*/ 2135 METHOD does(STRING *role_name) :no_wb { 2136 const INTVAL does = VTABLE_does(INTERP, SELF, role_name); 2137 RETURN(INTVAL does); 2138 } 2139 2140 METHOD clear_method_cache() { 2141 Parrot_Class_attributes * const attrs = PARROT_CLASS(SELF); 2142 PMC * const cache = attrs->meth_cache; 2143 if (cache) 2144 attrs->meth_cache = PMCNULL; 2145 } 2146 2147 METHOD get_method_cache() :no_wb { 2148 Parrot_Class_attributes * const attrs = PARROT_CLASS(SELF); 2149 PMC * cache = attrs->meth_cache; 2150 if (!cache) { 2151 cache = Parrot_pmc_new(INTERP, enum_class_Hash); 2152 attrs->meth_cache = cache; 2153 } 2154 RETURN(PMC *cache); 2155 } 2156 2157} /* END pmclass */ 2158 2159/* 2160 2161=back 2162 2163=head1 SEE ALSO 2164 2165F<docs/pdds/pdd15_objects.pod>. 2166 2167=cut 2168 2169*/ 2170 2171/* 2172 * Local variables: 2173 * c-file-style: "parrot" 2174 * End: 2175 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' : 2176 */ 2177