1/* 2Copyright (C) 2005-2014, Parrot Foundation. 3 4=head1 NAME 5 6src/pmc/namespace.pmc - NameSpace PMC 7 8=head1 DESCRIPTION 9 10These are the vtable functions for the namespace PMC, 11a container for dynamic and structured variable lookup. 12 13=head2 Functions 14 15=over 4 16 17=cut 18 19*/ 20 21#include "pmc/pmc_sub.h" 22 23/* HEADERIZER HFILE: none */ 24/* HEADERIZER BEGIN: static */ 25/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ 26 27static void add_multi_to_namespace(PARROT_INTERP, 28 ARGIN(PMC *SELF), 29 ARGIN(STRING *key), 30 ARGIN_NULLOK(PMC *value)) 31 __attribute__nonnull__(1) 32 __attribute__nonnull__(2) 33 __attribute__nonnull__(3); 34 35static void add_native_to_namespace(PARROT_INTERP, 36 ARGIN(PMC *SELF), 37 ARGIN(STRING *key), 38 ARGIN_NULLOK(PMC *value)) 39 __attribute__nonnull__(1) 40 __attribute__nonnull__(2) 41 __attribute__nonnull__(3); 42 43static void add_to_class(PARROT_INTERP, 44 ARGMOD(Parrot_NameSpace_attributes *nsinfo), 45 ARGMOD_NULLOK(PMC *classobj), 46 ARGIN(STRING *key), 47 ARGIN(PMC *value)) 48 __attribute__nonnull__(1) 49 __attribute__nonnull__(2) 50 __attribute__nonnull__(4) 51 __attribute__nonnull__(5) 52 FUNC_MODIFIES(*nsinfo) 53 FUNC_MODIFIES(*classobj); 54 55PARROT_WARN_UNUSED_RESULT 56static int maybe_add_sub_to_namespace(PARROT_INTERP, 57 ARGIN(PMC *SELF), 58 ARGIN(STRING *key), 59 ARGIN(PMC *value)) 60 __attribute__nonnull__(1) 61 __attribute__nonnull__(2) 62 __attribute__nonnull__(3) 63 __attribute__nonnull__(4); 64 65PARROT_WARN_UNUSED_RESULT 66static int ns_insert_sub_keyed_str(PARROT_INTERP, 67 ARGIN(PMC *self), 68 ARGIN(STRING *key), 69 ARGIN(PMC *value)) 70 __attribute__nonnull__(1) 71 __attribute__nonnull__(2) 72 __attribute__nonnull__(3) 73 __attribute__nonnull__(4); 74 75#define ASSERT_ARGS_add_multi_to_namespace __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 76 PARROT_ASSERT_ARG(interp) \ 77 , PARROT_ASSERT_ARG(SELF) \ 78 , PARROT_ASSERT_ARG(key)) 79#define ASSERT_ARGS_add_native_to_namespace __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 80 PARROT_ASSERT_ARG(interp) \ 81 , PARROT_ASSERT_ARG(SELF) \ 82 , PARROT_ASSERT_ARG(key)) 83#define ASSERT_ARGS_add_to_class __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 84 PARROT_ASSERT_ARG(interp) \ 85 , PARROT_ASSERT_ARG(nsinfo) \ 86 , PARROT_ASSERT_ARG(key) \ 87 , PARROT_ASSERT_ARG(value)) 88#define ASSERT_ARGS_maybe_add_sub_to_namespace __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 89 PARROT_ASSERT_ARG(interp) \ 90 , PARROT_ASSERT_ARG(SELF) \ 91 , PARROT_ASSERT_ARG(key) \ 92 , PARROT_ASSERT_ARG(value)) 93#define ASSERT_ARGS_ns_insert_sub_keyed_str __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 94 PARROT_ASSERT_ARG(interp) \ 95 , PARROT_ASSERT_ARG(self) \ 96 , PARROT_ASSERT_ARG(key) \ 97 , PARROT_ASSERT_ARG(value)) 98/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ 99/* HEADERIZER END: static */ 100 101/* 102 103=item C<static void add_to_class(PARROT_INTERP, Parrot_NameSpace_attributes 104*nsinfo, PMC *classobj, STRING *key, PMC *value)> 105 106Add the method Sub C<value> with name C<key> to the C<classobj>. 107 108=cut 109 110*/ 111 112static void 113add_to_class(PARROT_INTERP, ARGMOD(Parrot_NameSpace_attributes *nsinfo), 114 ARGMOD_NULLOK(PMC *classobj), ARGIN(STRING *key), ARGIN(PMC *value)) 115{ 116 ASSERT_ARGS(add_to_class) 117 118 /* Insert it in class, if there is a class */ 119 if (!PMC_IS_NULL(classobj) && PObj_is_class_TEST(classobj)) 120 VTABLE_add_method(interp, classobj, key, value); 121 122 /* Otherwise, store it in the namespace for the class to 123 * retrieve later */ 124 else { 125 /* If we don't have a place to hang methods, make one. */ 126 if (PMC_IS_NULL(nsinfo->methods)) 127 nsinfo->methods = Parrot_pmc_new(interp, enum_class_Hash); 128 129 /* Insert it. */ 130 VTABLE_set_pmc_keyed_str(interp, nsinfo->methods, key, value); 131 } 132} 133 134/* 135 136=item C<static int ns_insert_sub_keyed_str(PARROT_INTERP, PMC *self, STRING 137*key, PMC *value)> 138 139Add the Sub PMC C<value> to the namespace. If it's a vtable, add it as a 140vtable to the corresponding Class (or store it locally for the Class to fetch 141later). If it's a method, do the same. 142 143=cut 144 145*/ 146 147PARROT_WARN_UNUSED_RESULT 148static int 149ns_insert_sub_keyed_str(PARROT_INTERP, ARGIN(PMC *self), ARGIN(STRING *key), 150 ARGIN(PMC *value)) 151{ 152 ASSERT_ARGS(ns_insert_sub_keyed_str) 153 154 Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(self); 155 PMC * vtable = nsinfo->vtable; 156 PMC * const classobj = VTABLE_get_class(interp, self); 157 STRING * vtable_key = STRINGNULL; 158 Parrot_Sub_attributes *sub; 159 INTVAL stored = 0; 160 161 PMC_get_sub(interp, value, sub); 162 163 if (sub->vtable_index != -1) { 164 /* Insert it in class, if there is a class */ 165 if (!PMC_IS_NULL(classobj) && PObj_is_class_TEST(classobj)) { 166 const char * const vtable_key_c = 167 Parrot_get_vtable_name(interp, sub->vtable_index); 168 PARROT_ASSERT(vtable_key_c); 169 vtable_key = Parrot_str_new(interp, vtable_key_c, 170 strlen(vtable_key_c)); 171 VTABLE_add_vtable_override(interp, classobj, vtable_key, value); 172 } 173 174 /* Otherwise, store it in the namespace for the class to 175 * retrieve later */ 176 else { 177 /* If we don't have a place to hang vtables, make one. */ 178 if (PMC_IS_NULL(vtable)) 179 nsinfo->vtable = vtable = Parrot_pmc_new(interp, enum_class_Hash); 180 181 /* Insert it. */ 182 VTABLE_set_pmc_keyed_int(interp, vtable, sub->vtable_index, value); 183 } 184 if (!(sub->comp_flags & SUB_COMP_FLAG_NSENTRY)) 185 stored = 1; 186 } 187 188 if (sub->comp_flags & SUB_COMP_FLAG_METHOD) { 189 STRING *method_name = key; 190 191 if (STRING_equal(interp, sub->method_name, CONST_STRING(interp, ""))) { 192 if (sub->vtable_index != -1 && !STRING_IS_NULL(vtable_key)) { 193 method_name = vtable_key; 194 } 195 } 196 else { 197 method_name = sub->method_name; 198 } 199 add_to_class(interp, nsinfo, classobj, method_name, value); 200 201 if (!(sub->comp_flags & SUB_COMP_FLAG_NSENTRY)) 202 stored = 1; 203 } 204 205 return stored; 206} 207 208/* 209 210=item C<static int maybe_add_sub_to_namespace(PARROT_INTERP, PMC *SELF, STRING 211*key, PMC *value)> 212 213If the item C<value> is a non-null Sub PMC (but not a subclass), add it to the 214namespace and any associated Class PMC (if it's a method or vtable). 215 216=cut 217 218*/ 219 220PARROT_WARN_UNUSED_RESULT 221static int 222maybe_add_sub_to_namespace(PARROT_INTERP, ARGIN(PMC *SELF), ARGIN(STRING *key), 223 ARGIN(PMC *value)) 224{ 225 ASSERT_ARGS(maybe_add_sub_to_namespace) 226 227 STRING * const sub_str = CONST_STRING(interp, "Sub"); 228 229 if (!PMC_IS_NULL(value) 230 && VTABLE_isa(interp, value, sub_str) 231 && value->vtable->base_type != enum_class_Object) 232 return ns_insert_sub_keyed_str(interp, SELF, key, value); 233 234 return 0; 235} 236 237/* 238 239=item C<static void add_native_to_namespace(PARROT_INTERP, PMC *SELF, STRING 240*key, PMC *value)> 241 242Add an NCI or NativePCCMethod PMC to the namespace. The PMC C<value> must 243be non-null. If it's flagged as a method (usually for NativePCCMethod PMCs) 244add it to the Class as well. 245 246=cut 247 248*/ 249 250static void 251add_native_to_namespace(PARROT_INTERP, ARGIN(PMC *SELF), ARGIN(STRING *key), 252 ARGIN_NULLOK(PMC *value)) 253{ 254 ASSERT_ARGS(add_native_to_namespace) 255 256 if (!PMC_IS_NULL(value) 257 && (value->vtable->base_type == enum_class_NativePCCMethod || 258 value->vtable->base_type == enum_class_NCI)) { 259 Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF); 260 PMC * const classobj = VTABLE_get_class(interp, SELF); 261 262 /* Insert it in class, if there is a class */ 263 add_to_class(interp, nsinfo, classobj, key, value); 264 } 265} 266 267/* 268 269=item C<static void add_multi_to_namespace(PARROT_INTERP, PMC *SELF, STRING 270*key, PMC *value)> 271 272If PMC C<value> is a MultiSub, add it to the namespace and possibly the 273associated class. 274 275=cut 276 277*/ 278 279static void 280add_multi_to_namespace(PARROT_INTERP, ARGIN(PMC *SELF), ARGIN(STRING *key), 281 ARGIN_NULLOK(PMC *value)) 282{ 283 ASSERT_ARGS(add_multi_to_namespace) 284 285 STRING * const multi_str = CONST_STRING(interp, "MultiSub"); 286 287 if (!PMC_IS_NULL(value) 288 && VTABLE_isa(interp, value, multi_str)) { 289 290 /* TT #10; work around that Sub doesn't use PMC ATTRs */ 291 if (value->vtable->base_type != enum_class_Object 292 && VTABLE_elements(interp, value) > 0) { 293 Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF); 294 PMC * const classobj = VTABLE_get_class(interp, SELF); 295 296 /* Extract the first alternate and check if it is a method */ 297 PMC * const pmc_sub = VTABLE_get_pmc_keyed_int(interp, value, 0); 298 Parrot_Sub_attributes *sub; 299 PMC_get_sub(interp, pmc_sub, sub); 300 301 if (sub->comp_flags & SUB_COMP_FLAG_METHOD) { 302 STRING * const empty_str = CONST_STRING(interp, ""); 303 STRING *method_name = key; 304 Hash *hash; 305 306 if (!STRING_equal(interp, sub->method_name, empty_str)) 307 method_name = sub->method_name; 308 309 add_to_class(interp, nsinfo, classobj, method_name, value); 310 311 GETATTR_NameSpace_hash(interp, SELF, hash); 312 PARROT_GC_WRITE_BARRIER(interp, SELF); 313 314 Parrot_hash_put(interp, hash, 315 Parrot_hash_key_from_string(interp, hash, key), 316 Parrot_hash_value_from_pmc(interp, hash, value)); 317 } 318 } 319 } 320} 321 322 323/* 324 * Typically a named slot contains either another namespace or a 325 * var/sub (not both). 326 * In case that the bucket->value is occupied, a FixedPMCArray is 327 * created, and the items are moved over to that extra storage. 328 * The array is flagged with FPA_is_ns_ext to distinguish it from a 329 * plain array variable. 330 * 331 * This could easily expand to a full-fledged typed namespace if needed. 332 */ 333 334typedef enum { 335 NS_slot_ns, 336 NS_slot_var_sub, /* unspecified ~half-raw slot */ 337 NS_max_slots 338} NS_slot_enum; 339 340#define FPA_is_ns_ext PObj_private0_FLAG 341 342pmclass NameSpace extends Hash provides hash no_ro auto_attrs { 343 344 ATTR STRING *name; /* Name of this namespace part. */ 345 ATTR PMC *_class; /* The class or role attached to this namespace. */ 346 ATTR PMC *methods; /* A Hash of methods, keyed on the method name. This 347 * goes away when the methods are sucked in by a 348 * class. */ 349 ATTR PMC *vtable; /* A Hash of vtable subs, keyed on the vtable index */ 350 ATTR PMC *parent; /* This NameSpace's parent NameSpace */ 351 352/* 353 354=item C<void init()> 355 356Initialize a C<NameSpace> PMC. 357 358=cut 359 360*/ 361 362 VTABLE void init() { 363 SUPER(); 364 PARROT_NAMESPACE(SELF)->vtable = PMCNULL; 365 PARROT_NAMESPACE(SELF)->methods = PMCNULL; 366 PARROT_NAMESPACE(SELF)->_class = PMCNULL; 367 PObj_custom_mark_SET(SELF); 368 } 369 370/* 371 372=item C<void mark()> 373 374Marks the namespace as live. 375 376=cut 377 378*/ 379 VTABLE void mark() :no_wb { 380 Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF); 381 382 SUPER(); 383 Parrot_gc_mark_PMC_alive(INTERP, nsinfo->parent); 384 Parrot_gc_mark_PMC_alive(INTERP, nsinfo->_class); 385 Parrot_gc_mark_PMC_alive(INTERP, nsinfo->vtable); 386 Parrot_gc_mark_PMC_alive(INTERP, nsinfo->methods); 387 Parrot_gc_mark_STRING_alive(INTERP, nsinfo->name); 388 } 389 390/* 391 392=item C<PMC *get_class()> 393 394Returns the class or role PMC that is associated with this namespace. 395 396=cut 397 398*/ 399 400 PMC *get_class() :no_wb { 401 UNUSED(INTERP); 402 return PARROT_NAMESPACE(SELF)->_class; 403 } 404 405/* 406 407=item C<void set_pmc_keyed_str(STRING *key, PMC *value)> 408 409Sets C<*value> as the namespace item for C<*key>. This is part of the 410raw interface. If the PMC C<value> is exactly a NameSpace, C<SELF> 411will be set as the parent of that namespace and the name C<key> of 412C<value> is stored too. 413 414=item C<void set_pmc_keyed(PMC *key, PMC *value)> 415 416If C<key> is a simple key, it works like above. If C<key> is an array 417of strings or a chained key, add all components to the namespace. 418 419=item C<PMC *get_pmc_keyed(PMC *key)> 420 421Return the given namespace or PMCNULL. C<key> is either an array of 422strings, or a possibly nested key. 423 424=item C<PMC *get_pmc_keyed_str(STRING *key)> 425 426Return the given namespace item or PMCNULL. If the named item is either 427a NameSpace or a var, the NameSpace is returned. 428 429=item C<PMC *get_pmc_keyed_int(INTVAL key)> 430 431Return a Sub representing an overridden vtable entry or PMCNULL. This is not 432really a public API. 433 434=cut 435 436*/ 437 438 VTABLE void set_pmc_keyed_str(STRING *key, PMC *value) { 439 PMC *new_tuple = NULL; 440 const int val_is_NS = PMC_IS_NULL(value) 441 ? 0 442 :value->vtable->base_type == enum_class_NameSpace; 443 444 /* don't need this everywhere yet */ 445 PMC *old; 446 447 /* If it's a sub... */ 448 if (maybe_add_sub_to_namespace(INTERP, SELF, key, value)) 449 return; 450 451 /* If it's an native method */ 452 add_native_to_namespace(INTERP, SELF, key, value); 453 454 /* If it's a multi-sub and the first in this NS... */ 455 add_multi_to_namespace(INTERP, SELF, key, value); 456 457 old = (PMC *)Parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(), key); 458 459 if (!old) 460 SUPER(key, value); 461 else { 462 if ((old->vtable->base_type == enum_class_NameSpace) == val_is_NS) { 463 /* simple ns or simple var/sub changed */ 464 SUPER(key, value); 465 } 466 else if ((PObj_get_FLAGS(old) & FPA_is_ns_ext) && 467 old->vtable->base_type == enum_class_FixedPMCArray) { 468 /* we have a tuple extension already */ 469 VTABLE_set_pmc_keyed_int(INTERP, old, 470 val_is_NS ? NS_slot_ns : NS_slot_var_sub, 471 value); 472 } 473 else { 474 /* create new tuple */ 475 /* for a fully typed namespace, we'd need 3 or 4 */ 476 new_tuple = Parrot_pmc_new_init_int(INTERP, 477 enum_class_FixedPMCArray, NS_max_slots); 478 479 /* flag it as special */ 480 PObj_get_FLAGS(new_tuple) |= FPA_is_ns_ext; 481 } 482 } 483 484 if (val_is_NS) { 485 /* TODO - this hack needs to go */ 486 Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(value); 487 nsinfo->parent = SELF; /* set parent */ 488 nsinfo->name = key; /* and name */ 489 490 if (new_tuple) { 491 VTABLE_set_pmc_keyed_int(INTERP, new_tuple, NS_slot_ns, value); 492 VTABLE_set_pmc_keyed_int(INTERP, new_tuple, NS_slot_var_sub, 493 old); 494 495 Parrot_hash_put(INTERP, (Hash *)SELF.get_pointer(), key, new_tuple); 496 /* distinction from a plain FPA, which doesn't extend the 497 * namespace storage */ 498 } 499 } 500 else if (new_tuple) { 501 VTABLE_set_pmc_keyed_int(INTERP, new_tuple, NS_slot_ns, old); 502 VTABLE_set_pmc_keyed_int(INTERP, new_tuple, NS_slot_var_sub, value); 503 Parrot_hash_put(INTERP, (Hash *)SELF.get_pointer(), key, new_tuple); 504 } 505 } 506 507 VTABLE void set_pmc_keyed(PMC *key, PMC *value) :manual_wb { 508 PMC *ns = SELF; 509 510 if (key->vtable->base_type == enum_class_String) { 511 SELF.set_pmc_keyed_str(VTABLE_get_string(INTERP, key), value); 512 return; 513 } 514 515 if (key->vtable->base_type == enum_class_Key) { 516 while (1) { 517 STRING * const part = VTABLE_get_string(INTERP, key); 518 key = VTABLE_shift_pmc(INTERP, key); 519 520 if (!key) { 521 Parrot_ns_set_global(INTERP, ns, part, value); 522 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 523 return; 524 } 525 526 ns = Parrot_ns_make_namespace_keyed_str(INTERP, ns, part); 527 } 528 } 529 530 if (key->vtable->base_type == enum_class_ResizableStringArray) { 531 const INTVAL elements = VTABLE_elements(INTERP, key); 532 INTVAL i; 533 for (i = 0; i < elements; ++i) { 534 STRING * const part = VTABLE_get_string_keyed_int(INTERP, key, i); 535 536 if ((i + 1) >= elements) { /* Last entry in the array */ 537 Parrot_ns_set_global(INTERP, ns, part, value); 538 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 539 return; 540 } 541 542 ns = Parrot_ns_make_namespace_keyed_str(INTERP, ns, part); 543 } 544 } 545 546 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_GLOBAL_NOT_FOUND, 547 "Invalid namespace key in set_pmc_keyed"); 548 } 549 550 VTABLE PMC *get_pmc_keyed_str(STRING *key) :no_wb { 551 Hash * const hash = (Hash *)SELF.get_pointer(); 552 PMC *ns = (PMC *)Parrot_hash_get(INTERP, hash, key); 553 554 if (!ns) 555 return PMCNULL; 556 557 if ((PObj_get_FLAGS(ns) & FPA_is_ns_ext) && 558 ns->vtable->base_type == enum_class_FixedPMCArray) 559 ns = VTABLE_get_pmc_keyed_int(INTERP, ns, NS_slot_ns); 560 561 return ns; 562 } 563 564 VTABLE PMC *get_pmc_keyed(PMC *key) :no_wb { 565 PMC *ns = SUPER(key); 566 /* Is this equivalent? 567 PMC *ns = INTERP->vtables[enum_class_Hash]->get_pmc_keyed(INTERP, SELF, key); 568 */ 569 570 if (!PMC_IS_NULL(ns)) 571 return ns; 572 573 ns = SELF; 574 575 if (key->vtable->base_type == enum_class_Key) { 576 STRING * const part = VTABLE_get_string(INTERP, key); 577 key = VTABLE_shift_pmc(INTERP, key); 578 579 if (!key) 580 return VTABLE_get_pmc_keyed_str(INTERP, ns, part); 581 582 ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, part); 583 584 if (PMC_IS_NULL(ns)) 585 return PMCNULL; 586 587 return VTABLE_get_pmc_keyed(INTERP, ns, key); 588 } 589 else if (VTABLE_does(INTERP, key, CONST_STRING(INTERP, "array"))) { 590 const INTVAL elements = VTABLE_elements(INTERP, key); 591 INTVAL i; 592 for (i = 0; i < elements && !PMC_IS_NULL(ns); ++i) { 593 STRING * const name = VTABLE_get_string_keyed_int(INTERP, key, i); 594 if (STRING_IS_NULL(name)) { 595 ns = PMCNULL; 596 /* What to do here? Throw an exception or something? */ 597 break; 598 } 599 ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, name); 600 } 601 return ns; 602 } 603 else { 604 STRING * const name = VTABLE_get_string(INTERP, key); 605 ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, name); 606 return ns; 607 } 608 /* If we get the wrong type, should we throw an exception? 609 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_GLOBAL_NOT_FOUND, 610 "Invalid namespace key in get_pmc_keyed_str"); 611 */ 612 } 613 614 VTABLE PMC *get_pmc_keyed_int(INTVAL key) :no_wb { 615 Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF); 616 PMC * const vtable = nsinfo->vtable; 617 618 if (PMC_IS_NULL(vtable)) 619 return PMCNULL; 620 621 return VTABLE_get_pmc_keyed_int(INTERP, vtable, key); 622 } 623 624/* 625 626=item C<void *get_pointer_keyed_str(STRING *key)> 627 628Return the given namepace item or PMCNULL, keyed by name. 629 630=item C<void *get_pointer_keyed(PMC *key)> 631 632Return the given namespace item or PMCNULL. If the named item is either 633a NameSpace or a var, the var is returned. 634 635TT #1472 636TOTAL KLUDGE. ON THE CHOPPING BLOCK. 637 638=cut 639 640*/ 641 642 VTABLE void *get_pointer_keyed_str(STRING *key) :no_wb { 643 PMC *ns; 644 Hash *hash; 645 GETATTR_NameSpace_hash(INTERP, SELF, hash); 646 647 ns = (PMC *)Parrot_hash_get(INTERP, hash, key); 648 649 if (ns && (PObj_get_FLAGS(ns) & FPA_is_ns_ext) 650 && ns->vtable->base_type == enum_class_FixedPMCArray) 651 ns = VTABLE_get_pmc_keyed_int(INTERP, ns, NS_slot_var_sub); 652 653 /* Be extra careful about returning PMCNULL */ 654 if (!ns) ns = PMCNULL; 655 RETURN(PMC *ns); 656 } 657 658 VTABLE void *get_pointer_keyed(PMC *key) :no_wb { 659 PMC *ns = SELF; 660 661 if (PMC_IS_NULL(key)) 662 return PMCNULL; 663 664 switch (key->vtable->base_type) { 665 case enum_class_String: 666 return SELF.get_pointer_keyed_str(VTABLE_get_string(INTERP, key)); 667 case enum_class_Key: { 668 /* this loop (and function) could use a rewrite for clarity */ 669 while (1) { 670 STRING * const part = VTABLE_get_string(INTERP, key); 671 key = VTABLE_shift_pmc(INTERP, key); 672 673 if (!key) 674 return VTABLE_get_pointer_keyed_str(INTERP, ns, part); 675 676 ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, part); 677 678 if (PMC_IS_NULL(ns)) 679 return PMCNULL; 680 } 681 } 682 case enum_class_ResizableStringArray: { 683 const INTVAL elements = VTABLE_elements(INTERP, key); 684 INTVAL i; 685 for (i = 0; i < elements; ++i) { 686 STRING * const part = VTABLE_get_string_keyed_int(INTERP, key, i); 687 688 /* Last entry in the array */ 689 if ((i + 1) >= elements) 690 return VTABLE_get_pointer_keyed_str(INTERP, ns, part); 691 692 ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, part); 693 694 if (PMC_IS_NULL(ns)) 695 return PMCNULL; 696 } 697 return ns; 698 } 699 default: 700 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_GLOBAL_NOT_FOUND, 701 "Invalid namespace key of type '%S' in get_pointer_keyed", 702 key->vtable->whoami); 703 } 704 } 705 706/* 707 708=item C<STRING *get_string()> 709 710Return the name of this namespace part. 711 712=cut 713 714*/ 715 716 VTABLE STRING *get_string() :no_wb { 717 const Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF); 718 UNUSED(INTERP) 719 return nsinfo->name; 720 } 721 722/* 723 724=item C<PMC *inspect_str(STRING *what)> 725 726Provides introspection of a specific piece of information about the 727namespace. The available information is: 728 729=over 8 730 731=item class 732 733The class object associated with the namespace, if any. 734 735=item methods 736 737A temporary cache of methods (destroyed when class object is created). 738Hash keyed on method name, value is an invokable PMC. Includes methods 739composed in from roles. 740 741=item vtable_overrides 742 743A temporary cache of vtable overrides (destroyed when class object is 744created). Hash keyed on vtable name, value is an invokable PMC. 745Includes vtable overrides composed in from roles. 746 747=back 748 749=cut 750 751*/ 752 753 VTABLE PMC *inspect_str(STRING *what) :no_wb { 754 const Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF); 755 PMC *found; 756 757 if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "methods"))) { 758 found = nsinfo->methods; 759 } 760 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "vtable_overrides"))) { 761 found = nsinfo->vtable; 762 } 763 else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "class"))) { 764 found = nsinfo->_class; 765 } 766 else 767 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 768 "Unknown introspection value '%S'", what); 769 770 /* return found value */ 771 if (PMC_IS_NULL(found)) 772 return PMCNULL; 773 774 return found; 775 } 776 777/* 778 779=back 780 781=head2 Methods 782 783=over 4 784 785=cut 786 787=item C<METHOD make_namespace(PMC* key)> 788 789Create and retrieve the namespace given by C<key>. If the namespace 790already exists, only retrieve it. 791 792=cut 793 794*/ 795 796 METHOD make_namespace(PMC *key) { 797 PMC *ns = Parrot_ns_get_namespace_keyed(INTERP, SELF, key); 798 if (PMC_IS_NULL(ns)) { 799 ns = Parrot_ns_make_namespace_keyed(INTERP, SELF, key); 800 } 801 RETURN(PMC *ns); 802 } 803 804/* 805 806=item C<METHOD add_namespace(STRING *name, PMC *namespace)> 807 808Stores the given namespace under this namespace, with the given name. Throws 809an invalid type exception if C<namespace> is not a NameSpace PMC or subclass. 810 811=cut 812 813*/ 814 815 METHOD add_namespace(STRING *name, PMC *_namespace) :manual_wb { 816 STRING * const s_ns = CONST_STRING(INTERP, "NameSpace"); 817 818 if (!VTABLE_isa(INTERP, _namespace, s_ns)) 819 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 820 "Invalid type %d in add_namespace()", 821 _namespace->vtable->base_type); 822 823 VTABLE_set_pmc_keyed_str(INTERP, SELF, name, _namespace); 824 } 825 826/* 827 828=item C<METHOD add_sub(STRING *name, PMC *sub)> 829 830Stores the given sub under this namespace, with the given name. Throws an 831invalid type exception if C<sub> is not a Sub PMC or subclass. 832 833=cut 834 835*/ 836 837 METHOD add_sub(STRING *name, PMC *sub) :manual_wb { 838 STRING * const s_sub = CONST_STRING(INTERP, "Sub"); 839 STRING * const s_multisub = CONST_STRING(INTERP, "MultiSub"); 840 841 if (!VTABLE_isa(INTERP, sub, s_sub) 842 && !VTABLE_isa(INTERP, sub, s_multisub)) 843 Parrot_ex_throw_from_c_args(INTERP, NULL, 844 EXCEPTION_INVALID_OPERATION, 845 "Invalid type %d in add_sub()", sub->vtable->base_type); 846 847 VTABLE_set_pmc_keyed_str(INTERP, SELF, name, sub); 848 } 849 850/* 851 852=item C<METHOD add_var(STRING *name, PMC *var)> 853 854Stores the given variable under this namespace, with the given name. 855 856=cut 857 858*/ 859 860 METHOD add_var(STRING *name, PMC *var) :manual_wb { 861 VTABLE_set_pmc_keyed_str(INTERP, SELF, name, var); 862 } 863 864/* 865 866=item C<METHOD get_name()> 867 868Returns the name of the namespace as an array of strings. 869 870 $P2 = $P3.'get_name'() 871 $S0 = join '::', $P2 # '::Foo::Bar' 872 873=cut 874 875*/ 876 877 METHOD get_name() :no_wb { 878 PMC * const ar = Parrot_pmc_new(INTERP, enum_class_ResizableStringArray); 879 INTVAL elements = 0; 880 PMC *ns = SELF; 881 882 while (ns) { 883 Parrot_NameSpace_attributes *nsinfo = PARROT_NAMESPACE(ns); 884 VTABLE_unshift_string(INTERP, ar, nsinfo->name); 885 ns = nsinfo->parent; 886 ++elements; 887 } 888 889 /* remove the NULL string of the namespace root */ 890 if (elements > 0) 891 VTABLE_shift_string(INTERP, ar); 892 893 RETURN(PMC *ar); 894 } 895/* 896 897=item C<METHOD find_namespace(STRING *name)> 898 899Return the namespace with the given name. 900 901=cut 902 903*/ 904 905 METHOD find_namespace(STRING *key) :no_wb { 906 STRING * const s_ns = CONST_STRING(INTERP, "NameSpace"); 907 PMC * const ns = (PMC *)Parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(), 908 key); 909 910 if (!ns) 911 RETURN(PMC *PMCNULL); 912 913 /* it's a NameSpace */ 914 if (VTABLE_isa(INTERP, ns, s_ns)) 915 RETURN(PMC *ns); 916 917 RETURN(PMC *PMCNULL); 918 } 919 920/* 921 922=item C<METHOD find_sub(STRING *name)> 923 924Return the Sub PMC with the given name. 925 926=cut 927 928*/ 929 930 METHOD find_sub(STRING *key) :no_wb { 931 STRING * const s_sub = CONST_STRING(INTERP, "Sub"); 932 PMC * const sub = (PMC *)Parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(), 933 key); 934 935 if (!sub) 936 RETURN(PMC *PMCNULL); 937 938 /* it's a Sub */ 939 if (VTABLE_isa(INTERP, sub, s_sub)) 940 RETURN(PMC *sub); 941 942 RETURN(PMC *PMCNULL); 943 } 944 945/* 946 947=item C<METHOD find_var(STRING *name)> 948 949Return the PMC with the given name. 950 951=cut 952 953*/ 954 955 METHOD find_var(STRING *key) :no_wb { 956 PMC * const val = (PMC *)Parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(), key); 957 958 if (!val) 959 RETURN(PMC *PMCNULL); 960 961 RETURN(PMC *val); 962 } 963 964/* 965 966=item C<METHOD del_namespace(STRING *name)> 967 968Deletes the contained NameSpace PMC with the given name. Throws an invalid 969type exception if the item to delete is not a NameSpace PMC or subclass, and 970does not delete the PMC. 971 972=cut 973 974*/ 975 976 METHOD del_namespace(STRING *name) { 977 Hash * const hash = (Hash *)SELF.get_pointer(); 978 PMC * const ns = (PMC *)Parrot_hash_get(INTERP, hash, name); 979 STRING * const s_ns = CONST_STRING(INTERP, "NameSpace"); 980 981 if (PMC_IS_NULL(ns)) 982 RETURN(void); 983 984 if (!VTABLE_isa(INTERP, ns, s_ns)) 985 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 986 "Invalid type %d for '%Ss' in del_namespace()", 987 ns->vtable->base_type, name); 988 989 Parrot_hash_delete(INTERP, hash, name); 990 } 991 992/* 993 994=item C<METHOD del_sub(STRING *name)> 995 996Deletes the contained Sub PMC with the given name. Throws an invalid type 997exception if the item to delete is not a Sub PMC or subclass, and does not 998delete the PMC. 999 1000=cut 1001 1002*/ 1003 1004 METHOD del_sub(STRING *name) { 1005 Hash * const hash = (Hash *)SELF.get_pointer(); 1006 PMC * const sub = (PMC *)Parrot_hash_get(INTERP, hash, name); 1007 STRING * const s_sub = CONST_STRING(INTERP, "Sub"); 1008 1009 if (PMC_IS_NULL(sub)) 1010 RETURN(void); 1011 1012 if (!VTABLE_isa(INTERP, sub, s_sub)) 1013 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 1014 "Invalid type %d for '%Ss' in del_sub()", 1015 sub->vtable->base_type, name); 1016 1017 Parrot_hash_delete(INTERP, hash, name); 1018 } 1019 1020/* 1021 1022=item C<METHOD del_var(STRING *name)> 1023 1024Deletes the contained variable-like PMC with the given name. 1025 1026=cut 1027 1028*/ 1029 1030 METHOD del_var(STRING *name) { 1031 Parrot_hash_delete(INTERP, (Hash *)SELF.get_pointer(), name); 1032 } 1033 1034/* 1035 1036=item C<METHOD get_sym(STRING *name)> 1037 1038Return the symbol (var or sub) with the given name. This can be used 1039to retrieve symbols, if a NameSpace with the same name exists. 1040 1041=cut 1042 1043*/ 1044 1045 METHOD get_sym(STRING *key) :no_wb { 1046 PMC *ns = (PMC *)Parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(), key); 1047 1048 if (!ns) 1049 RETURN(PMC *PMCNULL); 1050 1051 /* it's a NameSpace */ 1052 if (ns->vtable == SELF->vtable) 1053 RETURN(PMC *PMCNULL); 1054 1055 if ((PObj_get_FLAGS(ns) & FPA_is_ns_ext) 1056 && ns->vtable->base_type == enum_class_FixedPMCArray) 1057 ns = VTABLE_get_pmc_keyed_int(INTERP, ns, NS_slot_var_sub); 1058 1059 RETURN(PMC *ns); 1060 } 1061 1062/* 1063 1064=item C<METHOD export_to(PMC *dest, PMC *what)> 1065 1066Export items from this NameSpace into the C<dest> NameSpace. The items to 1067export are named in C<what>, which may be an array of strings, a hash, or null. 1068If C<what> is an array of strings, interpretation of items in an array follows 1069the conventions of the source (exporting) namespace. 1070If C<what> is a hash, the keys correspond to the names in the source namespace, 1071and the values correspond to the names in the destination namespace. 1072if a hash value is null or an empty string, the name in the hash key is used. 1073A null C<what> requests the 'default' set of items. 1074Any other type passed in C<what> throws an exception. 1075 1076NOTE: exporting 'default' set of items is not yet implemented. 1077 1078=cut 1079 1080*/ 1081 1082 METHOD export_to(PMC *dest, PMC *what) :no_wb { 1083 STRING * const s_hash = CONST_STRING(INTERP, "hash"); 1084 STRING * const s_array = CONST_STRING(INTERP, "array"); 1085 1086 if (PMC_IS_NULL(dest)) 1087 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION, 1088 "destination namespace not specified"); 1089 1090 if (PMC_IS_NULL(what) || !VTABLE_elements(INTERP, what)) 1091 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_UNIMPLEMENTED, 1092 "exporting default object set not yet implemented"); 1093 1094 /* if "what" does "hash", we extract string key/value pairs, 1095 * lookup the object with the name specified in the key, 1096 * and export it with the name specified as value. */ 1097 if (VTABLE_does(INTERP, what, s_hash)) { 1098 PMC * const iter = VTABLE_get_iter(INTERP, what); 1099 const INTVAL n = VTABLE_elements(INTERP, what); 1100 INTVAL i; 1101 1102 for (i = 0; i < n; ++i) { 1103 STRING *dest_name; 1104 PMC *object; 1105 STRING * const src_name = VTABLE_shift_string(INTERP, iter); 1106 1107 if (STRING_IS_NULL(src_name) || STRING_IS_EMPTY(src_name)) 1108 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION, 1109 "source object name not specified"); 1110 1111 if (PMC_IS_NULL(VTABLE_get_pmc_keyed_str(INTERP, what, src_name))) { 1112 dest_name = src_name; 1113 } 1114 else { 1115 dest_name = VTABLE_get_string_keyed_str(INTERP, what, src_name); 1116 if (STRING_IS_NULL(dest_name) || STRING_IS_EMPTY(dest_name)) 1117 dest_name = src_name; 1118 } 1119 1120 object = VTABLE_get_pmc_keyed_str(INTERP, SELF, src_name); 1121 1122 if (PMC_IS_NULL(object)) 1123 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_GLOBAL_NOT_FOUND, 1124 "object '%Ss' not found in current namespace", src_name); 1125 1126 VTABLE_set_pmc_keyed_str(INTERP, dest, dest_name, object); 1127 } 1128 } 1129 else if (VTABLE_does(INTERP, what, s_array)) { 1130 const INTVAL n = VTABLE_elements(INTERP, what); 1131 INTVAL i; 1132 1133 for (i = 0; i < n; ++i) { 1134 PMC *object; 1135 STRING * const name = VTABLE_get_string_keyed_int(INTERP, what, i); 1136 1137 if (STRING_IS_NULL(name) || STRING_IS_EMPTY(name)) 1138 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION, 1139 "object name not specified"); 1140 1141 object = VTABLE_get_pmc_keyed_str(INTERP, SELF, name); 1142 1143 if (PMC_IS_NULL(object)) 1144 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_GLOBAL_NOT_FOUND, 1145 "object '%Ss' not found in current namespace", name); 1146 1147 VTABLE_set_pmc_keyed_str(INTERP, dest, name, object); 1148 } 1149 } 1150 else 1151 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 1152 "can't handle argument of type %Ss", what->vtable->whoami); 1153 } 1154 1155/* 1156 1157=item C<METHOD get_parent()> 1158 1159Return the parent NameSpace or PMCNULL, if none. 1160 1161=cut 1162 1163*/ 1164 1165 METHOD get_parent() :no_wb { 1166 PMC * const parent = PARROT_NAMESPACE(SELF)->parent ? 1167 PARROT_NAMESPACE(SELF)->parent : PMCNULL; 1168 RETURN(PMC *parent); 1169 } 1170 1171/* 1172 1173=item C<METHOD get_class()> 1174 1175Returns the class or role PMC that is associated with this namespace. 1176 1177=cut 1178 1179*/ 1180 1181 METHOD get_class() :no_wb { 1182 const Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF); 1183 PMC *ret_class = nsinfo->_class; 1184 1185 if (PMC_IS_NULL(ret_class)) 1186 ret_class = PMCNULL; 1187 1188 RETURN(PMC *ret_class); 1189 } 1190 1191/* 1192 1193=item C<METHOD set_class(PMC *class_or_role)> 1194 1195Sets the class or role PMC that is associated with this namespace. 1196 1197=cut 1198 1199*/ 1200 1201 METHOD set_class(PMC *class_or_role) { 1202 PARROT_ASSERT_INTERP(class_or_role, INTERP); 1203 PARROT_NAMESPACE(SELF)->_class = class_or_role; 1204 } 1205 1206/* 1207 1208=item C<METHOD get_associated_methods()> 1209 1210Gets the Hash of methods associated with this namespace and removes it from 1211the namespace. 1212 1213=cut 1214 1215*/ 1216 1217 METHOD get_associated_methods() :no_wb { 1218 Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF); 1219 PMC * const ret_methods = nsinfo->methods; 1220 1221 nsinfo->methods = PMCNULL; 1222 1223 RETURN(PMC *ret_methods); 1224 } 1225 1226/* 1227 1228=item C<METHOD get_associated_vtable_methods()> 1229 1230Gets the Hash of vtables associated with this namespace and removes it 1231from the namespace. 1232 1233=cut 1234 1235*/ 1236 1237 METHOD get_associated_vtable_methods() :no_wb { 1238 Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF); 1239 PMC * const ret_methods = nsinfo->vtable; 1240 1241 nsinfo->vtable = PMCNULL; 1242 1243 RETURN(PMC *ret_methods); 1244 } 1245 1246} 1247 1248/* 1249 1250=back 1251 1252=head1 SEE ALSO 1253 1254F<docs/pdds/pdd21_namespaces.pod> 1255 1256=cut 1257 1258*/ 1259 1260/* 1261 * Local variables: 1262 * c-file-style: "parrot" 1263 * End: 1264 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' : 1265 */ 1266