1 /*
2 Copyright (C) 2004-2010, Parrot Foundation.
3 
4 =head1 NAME
5 
6 src/namespace.c
7 
8 =head1 DESCRIPTION
9 
10 Common routines for storing and finding elements in namespaces
11 
12 =cut
13 
14 */
15 
16 #include "parrot/parrot.h"
17 #include "namespace.str"
18 #include "pmc/pmc_sub.h"
19 #include "pmc/pmc_callcontext.h"
20 
21 /* HEADERIZER HFILE: include/parrot/namespace.h */
22 /* HEADERIZER BEGIN: static */
23 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
24 
25 PARROT_WARN_UNUSED_RESULT
26 PARROT_CANNOT_RETURN_NULL
27 static PMC * get_namespace_pmc(PARROT_INTERP, ARGIN(PMC *sub_pmc))
28         __attribute__nonnull__(1)
29         __attribute__nonnull__(2);
30 
31 PARROT_WARN_UNUSED_RESULT
32 PARROT_CANNOT_RETURN_NULL
33 static PMC * internal_ns_keyed(PARROT_INTERP,
34     ARGIN(PMC *base_ns),
35     ARGIN(PMC *pmc_key),
36     int flags)
37         __attribute__nonnull__(1)
38         __attribute__nonnull__(2)
39         __attribute__nonnull__(3);
40 
41 PARROT_WARN_UNUSED_RESULT
42 PARROT_CANNOT_RETURN_NULL
43 static PMC * internal_ns_keyed_key(PARROT_INTERP,
44     ARGIN(PMC *ns),
45     ARGIN(PMC *key),
46     int flags)
47         __attribute__nonnull__(1)
48         __attribute__nonnull__(2)
49         __attribute__nonnull__(3);
50 
51 PARROT_WARN_UNUSED_RESULT
52 PARROT_CANNOT_RETURN_NULL
53 static PMC * internal_ns_keyed_str(PARROT_INTERP,
54     ARGIN(PMC *base_ns),
55     ARGIN(STRING *key),
56     int flags)
57         __attribute__nonnull__(1)
58         __attribute__nonnull__(2)
59         __attribute__nonnull__(3);
60 
61 PARROT_WARN_UNUSED_RESULT
62 PARROT_CANNOT_RETURN_NULL
63 static PMC * internal_ns_maybe_create(PARROT_INTERP,
64     ARGIN(PMC *ns),
65     ARGIN(STRING *key),
66     int flags)
67         __attribute__nonnull__(1)
68         __attribute__nonnull__(2)
69         __attribute__nonnull__(3);
70 
71 static void store_sub_in_multi(PARROT_INTERP,
72     ARGIN(PMC *sub_pmc),
73     ARGIN(PMC *ns))
74         __attribute__nonnull__(1)
75         __attribute__nonnull__(2)
76         __attribute__nonnull__(3);
77 
78 #define ASSERT_ARGS_get_namespace_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
79        PARROT_ASSERT_ARG(interp) \
80     , PARROT_ASSERT_ARG(sub_pmc))
81 #define ASSERT_ARGS_internal_ns_keyed __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
82        PARROT_ASSERT_ARG(interp) \
83     , PARROT_ASSERT_ARG(base_ns) \
84     , PARROT_ASSERT_ARG(pmc_key))
85 #define ASSERT_ARGS_internal_ns_keyed_key __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
86        PARROT_ASSERT_ARG(interp) \
87     , PARROT_ASSERT_ARG(ns) \
88     , PARROT_ASSERT_ARG(key))
89 #define ASSERT_ARGS_internal_ns_keyed_str __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
90        PARROT_ASSERT_ARG(interp) \
91     , PARROT_ASSERT_ARG(base_ns) \
92     , PARROT_ASSERT_ARG(key))
93 #define ASSERT_ARGS_internal_ns_maybe_create __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
94        PARROT_ASSERT_ARG(interp) \
95     , PARROT_ASSERT_ARG(ns) \
96     , PARROT_ASSERT_ARG(key))
97 #define ASSERT_ARGS_store_sub_in_multi __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
98        PARROT_ASSERT_ARG(interp) \
99     , PARROT_ASSERT_ARG(sub_pmc) \
100     , PARROT_ASSERT_ARG(ns))
101 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
102 /* HEADERIZER END: static */
103 
104 /* flags for internal_ns_keyed */
105 #define INTERN_NS_CREAT 1       /* I'm a fan of the classics */
106 
107 /*
108 
109 =head1 Internal Static Functions
110 
111 =over 4
112 
113 =item C<static PMC * internal_ns_keyed_str(PARROT_INTERP, PMC *base_ns, STRING
114 *key, int flags)>
115 
116 Looks up a nested NameSpace PMC starting from C<base_ns> and doing a relative
117 lookup. C<key> is a STRING containing the name of the NameSpace to look up.
118 Flags can be 0 or INTERN_NS_CREAT. In the former case, PMCNULL is returned
119 if the namespace is not found. In the later, a new namespace with the given
120 is created and returned if it is not found.
121 
122 =cut
123 
124 */
125 
126 PARROT_WARN_UNUSED_RESULT
127 PARROT_CANNOT_RETURN_NULL
128 static PMC *
internal_ns_keyed_str(PARROT_INTERP,ARGIN (PMC * base_ns),ARGIN (STRING * key),int flags)129 internal_ns_keyed_str(PARROT_INTERP, ARGIN(PMC *base_ns),
130     ARGIN(STRING *key), int flags)
131 {
132     ASSERT_ARGS(internal_ns_keyed_str)
133     PMC    * const ns     = VTABLE_get_pmc_keyed_str(interp, base_ns, key);
134     STRING * const namesp = CONST_STRING(interp, "NameSpace");
135 
136     if (!PMC_IS_NULL(ns)
137     && (ns->vtable->base_type == enum_class_NameSpace
138      || VTABLE_isa(interp, ns, namesp)))
139         return ns;
140 
141     return internal_ns_maybe_create(interp, base_ns, key, flags);
142 }
143 
144 /*
145 
146 =item C<static PMC * internal_ns_keyed_key(PARROT_INTERP, PMC *ns, PMC *key, int
147 flags)>
148 
149 Internal function to do keyed namespace lookup relative to a given namespace
150 PMC. The namespace to find is located by C<key> relative to C<ns>. C<flags>
151 determines what happens when an existing namespace is not found. 0 means
152 PMCNULL is returned, INTERN_NS_CREAT means a new namespace is created.
153 
154 =cut
155 
156 */
157 
158 PARROT_WARN_UNUSED_RESULT
159 PARROT_CANNOT_RETURN_NULL
160 static PMC *
internal_ns_keyed_key(PARROT_INTERP,ARGIN (PMC * ns),ARGIN (PMC * key),int flags)161 internal_ns_keyed_key(PARROT_INTERP, ARGIN(PMC *ns), ARGIN(PMC *key), int flags)
162 {
163     ASSERT_ARGS(internal_ns_keyed_key)
164     while (key) {
165         STRING * const part = VTABLE_get_string(interp, key);
166         PMC    *sub_ns      = VTABLE_get_pmc_keyed_str(interp, ns, part);
167 
168         if (PMC_IS_NULL(sub_ns) || !VTABLE_isa(interp, sub_ns, CONST_STRING(interp, "NameSpace"))) {
169             sub_ns = internal_ns_maybe_create(interp, ns, part, flags);
170 
171             if (PMC_IS_NULL(sub_ns))
172                 return PMCNULL;
173         }
174 
175         ns  = sub_ns;
176         key = VTABLE_shift_pmc(interp, key);
177     }
178 
179     return ns;
180 }
181 
182 /*
183 
184 =item C<static PMC * internal_ns_keyed(PARROT_INTERP, PMC *base_ns, PMC
185 *pmc_key, int flags)>
186 
187 Search for a namespace PMC starting from a base namespace C<base_ns> and
188 following C<pmc_key> to the nested namespace. C<pmc_key> can be a String,
189 a Key, or an array of strings (such as an ResizableStringArray, or a
190 ResizablePMCArray that contains Strings). Flags determines what we do if the
191 requested namespace is not found: 0 means we return PMCNULL, INTERN_NS_CREAT
192 means we create the new namespace and return it.
193 
194 =cut
195 
196 */
197 
198 PARROT_WARN_UNUSED_RESULT
199 PARROT_CANNOT_RETURN_NULL
200 static PMC *
internal_ns_keyed(PARROT_INTERP,ARGIN (PMC * base_ns),ARGIN (PMC * pmc_key),int flags)201 internal_ns_keyed(PARROT_INTERP, ARGIN(PMC *base_ns), ARGIN(PMC *pmc_key), int flags)
202 {
203     ASSERT_ARGS(internal_ns_keyed)
204 
205     if (PMC_IS_TYPE(pmc_key, Key))
206         return internal_ns_keyed_key(interp, base_ns, pmc_key, flags);
207     else if (VTABLE_isa(interp, pmc_key, CONST_STRING(interp, "String"))) {
208         STRING * const str_key = VTABLE_get_string(interp, pmc_key);
209         return internal_ns_keyed_str(interp, base_ns, str_key, flags);
210     }
211     else {
212         /* array of strings */
213         STRING * const isans = CONST_STRING(interp, "NameSpace");
214         const INTVAL n = VTABLE_elements(interp, pmc_key);
215         INTVAL i;
216         PMC *ns = base_ns;
217 
218         for (i = 0; i < n; ++i) {
219             STRING * const part = VTABLE_get_string_keyed_int(interp, pmc_key, i);
220             PMC *sub_ns = VTABLE_get_pmc_keyed_str(interp, ns, part);
221 
222             if (PMC_IS_NULL(sub_ns) || !VTABLE_isa(interp, sub_ns, isans)) {
223                 sub_ns = internal_ns_maybe_create(interp, ns, part, flags);
224                 if (PMC_IS_NULL(sub_ns))
225                     return PMCNULL;
226             }
227             ns = sub_ns;
228         }
229         return ns;
230     }
231 }
232 
233 /*
234 
235 =item C<static PMC * internal_ns_maybe_create(PARROT_INTERP, PMC *ns, STRING
236 *key, int flags)>
237 
238 Given a namespace PMC C<ns>, a STRING C<key> containing a name, and flags from
239 C<internal_ns_keyed> or C<internal_ns_keyed_str>, creates and returns a new
240 namespace with the given name as a child of the given namespace.  This is an
241 internal function only.
242 
243 =cut
244 
245 */
246 
247 PARROT_WARN_UNUSED_RESULT
248 PARROT_CANNOT_RETURN_NULL
249 static PMC *
internal_ns_maybe_create(PARROT_INTERP,ARGIN (PMC * ns),ARGIN (STRING * key),int flags)250 internal_ns_maybe_create(PARROT_INTERP, ARGIN(PMC *ns), ARGIN(STRING *key), int flags)
251 {
252     ASSERT_ARGS(internal_ns_maybe_create)
253 
254     /* TT #1220 - stop depending on typed namespace */
255     if (!(flags & INTERN_NS_CREAT))
256         return PMCNULL;
257     else {
258         const INTVAL type_id = Parrot_hll_get_ctx_HLL_type(interp, enum_class_NameSpace);
259         /* TT #1221 - match HLL of enclosing namespace? */
260         PMC * const sub_ns = Parrot_pmc_new(interp, type_id);
261 
262         if (PMC_IS_NULL(sub_ns))
263             return PMCNULL;
264 
265         VTABLE_set_pmc_keyed_str(interp, ns, key, sub_ns);
266         return sub_ns;
267     }
268 }
269 
270 /*
271 
272 =item C<static PMC * get_namespace_pmc(PARROT_INTERP, PMC *sub_pmc)>
273 
274 Return the namespace PMC associated with the PMC C<sub>. If there is no
275 NameSpace associated with the sub, return it's HLL NameSpace PMC instead.
276 
277 =cut
278 
279 */
280 
281 PARROT_WARN_UNUSED_RESULT
282 PARROT_CANNOT_RETURN_NULL
283 static PMC *
get_namespace_pmc(PARROT_INTERP,ARGIN (PMC * sub_pmc))284 get_namespace_pmc(PARROT_INTERP, ARGIN(PMC *sub_pmc))
285 {
286     ASSERT_ARGS(get_namespace_pmc)
287     Parrot_Sub_attributes *sub;
288     PMC        *nsname, *nsroot;
289 
290     PMC_get_sub(interp, sub_pmc, sub);
291     nsname = sub->namespace_name;
292     nsroot = Parrot_hll_get_HLL_namespace(interp, sub->HLL_id);
293 
294     /* If we have a NULL, return the HLL namespace */
295     if (PMC_IS_NULL(nsname))
296         return nsroot;
297     /* If we have a String, do a string lookup */
298     else if (nsname->vtable->base_type == enum_class_String)
299         return Parrot_ns_make_namespace_keyed_str(interp, nsroot,
300                 VTABLE_get_string(interp, nsname));
301     /* Otherwise, do a PMC lookup */
302     else
303         return Parrot_ns_make_namespace_keyed(interp, nsroot, nsname);
304 }
305 
306 /*
307 
308 =item C<static void store_sub_in_multi(PARROT_INTERP, PMC *sub_pmc, PMC *ns)>
309 
310 Adds the sub C<sub> into a multisub of the same name in the namespace C<ns>.
311 If no multisub by that name currently exists, we create one.
312 
313 =cut
314 
315 */
316 
317 static void
store_sub_in_multi(PARROT_INTERP,ARGIN (PMC * sub_pmc),ARGIN (PMC * ns))318 store_sub_in_multi(PARROT_INTERP, ARGIN(PMC *sub_pmc), ARGIN(PMC *ns))
319 {
320     ASSERT_ARGS(store_sub_in_multi)
321     Parrot_Sub_attributes *sub;
322     STRING     *ns_entry_name;
323     PMC        *multisub;
324 
325     PMC_get_sub(interp, sub_pmc, sub);
326     ns_entry_name = sub->ns_entry_name;
327     multisub      = VTABLE_get_pmc_keyed_str(interp, ns, ns_entry_name);
328 
329     /* is there an existing MultiSub PMC? or do we need to create one? */
330     if (PMC_IS_NULL(multisub)) {
331         multisub = Parrot_pmc_new(interp,
332                                   Parrot_hll_get_ctx_HLL_type(interp, enum_class_MultiSub));
333         /* we have to push the sub onto the MultiSub before we try to store
334         it because storing requires information from the sub */
335         VTABLE_push_pmc(interp, multisub, sub_pmc);
336         VTABLE_set_pmc_keyed_str(interp, ns, ns_entry_name, multisub);
337     }
338     else
339         VTABLE_push_pmc(interp, multisub, sub_pmc);
340 }
341 
342 /*
343 
344 =back
345 
346 =head1 NameSpace API Functions
347 
348 =over 4
349 
350 =item C<PMC * Parrot_ns_get_namespace_keyed(PARROT_INTERP, PMC *base_ns, PMC
351 *pmc_key)>
352 
353 Find the namespace relative to the namespace C<base_ns> with the key
354 C<pmc_key>, which may be a String, a Key, or an array of strings.  Return
355 the namespace, or NULL if not found.
356 
357 =cut
358 
359 */
360 
361 PARROT_EXPORT
362 PARROT_WARN_UNUSED_RESULT
363 PARROT_CANNOT_RETURN_NULL
364 PMC *
Parrot_ns_get_namespace_keyed(PARROT_INTERP,ARGIN (PMC * base_ns),ARGIN (PMC * pmc_key))365 Parrot_ns_get_namespace_keyed(PARROT_INTERP, ARGIN(PMC *base_ns), ARGIN(PMC *pmc_key))
366 {
367     ASSERT_ARGS(Parrot_ns_get_namespace_keyed)
368     return internal_ns_keyed(interp, base_ns, pmc_key, 0);
369 }
370 
371 /*
372 
373 =item C<PMC * Parrot_ns_get_namespace_keyed_str(PARROT_INTERP, PMC *base_ns,
374 STRING *str_key)>
375 
376 Find the namespace relative to the namespace C<base_ns> with the string key
377 C<str_key>.  Return the namespace, or NULL if not found.
378 
379 =cut
380 
381 */
382 
383 PARROT_EXPORT
384 PARROT_WARN_UNUSED_RESULT
385 PARROT_CANNOT_RETURN_NULL
386 PMC *
Parrot_ns_get_namespace_keyed_str(PARROT_INTERP,ARGIN (PMC * base_ns),ARGIN_NULLOK (STRING * str_key))387 Parrot_ns_get_namespace_keyed_str(PARROT_INTERP, ARGIN(PMC *base_ns),
388         ARGIN_NULLOK(STRING *str_key))
389 {
390     ASSERT_ARGS(Parrot_ns_get_namespace_keyed_str)
391     return internal_ns_keyed_str(interp, base_ns, str_key, 0);
392 }
393 
394 /*
395 
396 =item C<PMC * Parrot_ns_make_namespace_keyed(PARROT_INTERP, PMC *base_ns, PMC
397 *pmc_key)>
398 
399 Find, or create if necessary, the namespace relative to the namespace
400 C<base_ns> with the key C<pmc_key>, which may be a String, a Key, or an
401 array of strings.  Return the namespace.  Errors will result in exceptions.
402 
403 =cut
404 
405 */
406 
407 PARROT_EXPORT
408 PARROT_WARN_UNUSED_RESULT
409 PARROT_CANNOT_RETURN_NULL
410 PMC *
Parrot_ns_make_namespace_keyed(PARROT_INTERP,ARGIN (PMC * base_ns),ARGIN (PMC * pmc_key))411 Parrot_ns_make_namespace_keyed(PARROT_INTERP, ARGIN(PMC *base_ns),
412         ARGIN(PMC *pmc_key))
413 {
414     ASSERT_ARGS(Parrot_ns_make_namespace_keyed)
415     return internal_ns_keyed(interp, base_ns, pmc_key, INTERN_NS_CREAT);
416 }
417 
418 /*
419 
420 =item C<PMC * Parrot_ns_make_namespace_keyed_str(PARROT_INTERP, PMC *base_ns,
421 STRING *str_key)>
422 
423 Find, or create if necessary, the namespace relative to the namespace
424 C<base_ns> with the string key C<str_key>.  Return the namespace.  Errors
425 will result in exceptions.
426 
427 =cut
428 
429 */
430 
431 PARROT_EXPORT
432 PARROT_WARN_UNUSED_RESULT
433 PARROT_CANNOT_RETURN_NULL
434 PMC *
Parrot_ns_make_namespace_keyed_str(PARROT_INTERP,ARGIN (PMC * base_ns),ARGIN (STRING * str_key))435 Parrot_ns_make_namespace_keyed_str(PARROT_INTERP, ARGIN(PMC *base_ns),
436         ARGIN(STRING *str_key))
437 {
438     ASSERT_ARGS(Parrot_ns_make_namespace_keyed_str)
439     return internal_ns_keyed_str(interp, base_ns, str_key, INTERN_NS_CREAT);
440 }
441 
442 /*
443 
444 =item C<PMC * Parrot_ns_make_namespace_autobase(PARROT_INTERP, PMC *key)>
445 
446 Find, or create if necessary, a namespace with the key C<key>, which may be a
447 String, a Key, or an array of strings. If it is a String, then the lookup is
448 relative to the current namespace. Otherwise, it is relative to the current HLL
449 root namespace. Return the namespace.  Errors will result in exceptions.
450 
451 =cut
452 
453 */
454 
455 PARROT_EXPORT
456 PARROT_WARN_UNUSED_RESULT
457 PARROT_CANNOT_RETURN_NULL
458 PMC *
Parrot_ns_make_namespace_autobase(PARROT_INTERP,ARGIN (PMC * key))459 Parrot_ns_make_namespace_autobase(PARROT_INTERP, ARGIN(PMC *key))
460 {
461     ASSERT_ARGS(Parrot_ns_make_namespace_autobase)
462     PMC *base_ns;
463     if (VTABLE_isa(interp, key, CONST_STRING(interp, "String")))
464         base_ns = Parrot_pcc_get_namespace(interp, CURRENT_CONTEXT(interp));
465     else
466         base_ns = VTABLE_get_pmc_keyed_int(interp, interp->HLL_namespace,
467             Parrot_pcc_get_HLL(interp, CURRENT_CONTEXT(interp)));
468     return Parrot_ns_make_namespace_keyed(interp, base_ns, key);
469 }
470 
471 /*
472 
473 =item C<PMC * Parrot_ns_get_name(PARROT_INTERP, PMC *_namespace)>
474 
475 Get the name of the namespace, as a ResizableStringArray. For instance, the
476 namespace Foo:Bar:Baz would return an RSA with three elements.
477 
478 =cut
479 
480 */
481 
482 PARROT_EXPORT
483 PARROT_WARN_UNUSED_RESULT
484 PARROT_CAN_RETURN_NULL
485 PMC *
Parrot_ns_get_name(PARROT_INTERP,ARGIN (PMC * _namespace))486 Parrot_ns_get_name(PARROT_INTERP, ARGIN(PMC *_namespace))
487 {
488     ASSERT_ARGS(Parrot_ns_get_name)
489     PMC *names;
490     STRING * const get_name = CONST_STRING(interp, "get_name");
491     Parrot_pcc_invoke_method_from_c_args(interp, _namespace, get_name, "->P", &names);
492     return names;
493 }
494 
495 /*
496 
497 =item C<PMC * Parrot_ns_get_global(PARROT_INTERP, PMC *ns, STRING *globalname)>
498 
499 Look up the global named C<globalname> in the namespace C<ns>.  Return the
500 global, or return PMCNULL if C<ns> is null or if the global is not found.
501 
502 Parrot_ns_get_global allows a null namespace without throwing an exception; it
503 simply returns PMCNULL in that case.
504 
505 NOTE: At present the use of the {get, set}_global functions is mandatory due
506       to the wacky namespace typing of the default Parrot namespace.
507       Eventually it will be safe to just use the standard hash interface
508       (if desired).
509 
510 =cut
511 
512 */
513 
514 PARROT_EXPORT
515 PARROT_WARN_UNUSED_RESULT
516 PARROT_CANNOT_RETURN_NULL
517 PMC *
Parrot_ns_get_global(PARROT_INTERP,ARGIN_NULLOK (PMC * ns),ARGIN_NULLOK (STRING * globalname))518 Parrot_ns_get_global(PARROT_INTERP, ARGIN_NULLOK(PMC *ns), ARGIN_NULLOK(STRING *globalname))
519 {
520     ASSERT_ARGS(Parrot_ns_get_global)
521     if (PMC_IS_NULL(ns))
522         return PMCNULL;
523 
524     return (PMC *)VTABLE_get_pointer_keyed_str(interp, ns, globalname);
525 }
526 
527 /*
528 
529 =item C<void Parrot_ns_set_global(PARROT_INTERP, PMC *ns, STRING *globalname,
530 PMC *val)>
531 
532 Set the global named C<globalname> in the namespace C<ns> to the value C<val>.
533 
534 =cut
535 
536 */
537 
538 PARROT_EXPORT
539 void
Parrot_ns_set_global(PARROT_INTERP,ARGIN (PMC * ns),ARGIN_NULLOK (STRING * globalname),ARGIN_NULLOK (PMC * val))540 Parrot_ns_set_global(PARROT_INTERP, ARGIN(PMC *ns),
541         ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
542 {
543     ASSERT_ARGS(Parrot_ns_set_global)
544     VTABLE_set_pmc_keyed_str(interp, ns, globalname, val);
545 }
546 
547 
548 /*
549 
550 =item C<PMC * Parrot_ns_find_namespace_global(PARROT_INTERP, PMC *ns, STRING
551 *globalname)>
552 
553 Search the namespace PMC C<ns> for an object with name C<globalname>.
554 Return the object, or PMCNULL if not found.
555 
556 TT #1222 - For now this function prefers non-namespaces, it will eventually
557 entirely use the untyped interface.
558 
559 =cut
560 
561 */
562 
563 PARROT_EXPORT
564 PARROT_WARN_UNUSED_RESULT
565 PARROT_CANNOT_RETURN_NULL
566 PMC *
Parrot_ns_find_namespace_global(PARROT_INTERP,ARGIN_NULLOK (PMC * ns),ARGIN_NULLOK (STRING * globalname))567 Parrot_ns_find_namespace_global(PARROT_INTERP,
568         ARGIN_NULLOK(PMC *ns), ARGIN_NULLOK(STRING *globalname))
569 {
570     ASSERT_ARGS(Parrot_ns_find_namespace_global)
571     PMC *res;
572 
573     if (PMC_IS_NULL(ns))
574         res = PMCNULL;
575     else {
576         /*
577          * TT #1219 - we should be able to use 'get_pmc_keyed' here,
578          * but we can't because Parrot's default namespaces are not
579          * fully typed and there's a pseudo-typed interface that
580          * distinguishes 'get_pmc_keyed' from 'get_pointer_keyed';
581          * the former is for NS and the latter is for non-NS.
582          */
583         res = (PMC *)VTABLE_get_pointer_keyed_str(interp, ns, globalname);
584     }
585 
586     return PMC_IS_NULL(res) ? PMCNULL : res;
587 }
588 
589 /*
590 
591 =item C<PMC * Parrot_ns_find_current_namespace_global(PARROT_INTERP, STRING
592 *globalname)>
593 
594 Finds and returns the data time named C<globalname> in the current namespace.
595 
596 =cut
597 
598 */
599 
600 PARROT_EXPORT
601 PARROT_WARN_UNUSED_RESULT
602 PARROT_CANNOT_RETURN_NULL
603 PMC *
Parrot_ns_find_current_namespace_global(PARROT_INTERP,ARGIN_NULLOK (STRING * globalname))604 Parrot_ns_find_current_namespace_global(PARROT_INTERP, ARGIN_NULLOK(STRING *globalname))
605 {
606     ASSERT_ARGS(Parrot_ns_find_current_namespace_global)
607     PMC * const ns = Parrot_pcc_get_namespace(interp, CURRENT_CONTEXT(interp));
608     return Parrot_ns_find_namespace_global(interp, ns, globalname);
609 }
610 
611 /*
612 
613 =item C<void Parrot_ns_store_global(PARROT_INTERP, PMC *ns, STRING *globalname,
614 PMC *val)>
615 
616 Store the PMC C<val> into the namespace PMC C<ns> with name C<globalname>. If
617 the namespace is null, do nothing.
618 
619 =cut
620 
621 */
622 
623 PARROT_EXPORT
624 void
Parrot_ns_store_global(PARROT_INTERP,ARGIN_NULLOK (PMC * ns),ARGIN_NULLOK (STRING * globalname),ARGIN_NULLOK (PMC * val))625 Parrot_ns_store_global(PARROT_INTERP, ARGIN_NULLOK(PMC *ns),
626         ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
627 {
628     ASSERT_ARGS(Parrot_ns_store_global)
629 
630     if (PMC_IS_NULL(ns))
631         return;
632 
633     VTABLE_set_pmc_keyed_str(interp, ns, globalname, val);
634 }
635 
636 /*
637 
638 =item C<PMC * Parrot_ns_find_global_from_op(PARROT_INTERP, PMC *ns, STRING
639 *globalname, void *next)>
640 
641 If the global exists in the given namespace PMC, return it.  If not, return
642 PMCNULL. Throw an exception if a NULL name is passed.
643 
644 =cut
645 
646 */
647 
648 PARROT_EXPORT
649 PARROT_WARN_UNUSED_RESULT
650 PARROT_CANNOT_RETURN_NULL
651 PMC *
Parrot_ns_find_global_from_op(PARROT_INTERP,ARGIN (PMC * ns),ARGIN_NULLOK (STRING * globalname),SHIM (void * next))652 Parrot_ns_find_global_from_op(PARROT_INTERP, ARGIN(PMC *ns),
653         ARGIN_NULLOK(STRING *globalname), SHIM(void *next))
654 {
655     ASSERT_ARGS(Parrot_ns_find_global_from_op)
656     if (STRING_IS_NULL(globalname))
657         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_GLOBAL_NOT_FOUND,
658             "Tried to get null global");
659     else {
660         PMC * const res = Parrot_ns_find_namespace_global(interp, ns, globalname);
661         return res;
662     }
663 }
664 
665 
666 /*
667 
668 =item C<PMC * Parrot_ns_find_named_item(PARROT_INTERP, STRING *name, void
669 *next)>
670 
671 Find the given C<name> in lexicals, then the current namespace, then the HLL
672 root namespace, and finally Parrot builtins.  If the name isn't found
673 anywhere, return PMCNULL.
674 
675 =cut
676 
677 */
678 
679 PARROT_EXPORT
680 PARROT_WARN_UNUSED_RESULT
681 PARROT_CANNOT_RETURN_NULL
682 PMC *
Parrot_ns_find_named_item(PARROT_INTERP,ARGIN (STRING * name),ARGIN (SHIM (void * next)))683 Parrot_ns_find_named_item(PARROT_INTERP, ARGIN(STRING *name), ARGIN(SHIM(void *next)))
684 {
685     ASSERT_ARGS(Parrot_ns_find_named_item)
686     PMC * const ctx     = CURRENT_CONTEXT(interp);
687     PMC * const lex_pad = Parrot_sub_find_pad(interp, name, ctx);
688     PMC * g = PMCNULL;
689 
690     if (!PMC_IS_NULL(lex_pad)) {
691         g = VTABLE_get_pmc_keyed_str(interp, lex_pad, name);
692 
693         /* GH #563 - walk up the scopes!  duh!! */
694         if (!PMC_IS_NULL(g))
695             return g;
696     }
697 
698     g = Parrot_ns_find_current_namespace_global(interp, name);
699     if (!PMC_IS_NULL(g))
700         return g;
701 
702     g = Parrot_ns_find_namespace_global(interp, Parrot_hll_get_ctx_HLL_namespace(interp), name);
703     if (!PMC_IS_NULL(g))
704         return g;
705     return PMCNULL;
706 }
707 
708 /*
709 
710 =item C<void Parrot_ns_store_sub(PARROT_INTERP, PMC *sub_pmc)>
711 
712 Adds the PMC C<sub> into the current namespace. Adds the sub to a multi of the
713 same name if it's defined as a multi.
714 
715 =cut
716 
717 */
718 
719 PARROT_EXPORT
720 void
Parrot_ns_store_sub(PARROT_INTERP,ARGIN (PMC * sub_pmc))721 Parrot_ns_store_sub(PARROT_INTERP, ARGIN(PMC *sub_pmc))
722 {
723     ASSERT_ARGS(Parrot_ns_store_sub)
724     const INTVAL cur_id = Parrot_pcc_get_HLL(interp, CURRENT_CONTEXT(interp));
725 
726     PMC *ns;
727     Parrot_Sub_attributes *sub;
728 
729     /* store relative to HLL namespace */
730     PMC_get_sub(interp, sub_pmc, sub);
731     Parrot_pcc_set_HLL(interp, CURRENT_CONTEXT(interp), sub->HLL_id);
732 
733     ns = get_namespace_pmc(interp, sub_pmc);
734 
735     /* attach a namespace to the sub for lookups */
736     sub->namespace_stash = ns;
737 
738     /* store a :multi sub */
739     if (!PMC_IS_NULL(sub->multi_signature))
740         store_sub_in_multi(interp, sub_pmc, ns);
741 
742     /* store other subs (as long as they're not :anon) */
743     else if (!(PObj_get_FLAGS(sub_pmc) & SUB_FLAG_PF_ANON)
744         || sub->vtable_index != -1) {
745         STRING * const ns_entry_name = sub->ns_entry_name;
746         PMC    * const nsname        = sub->namespace_name;
747 
748         Parrot_ns_store_global(interp, ns, ns_entry_name, sub_pmc);
749 
750         /* TT #1224:
751            TEMPORARY HACK - cache invalidation should be a namespace function
752          */
753         if (!PMC_IS_NULL(nsname)) {
754             STRING * const nsname_s = VTABLE_get_string(interp, nsname);
755             Parrot_invalidate_method_cache(interp, nsname_s);
756         }
757     }
758 
759     /* restore HLL_id */
760     Parrot_pcc_set_HLL(interp, CURRENT_CONTEXT(interp), cur_id);
761 }
762 
763 /*
764 
765 =item C<Parrot_PMC Parrot_ns_get_root_namespace(PARROT_INTERP)>
766 
767 Return the root namespace
768 
769 =cut
770 
771 */
772 
773 PARROT_EXPORT
774 PARROT_PURE_FUNCTION
775 Parrot_PMC
Parrot_ns_get_root_namespace(PARROT_INTERP)776 Parrot_ns_get_root_namespace(PARROT_INTERP)
777 {
778     ASSERT_ARGS(Parrot_ns_get_root_namespace)
779 
780     return interp->root_namespace;
781 }
782 
783 /*
784 
785 =back
786 
787 =head1 SEE ALSO
788 
789 F<include/parrot/namespace.h>
790 
791 =cut
792 
793 */
794 
795 
796 /*
797  * Local variables:
798  *   c-file-style: "parrot"
799  * End:
800  * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
801  */
802