fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pmc / namespace.pmc
blobbb7d345356208a262ef146061aa010ffbfb80ab5
1 /*
2 Copyright (C) 2005-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/namespace.pmc - NameSpace PMC
9 =head1 DESCRIPTION
11 These are the vtable functions for the namespace PMC.
13 =head2 Functions
15 =over 4
17 =cut
21 #include "pmc/pmc_sub.h"
23 /* HEADERIZER HFILE: none */
24 /* HEADERIZER BEGIN: static */
25 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
27 static 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);
35 static 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);
43 static 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);
55 PARROT_WARN_UNUSED_RESULT
56 static 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);
65 PARROT_WARN_UNUSED_RESULT
66 static 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);
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 */
103 =item C<static void add_to_class(PARROT_INTERP, Parrot_NameSpace_attributes
104 *nsinfo, PMC *classobj, STRING *key, PMC *value)>
106 =cut
110 static void
111 add_to_class(PARROT_INTERP, ARGMOD(Parrot_NameSpace_attributes *nsinfo),
112         ARGMOD_NULLOK(PMC *classobj), ARGIN(STRING *key), ARGIN(PMC *value))
114     ASSERT_ARGS(add_to_class)
116     /* Insert it in class, if there is a class */
117     if (!PMC_IS_NULL(classobj) && PObj_is_class_TEST(classobj))
118         VTABLE_add_method(interp, classobj, key, value);
120     /* Otherwise, store it in the namespace for the class to
121      * retrieve later */
122     else {
123         /* If we don't have a place to hang methods, make one. */
124         if (PMC_IS_NULL(nsinfo->methods))
125             nsinfo->methods = Parrot_pmc_new(interp, enum_class_Hash);
127         /* Insert it. */
128         VTABLE_set_pmc_keyed_str(interp, nsinfo->methods, key, value);
129     }
134 =item C<static int ns_insert_sub_keyed_str(PARROT_INTERP, PMC *self, STRING
135 *key, PMC *value)>
137 =cut
141 PARROT_WARN_UNUSED_RESULT
142 static int
143 ns_insert_sub_keyed_str(PARROT_INTERP, ARGIN(PMC *self), ARGIN(STRING *key),
144         ARGIN(PMC *value))
146     ASSERT_ARGS(ns_insert_sub_keyed_str)
148     Parrot_NameSpace_attributes * const nsinfo   = PARROT_NAMESPACE(self);
149     PMC              *       vtable   = nsinfo->vtable;
150     PMC              * const classobj = VTABLE_get_class(interp, self);
151     STRING           * vtable_key     = STRINGNULL;
152     Parrot_Sub_attributes *sub;
153     INTVAL stored = 0;
155     PMC_get_sub(interp, value, sub);
157     if (sub->vtable_index != -1) {
158         /* Insert it in class, if there is a class */
159         if (!PMC_IS_NULL(classobj) && PObj_is_class_TEST(classobj)) {
160             const char * const vtable_key_c =
161                 Parrot_get_vtable_name(interp, sub->vtable_index);
162             PARROT_ASSERT(vtable_key_c);
163             vtable_key = Parrot_str_new(interp, vtable_key_c,
164                 strlen(vtable_key_c));
165             VTABLE_add_vtable_override(interp, classobj, vtable_key, value);
166         }
168         /* Otherwise, store it in the namespace for the class to
169          * retrieve later */
170         else {
171             /* If we don't have a place to hang vtables, make one. */
172             if (PMC_IS_NULL(vtable))
173                 nsinfo->vtable = vtable = Parrot_pmc_new(interp, enum_class_Hash);
175             /* Insert it. */
176             VTABLE_set_pmc_keyed_int(interp, vtable, sub->vtable_index, value);
177         }
178         if (!(sub->comp_flags & SUB_COMP_FLAG_NSENTRY))
179             stored = 1;
180     }
182     if (sub->comp_flags & SUB_COMP_FLAG_METHOD) {
183         STRING *method_name = key;
185         if (Parrot_str_equal(interp, sub->method_name, CONST_STRING(interp, ""))) {
186             if (sub->vtable_index != -1 && !STRING_IS_NULL(vtable_key)) {
187                 method_name = vtable_key;
188             }
189         }
190         else {
191             method_name = sub->method_name;
192         }
193         add_to_class(interp, nsinfo, classobj, method_name, value);
195         if (!(sub->comp_flags & SUB_COMP_FLAG_NSENTRY))
196             stored = 1;
197     }
199     return stored;
204 =item C<static int maybe_add_sub_to_namespace(PARROT_INTERP, PMC *SELF, STRING
205 *key, PMC *value)>
207 =cut
211 PARROT_WARN_UNUSED_RESULT
212 static int
213 maybe_add_sub_to_namespace(PARROT_INTERP, ARGIN(PMC *SELF), ARGIN(STRING *key),
214         ARGIN(PMC *value))
216     ASSERT_ARGS(maybe_add_sub_to_namespace)
218     STRING * const sub_str = CONST_STRING(interp, "Sub");
220     if (!PMC_IS_NULL(value)
221     &&   VTABLE_isa(interp, value, sub_str)
222     &&   value->vtable->base_type != enum_class_Object)
223         return ns_insert_sub_keyed_str(interp, SELF, key, value);
225     return 0;
230 =item C<static void add_nci_to_namespace(PARROT_INTERP, PMC *SELF, STRING *key,
231 PMC *value)>
233 =cut
237 static void
238 add_native_to_namespace(PARROT_INTERP, ARGIN(PMC *SELF), ARGIN(STRING *key),
239         ARGIN_NULLOK(PMC *value))
241     ASSERT_ARGS(add_native_to_namespace)
243     if (!PMC_IS_NULL(value)
244     && (value->vtable->base_type == enum_class_NativePCCMethod ||
245         value->vtable->base_type == enum_class_NCI)) {
246         Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF);
247         PMC * const classobj = VTABLE_get_class(interp, SELF);
249         /* Insert it in class, if there is a class */
250         add_to_class(interp, nsinfo, classobj, key, value);
251     }
256 =item C<static void add_multi_to_namespace(PARROT_INTERP, PMC *SELF, STRING
257 *key, PMC *value)>
259 =cut
263 static void
264 add_multi_to_namespace(PARROT_INTERP, ARGIN(PMC *SELF), ARGIN(STRING *key),
265         ARGIN_NULLOK(PMC *value))
267     ASSERT_ARGS(add_multi_to_namespace)
269     STRING * const multi_str = CONST_STRING(interp, "MultiSub");
271     if (!PMC_IS_NULL(value)
272     &&   VTABLE_isa(interp, value, multi_str)) {
274         /* TT #10; work around that Sub doesn't use PMC ATTRs */
275         if (value->vtable->base_type != enum_class_Object
276         &&  VTABLE_elements(interp, value) > 0) {
277             Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF);
278             PMC * const classobj = VTABLE_get_class(interp, SELF);
280             /* Extract the first alternate and check if it is a method */
281             PMC * const pmc_sub = VTABLE_get_pmc_keyed_int(interp, value, 0);
282             Parrot_Sub_attributes *sub;
283             PMC_get_sub(interp, pmc_sub, sub);
285             if (sub->comp_flags & SUB_COMP_FLAG_METHOD) {
286                 STRING * const empty_str   = CONST_STRING(interp, "");
287                 STRING *method_name = key;
288                 Hash   *hash;
290                 if (Parrot_str_not_equal(interp, sub->method_name, empty_str))
291                     method_name = sub->method_name;
293                 add_to_class(interp, nsinfo, classobj, method_name, value);
295                 GETATTR_NameSpace_hash(interp, SELF, hash);
297                 parrot_hash_put(interp, hash,
298                     hash_key_from_string(interp, hash, key),
299                     hash_value_from_pmc(interp, hash, value));
300             }
301         }
302     }
307  * Typically a named slot contains either another namespace or a
308  * var/sub (not both).
309  * In case that the bucket->value is occupied, a FixedPMCArray is
310  * created, and the items are moved over to that extra storage.
311  * The array is flagged with FPA_is_ns_ext to distinguish it from a
312  * plain array variable.
314  * This could easily expand to a full-fledged typed namespace if needed.
315  */
317 typedef enum {
318     NS_slot_ns,
319     NS_slot_var_sub,         /* unspecified ~half-raw slot */
320     NS_max_slots
321 } NS_slot_enum;
323 #define FPA_is_ns_ext PObj_private0_FLAG
325 pmclass NameSpace extends Hash provides hash no_ro auto_attrs {
327     ATTR STRING *name;     /* Name of this namespace part. */
328     ATTR PMC    *_class;   /* The class or role attached to this namespace. */
329     ATTR PMC    *methods;  /* A Hash of methods, keyed on the method name. This
330                             * goes away when the methods are sucked in by a
331                             * class. */
332     ATTR PMC    *vtable;   /* A Hash of vtable subs, keyed on the vtable index */
333     ATTR PMC    *parent;   /* This NameSpace's parent NameSpace */
337 =item C<void init()>
339 Initialize a C<NameSpace> PMC.
341 =cut
345     VTABLE void init() {
346         PARROT_NAMESPACE(SELF)->vtable  = PMCNULL;
347         PARROT_NAMESPACE(SELF)->methods = PMCNULL;
348         PARROT_NAMESPACE(SELF)->_class  = PMCNULL;
349         SELF.set_pointer(parrot_new_hash(INTERP));
350         PObj_custom_mark_destroy_SETALL(SELF);
351     }
355 =item C<void mark()>
357 Marks the namespace as live.
359 =cut
362     VTABLE void mark() {
363         Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF);
365         if (nsinfo->hash)
366             parrot_mark_hash(INTERP, nsinfo->hash);
368         Parrot_gc_mark_PMC_alive(INTERP, nsinfo->parent);
369         Parrot_gc_mark_PMC_alive(INTERP, nsinfo->_class);
370         Parrot_gc_mark_PMC_alive(INTERP, nsinfo->vtable);
371         Parrot_gc_mark_PMC_alive(INTERP, nsinfo->methods);
372         Parrot_gc_mark_STRING_alive(INTERP, nsinfo->name);
373     }
377 =item C<PMC *get_class()>
379 Returns the class or role PMC that is associated with this namespace.
381 =cut
385     PMC *get_class() {
386         return PARROT_NAMESPACE(SELF)->_class;
387     }
391 =item C<void set_pmc_keyed_str(STRING *key, PMC *value)>
393 Sets C<*value> as the namespace item for C<*key>. This is part of the
394 raw interface. If the PMC C<value> is exactly a NameSpace, C<SELF>
395 will be set as the parent of that namespace and the name C<key> of
396 C<value> is stored too.
398 =item C<void set_pmc_keyed(PMC *key, PMC *value)>
400 If C<key> is a simple key, it works like above. If C<key> is an array
401 of strings or a chained key, add all components to the namespace.
403 =item C<PMC *get_pmc_keyed(PMC *key)>
405 Return the given namespace or PMCNULL. C<key> is either an array of
406 strings, or a possibly nested key.
408 =item C<PMC *get_pmc_keyed_str(STRING *key)>
410 Return the given namespace item or PMCNULL. If the named item is either
411 a NameSpace or a var, the NameSpace is returned.
413 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
415 Return a Sub representing an overridden vtable entry or PMCNULL.  This is not
416 really a public API.
418 =cut
422     VTABLE void set_pmc_keyed_str(STRING *key, PMC *value) {
423         PMC        *new_tuple = NULL;
424         const int   val_is_NS = PMC_IS_NULL(value)
425                               ? 0
426                               :value->vtable->base_type == enum_class_NameSpace;
428         /* don't need this everywhere yet */
429         PMC *old;
431         /* If it's a sub... */
432         if (maybe_add_sub_to_namespace(INTERP, SELF, key, value))
433             return;
435         /* If it's an native method */
436         add_native_to_namespace(INTERP, SELF, key, value);
438         /* If it's a multi-sub and the first in this NS... */
439         add_multi_to_namespace(INTERP, SELF, key, value);
441         old = (PMC *)parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(), key);
443         if (!old)
444             SUPER(key, value);
445         else {
446             if ((old->vtable->base_type == enum_class_NameSpace) == val_is_NS) {
447                 /* simple ns or simple var/sub changed */
448                 SUPER(key, value);
449             }
450             else if ((PObj_get_FLAGS(old) & FPA_is_ns_ext) &&
451                     old->vtable->base_type == enum_class_FixedPMCArray) {
452                 /* we have a tuple extension already */
453                 VTABLE_set_pmc_keyed_int(INTERP, old,
454                         val_is_NS ? NS_slot_ns : NS_slot_var_sub,
455                         value);
456             }
457             else {
458                 /* create new tuple */
459                 /* for a fully typed namespace, we'd need 3 or 4 */
460                 new_tuple = Parrot_pmc_new_init_int(INTERP,
461                         enum_class_FixedPMCArray, NS_max_slots);
463                 /* flag it as special */
464                 PObj_get_FLAGS(new_tuple) |= FPA_is_ns_ext;
465             }
466         }
468         if (val_is_NS) {
469             /* TODO - this hack needs to go */
470             Parrot_NameSpace_attributes *nsinfo = PARROT_NAMESPACE(value);
471             nsinfo->parent = SELF;  /* set parent */
472             nsinfo->name   = key;   /* and name */
474             if (new_tuple) {
475                 VTABLE_set_pmc_keyed_int(INTERP, new_tuple, NS_slot_ns, value);
476                 VTABLE_set_pmc_keyed_int(INTERP, new_tuple, NS_slot_var_sub,
477                                          old);
479                 parrot_hash_put(INTERP, (Hash *)SELF.get_pointer(), key, new_tuple);
480                 /* distinction from a plain FPA, which doesn't extend the
481                  * namespace storage */
482             }
483         }
484         else if (new_tuple) {
485             VTABLE_set_pmc_keyed_int(INTERP, new_tuple, NS_slot_ns, old);
486             VTABLE_set_pmc_keyed_int(INTERP, new_tuple, NS_slot_var_sub, value);
487             parrot_hash_put(INTERP, (Hash *)SELF.get_pointer(), key, new_tuple);
488         }
489     }
491     VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
492         PMC *ns = SELF;
494         if (key->vtable->base_type == enum_class_String) {
495             SELF.set_pmc_keyed_str(VTABLE_get_string(INTERP, key), value);
496             return;
497         }
499         if (key->vtable->base_type == enum_class_Key) {
500             while (1) {
501                 STRING * const part = VTABLE_get_string(INTERP, key);
502                 key                 = VTABLE_shift_pmc(INTERP, key);
504                 if (!key) {
505                     Parrot_ns_set_global(INTERP, ns, part, value);
506                     return;
507                 }
509                 ns = Parrot_ns_make_namespace_keyed_str(INTERP, ns, part);
510             }
511         }
513         if (key->vtable->base_type == enum_class_ResizableStringArray) {
514             const INTVAL elements = VTABLE_elements(INTERP, key);
515             INTVAL i;
516             for (i = 0; i < elements; ++i)  {
517                 STRING * const part = VTABLE_get_string_keyed_int(INTERP, key, i);
519                 if ((i + 1) >= elements) { /* Last entry in the array */
520                     Parrot_ns_set_global(INTERP, ns, part, value);
521                     return;
522                 }
524                 ns = Parrot_ns_make_namespace_keyed_str(INTERP, ns, part);
525             }
526         }
528         Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_GLOBAL_NOT_FOUND,
529             "Invalid namespace key in set_pmc_keyed");
530     }
532     VTABLE PMC *get_pmc_keyed_str(STRING *key) {
533         Hash * const hash = (Hash *)SELF.get_pointer();
534         PMC *ns = (PMC *)parrot_hash_get(INTERP, hash, key);
536         if (!ns)
537             return PMCNULL;
539         if ((PObj_get_FLAGS(ns) & FPA_is_ns_ext) &&
540                 ns->vtable->base_type == enum_class_FixedPMCArray)
541             ns = VTABLE_get_pmc_keyed_int(INTERP, ns, NS_slot_ns);
543         return ns;
544     }
546     VTABLE PMC *get_pmc_keyed(PMC *key) {
547         PMC *ns = SUPER(key);
548         /* Is this equivalent?
549         PMC    *ns = INTERP->vtables[enum_class_Hash]->get_pmc_keyed(INTERP, SELF, key);
550         */
552         if (!PMC_IS_NULL(ns))
553             return ns;
555         ns = SELF;
557         if (key->vtable->base_type == enum_class_Key) {
558             STRING * const part = VTABLE_get_string(INTERP, key);
559             key                 = VTABLE_shift_pmc(INTERP, key);
561             if (!key)
562                 return VTABLE_get_pmc_keyed_str(INTERP, ns, part);
564             ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, part);
566             if (PMC_IS_NULL(ns))
567                 return PMCNULL;
569             return VTABLE_get_pmc_keyed(INTERP, ns, key);
570         }
571         else if (VTABLE_does(INTERP, key, CONST_STRING(INTERP, "array"))) {
572             INTVAL i = 0;
573             while (!PMC_IS_NULL(ns) && VTABLE_elements(INTERP, key)) {
574                 STRING * const name = VTABLE_get_string_keyed_int(INTERP, key, i);
575                 if (STRING_IS_NULL(name)) {
576                     ns = PMCNULL;
577                     /* What to do here? Throw an exception or something? */
578                     break;
579                 }
580                 ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, name);
581                 ++i;
582             }
583             return ns;
584         }
585         else {
586             STRING * const name = VTABLE_get_string(INTERP, key);
587             ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, name);
588             return ns;
589         }
590         /* If we get the wrong type, should we throw an exception?
591         Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_GLOBAL_NOT_FOUND,
592             "Invalid namespace key in get_pmc_keyed_str");
593         */
594     }
596     VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
597         Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF);
598         PMC              * const vtable = nsinfo->vtable;
600         if (PMC_IS_NULL(vtable))
601             return PMCNULL;
603         return VTABLE_get_pmc_keyed_int(INTERP, vtable, key);
604     }
608 =item C<void *get_pointer_keyed_str(STRING *key)>
610 =item C<void *get_pointer_keyed(PMC *key)>
612 Return the given namespace item or PMCNULL. If the named item is either
613 a NameSpace or a var, the var is returned.
615 TT #1472
616 TOTAL KLUDGE.  ON THE CHOPPING BLOCK.
618 =cut
622     VTABLE void *get_pointer_keyed_str(STRING *key) {
623         PMC *ns = (PMC *)parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(), key);
625         /* Be extra careful about returning PMCNULL */
626         if (! PMC_IS_NULL(ns)) {
627             if ((PObj_get_FLAGS(ns) & FPA_is_ns_ext) &&
628                     ns->vtable->base_type == enum_class_FixedPMCArray)
629                 ns = VTABLE_get_pmc_keyed_int(INTERP, ns, NS_slot_var_sub);
630         }
631         if (PMC_IS_NULL(ns))
632             ns = PMCNULL;
633         return ns;
634     }
636     VTABLE void *get_pointer_keyed(PMC *key) {
637         PMC    *ns = SELF;
639         if (PMC_IS_NULL(key))
640             return PMCNULL;
642         switch (key->vtable->base_type) {
643             case enum_class_String:
644                 return SELF.get_pointer_keyed_str(VTABLE_get_string(INTERP, key));
645             case enum_class_Key: {
646                 /* this loop (and function) could use a rewrite for clarity */
647                 while (1) {
648                     STRING * const part = VTABLE_get_string(INTERP, key);
649                     key                 = VTABLE_shift_pmc(INTERP, key);
651                     if (!key)
652                         return VTABLE_get_pointer_keyed_str(INTERP, ns, part);
654                     ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, part);
656                     if (PMC_IS_NULL(ns))
657                         return PMCNULL;
658                 }
659             }
660             case enum_class_ResizableStringArray: {
661                 const INTVAL elements = VTABLE_elements(INTERP, key);
662                 INTVAL i;
663                 for (i = 0; i < elements; ++i)  {
664                     STRING * const part = VTABLE_get_string_keyed_int(INTERP, key, i);
666                     /* Last entry in the array */
667                     if ((i + 1) >= elements)
668                         return VTABLE_get_pointer_keyed_str(INTERP, ns, part);
670                     ns = Parrot_ns_get_namespace_keyed_str(INTERP, ns, part);
672                     if (PMC_IS_NULL(ns))
673                         return PMCNULL;
674                 }
675                 return ns;
676             }
677             default:
678                 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_GLOBAL_NOT_FOUND,
679                     "Invalid namespace key of type '%S' in get_pointer_keyed",
680                     key->vtable->whoami);
681         }
682     }
686 =item C<STRING *get_string()>
688 Return the name of this namespace part.
690 =cut
694     VTABLE STRING *get_string() {
695         const Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF);
696         return nsinfo->name;
697     }
701 =item C<PMC *inspect_str(STRING *what)>
703 Provides introspection of a specific piece of information about the
704 namespace. The available information is:
706 =over 8
708 =item class
710 The class object associated with the namespace, if any.
712 =item methods
714 A temporary cache of methods (destroyed when class object is created).
715 Hash keyed on method name, value is an invokable PMC. Includes methods
716 composed in from roles.
718 =item vtable_overrides
720 A temporary cache of vtable overrides (destroyed when class object is
721 created). Hash keyed on vtable name, value is an invokable PMC.
722 Includes vtable overrides composed in from roles.
724 =back
726 =cut
730     VTABLE PMC *inspect_str(STRING *what) {
731         const Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF);
732         PMC *found;
734         if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "methods"))) {
735             found = nsinfo->methods;
736         }
737         else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "vtable_overrides"))) {
738             found = nsinfo->vtable;
739         }
740         else if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "class"))) {
741             found = nsinfo->_class;
742         }
743         else
744             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
745                 "Unknown introspection value '%S'", what);
747         /* return found value */
748         if (PMC_IS_NULL(found))
749             return PMCNULL;
751         return found;
752     }
756 =back
758 =head2 Methods
760 =over 4
762 =cut
768 =item C<METHOD make_namespace(PMC* key)>
770 Create and retrieve the namespace given by C<key>.  If the namespace
771 already exists, only retrieve it.
773 =cut
777     METHOD make_namespace(PMC *key) {
778         PMC *ns = Parrot_ns_get_namespace_keyed(INTERP, SELF, key);
779         if (PMC_IS_NULL(ns)) {
780             ns = Parrot_ns_make_namespace_keyed(INTERP, SELF, key);
781         }
782         RETURN(PMC *ns);
783     }
787 =item C<METHOD add_namespace(STRING *name, PMC *namespace)>
789 Stores the given namespace under this namespace, with the given name.  Throws
790 an invalid type exception if C<namespace> is not a NameSpace PMC or subclass.
792 =cut
796     METHOD add_namespace(STRING *name, PMC *_namespace) {
797         STRING * const s_ns = CONST_STRING(INTERP, "NameSpace");
799         if (!VTABLE_isa(INTERP, _namespace, s_ns))
800             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
801                 "Invalid type %d in add_namespace()",
802                 _namespace->vtable->base_type);
804         VTABLE_set_pmc_keyed_str(INTERP, SELF, name, _namespace);
805     }
809 =item C<METHOD add_sub(STRING *name, PMC *sub)>
811 Stores the given sub under this namespace, with the given name.  Throws an
812 invalid type exception if C<sub> is not a Sub PMC or subclass.
814 =cut
818     METHOD add_sub(STRING *name, PMC *sub) {
819         STRING * const s_sub      = CONST_STRING(INTERP, "Sub");
820         STRING * const s_multisub = CONST_STRING(INTERP, "MultiSub");
822         if (!VTABLE_isa(INTERP, sub, s_sub)
823         &&  !VTABLE_isa(INTERP, sub, s_multisub))
824             Parrot_ex_throw_from_c_args(INTERP, NULL,
825                 EXCEPTION_INVALID_OPERATION,
826                 "Invalid type %d in add_sub()", sub->vtable->base_type);
828         VTABLE_set_pmc_keyed_str(INTERP, SELF, name, sub);
829     }
833 =item C<METHOD add_var(STRING *name, PMC *var)>
835 Stores the given variable under this namespace, with the given name.
837 =cut
841     METHOD add_var(STRING *name, PMC *var) {
842         VTABLE_set_pmc_keyed_str(INTERP, SELF, name, var);
843     }
847 =item C<METHOD get_name()>
849 Returns the name of the namespace as an array of strings.
851   $P2 = $P3.'get_name'()
852   $S0 = join '::', $P2            # '::Foo::Bar'
854 =cut
858     METHOD get_name() {
859         PMC * const ar = Parrot_pmc_new(INTERP, enum_class_ResizableStringArray);
860         INTVAL elements = 0;
861         PMC *ns        = SELF;
863         while (ns) {
864             Parrot_NameSpace_attributes *nsinfo = PARROT_NAMESPACE(ns);
865             VTABLE_unshift_string(INTERP, ar, nsinfo->name);
866             ns = nsinfo->parent;
867             ++elements;
868         }
870         /* remove the NULL string of the namespace root */
871         if (elements > 0)
872             VTABLE_shift_string(INTERP, ar);
874         RETURN(PMC *ar);
875     }
878 =item C<METHOD find_namespace(STRING *name)>
880 Return the namespace with the given name.
882 =cut
886     METHOD find_namespace(STRING *key) {
887         STRING * const s_ns = CONST_STRING(INTERP, "NameSpace");
888         PMC    * const ns   = (PMC *)parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(),
889                                                      key);
891         if (!ns)
892             RETURN(PMC *PMCNULL);
894         /* it's a NameSpace */
895         if (VTABLE_isa(INTERP, ns, s_ns))
896             RETURN(PMC *ns);
898         RETURN(PMC *PMCNULL);
899     }
903 =item C<METHOD find_sub(STRING *name)>
905 Return the Sub PMC with the given name.
907 =cut
911     METHOD find_sub(STRING *key) {
912         STRING * const s_sub = CONST_STRING(INTERP, "Sub");
913         PMC    * const sub   = (PMC *)parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(),
914                                                       key);
916         if (!sub)
917             RETURN(PMC *PMCNULL);
919         /* it's a Sub */
920         if (VTABLE_isa(INTERP, sub, s_sub))
921             RETURN(PMC *sub);
923         RETURN(PMC *PMCNULL);
924     }
928 =item C<METHOD find_var(STRING *name)>
930 Return the PMC with the given name.
932 =cut
936     METHOD find_var(STRING *key) {
937         PMC * const val = (PMC *)parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(), key);
939         if (!val)
940             RETURN(PMC *PMCNULL);
942         RETURN(PMC *val);
943     }
947 =item C<METHOD del_namespace(STRING *name)>
949 Deletes the contained NameSpace PMC with the given name.  Throws an invalid
950 type exception if the item to delete is not a NameSpace PMC or subclass, and
951 does not delete the PMC.
953 =cut
957     METHOD del_namespace(STRING *name) {
958         Hash   * const hash = (Hash *)SELF.get_pointer();
959         PMC    * const ns   = (PMC *)parrot_hash_get(INTERP, hash, name);
960         STRING * const s_ns = CONST_STRING(INTERP, "NameSpace");
962         if (PMC_IS_NULL(ns))
963             RETURN(void);
965         if (!VTABLE_isa(INTERP, ns, s_ns))
966             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
967                 "Invalid type %d for '%Ss' in del_namespace()",
968                 ns->vtable->base_type, name);
970         parrot_hash_delete(INTERP, hash, name);
971     }
975 =item C<METHOD del_sub(STRING *name)>
977 Deletes the contained Sub PMC with the given name.  Throws an invalid type
978 exception if the item to delete is not a Sub PMC or subclass, and does not
979 delete the PMC.
981 =cut
985     METHOD del_sub(STRING *name) {
986         Hash   * const hash  = (Hash *)SELF.get_pointer();
987         PMC    * const sub   = (PMC *)parrot_hash_get(INTERP, hash, name);
988         STRING * const s_sub = CONST_STRING(INTERP, "Sub");
990         if (PMC_IS_NULL(sub))
991             RETURN(void);
993         if (!VTABLE_isa(INTERP, sub, s_sub))
994             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
995                 "Invalid type %d for '%Ss' in del_sub()",
996                 sub->vtable->base_type, name);
998         parrot_hash_delete(INTERP, hash, name);
999     }
1003 =item C<METHOD del_var(STRING *name)>
1005 Deletes the contained variable-like PMC with the given name.
1007 =cut
1011     METHOD del_var(STRING *name) {
1012         parrot_hash_delete(INTERP, (Hash *)SELF.get_pointer(), name);
1013     }
1017 =item C<METHOD get_sym(STRING *name)>
1019 Return the symbol (var or sub) with the given name. This can be used
1020 to retrieve symbols, if a NameSpace with the same name exists.
1022 =cut
1026     METHOD get_sym(STRING *key) {
1027         PMC *ns = (PMC *)parrot_hash_get(INTERP, (Hash *)SELF.get_pointer(), key);
1029         if (!ns)
1030             RETURN(PMC *PMCNULL);
1032         /* it's a NameSpace */
1033         if (ns->vtable == SELF->vtable)
1034             RETURN(PMC *PMCNULL);
1036         if ((PObj_get_FLAGS(ns) & FPA_is_ns_ext)
1037         &&  ns->vtable->base_type == enum_class_FixedPMCArray)
1038             ns = VTABLE_get_pmc_keyed_int(INTERP, ns, NS_slot_var_sub);
1040         RETURN(PMC *ns);
1041     }
1045 =item C<METHOD export_to(PMC *dest, PMC *what)>
1047 Export items from this NameSpace into the C<dest> NameSpace. The items to
1048 export are named in C<what>, which may be an array of strings, a hash, or null.
1049 If C<what> is an array of strings, interpretation of items in an array follows
1050 the conventions of the source (exporting) namespace.
1051 If C<what> is a hash, the keys correspond to the names in the source namespace,
1052 and the values correspond to the names in the destination namespace.
1053 if a hash value is null or an empty string, the name in the hash key is used.
1054 A null C<what> requests the 'default' set of items.
1055 Any other type passed in C<what> throws an exception.
1057 NOTE: exporting 'default' set of items is not yet implemented.
1059 =cut
1063     METHOD export_to(PMC *dest, PMC *what) {
1064         STRING * const s_hash  = CONST_STRING(INTERP, "hash");
1065         STRING * const s_array = CONST_STRING(INTERP, "array");
1067         if (PMC_IS_NULL(dest))
1068             Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
1069                 "destination namespace not specified");
1071         if (PMC_IS_NULL(what) || !VTABLE_elements(INTERP, what))
1072             Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
1073                 "exporting default object set not yet implemented");
1075         /* if "what" does "hash", we extract string key/value pairs,
1076          * lookup the object with the name specified in the key,
1077          * and export it with the name specified as value. */
1078         if (VTABLE_does(INTERP, what, s_hash)) {
1079             PMC * const  iter = VTABLE_get_iter(INTERP, what);
1080             const INTVAL n    = VTABLE_elements(INTERP, what);
1081             INTVAL       i;
1083             for (i = 0; i < n; ++i) {
1084                 STRING *dest_name;
1085                 PMC    *object;
1086                 STRING * const src_name = VTABLE_shift_string(INTERP, iter);
1088                 if (STRING_IS_NULL(src_name) || STRING_IS_EMPTY(src_name))
1089                     Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
1090                         "source object name not specified");
1092                 if (PMC_IS_NULL(VTABLE_get_pmc_keyed_str(INTERP, what, src_name))) {
1093                     dest_name = src_name;
1094                 }
1095                 else {
1096                     dest_name = VTABLE_get_string_keyed_str(INTERP, what, src_name);
1097                     if (STRING_IS_NULL(dest_name) || STRING_IS_EMPTY(dest_name))
1098                         dest_name = src_name;
1099                 }
1101                 object = VTABLE_get_pmc_keyed_str(INTERP, SELF, src_name);
1103                 if (PMC_IS_NULL(object))
1104                     Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
1105                         "object '%Ss' not found in current namespace", src_name);
1107                 VTABLE_set_pmc_keyed_str(INTERP, dest, dest_name, object);
1108             }
1109         }
1110         else if (VTABLE_does(INTERP, what, s_array)) {
1111             const INTVAL n = VTABLE_elements(INTERP, what);
1112             INTVAL       i;
1114             for (i = 0; i < n; ++i) {
1115                 PMC    *object;
1116                 STRING * const name = VTABLE_get_string_keyed_int(INTERP, what, i);
1118                 if (STRING_IS_NULL(name) || STRING_IS_EMPTY(name))
1119                     Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
1120                         "object name not specified");
1122                 object = VTABLE_get_pmc_keyed_str(INTERP, SELF, name);
1124                 if (PMC_IS_NULL(object))
1125                     Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
1126                         "object '%Ss' not found in current namespace", name);
1128                 VTABLE_set_pmc_keyed_str(INTERP, dest, name, object);
1129             }
1130         }
1131         else
1132             Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
1133                 "can't handle argument of type %s", what->vtable->base_type);
1134     }
1138 =item C<METHOD get_parent()>
1140 Return the parent NameSpace or PMCNULL, if none.
1142 =cut
1146     METHOD get_parent() {
1147         PMC *parent = PARROT_NAMESPACE(SELF)->parent ? PARROT_NAMESPACE(SELF)->parent : PMCNULL;
1148         RETURN(PMC *parent);
1149     }
1153 =item C<METHOD get_class()>
1155 Returns the class or role PMC that is associated with this namespace.
1157 =cut
1161     METHOD get_class() {
1162         Parrot_NameSpace_attributes * const nsinfo = PARROT_NAMESPACE(SELF);
1163         PMC              *ret_class     = nsinfo->_class;
1165         if (PMC_IS_NULL(ret_class))
1166             ret_class = PMCNULL;
1168         RETURN(PMC *ret_class);
1169     }
1173 =item C<METHOD set_class(PMC *class_or_role)>
1175 Sets the class or role PMC that is associated with this namespace.
1177 =cut
1181     METHOD set_class(PMC *class_or_role) {
1182         PARROT_NAMESPACE(SELF)->_class = class_or_role;
1183     }
1187 =item C<METHOD get_associated_methods()>
1189 Gets the Hash of methods associated with this namespace and removes it from
1190 the namespace.
1192 =cut
1196     METHOD get_associated_methods() {
1197         Parrot_NameSpace_attributes * const nsinfo      = PARROT_NAMESPACE(SELF);
1198         PMC              * const ret_methods = nsinfo->methods;
1200         nsinfo->methods = PMCNULL;
1202         RETURN(PMC *ret_methods);
1203     }
1207 =item C<METHOD get_associated_vtable_methods()>
1209 Gets the Hash of vtables associated with this namespace and removes it
1210 from the namespace.
1212 =cut
1216     METHOD get_associated_vtable_methods() {
1217         Parrot_NameSpace_attributes * const nsinfo      = PARROT_NAMESPACE(SELF);
1218         PMC              * const ret_methods = nsinfo->vtable;
1220         nsinfo->vtable = PMCNULL;
1222         RETURN(PMC *ret_methods);
1223     }
1229 =back
1231 =head1 SEE ALSO
1233 F<docs/pdds/pdd21_namespaces.pod>
1235 =cut
1240  * Local variables:
1241  *   c-file-style: "parrot"
1242  * End:
1243  * vim: expandtab shiftwidth=4:
1244  */