+ --debug is now --imcc-debug; make this more consistent with -D.
[parrot.git] / src / global.c
blobb30577641d2472397897aa9f779d3828695a797e
1 /*
2 Copyright (C) 2004-2007, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/global.c - Access to global PMCs
9 =head1 DESCRIPTION
11 =head2 Functions
13 =over 4
15 =cut
19 #include "parrot/parrot.h"
20 #include "global.str"
22 /* HEADERIZER HFILE: include/parrot/global.h */
23 /* HEADERIZER BEGIN: static */
25 PARROT_WARN_UNUSED_RESULT
26 PARROT_CAN_RETURN_NULL
27 static PMC * get_namespace_pmc(PARROT_INTERP, ARGIN(PMC *sub))
28 __attribute__nonnull__(1)
29 __attribute__nonnull__(2);
31 PARROT_WARN_UNUSED_RESULT
32 PARROT_CAN_RETURN_NULL
33 static PMC * internal_ns_keyed(PARROT_INTERP,
34 ARGIN(PMC *base_ns),
35 ARGIN_NULLOK(PMC *pmc_key),
36 ARGIN_NULLOK(STRING *str_key),
37 int flags)
38 __attribute__nonnull__(1)
39 __attribute__nonnull__(2);
41 static void store_sub_in_multi(PARROT_INTERP,
42 ARGIN(PMC *sub),
43 ARGIN(PMC *ns))
44 __attribute__nonnull__(1)
45 __attribute__nonnull__(2)
46 __attribute__nonnull__(3);
48 /* HEADERIZER END: static */
50 #define DEBUG_GLOBAL 0
52 /* flags for internal_ns_keyed */
53 #define INTERN_NS_CREAT 1 /* I'm a fan of the classics */
57 =item C<static PMC * internal_ns_keyed>
59 internal_ns_keyed: Internal function to do keyed namespace lookup
60 relative to a given namespace PMC. Understands STRINGs, String PMCs,
61 Key pmcs, and array PMCs containing strings.
63 =cut
67 PARROT_WARN_UNUSED_RESULT
68 PARROT_CAN_RETURN_NULL
69 static PMC *
70 internal_ns_keyed(PARROT_INTERP, ARGIN(PMC *base_ns), ARGIN_NULLOK(PMC *pmc_key),
71 ARGIN_NULLOK(STRING *str_key), int flags)
73 PMC *ns, *sub_ns;
74 INTVAL i, n;
75 static const INTVAL max_intval = (INTVAL)((~(UINTVAL)0) >> 1); /*2s comp*/
77 ns = base_ns;
79 if (str_key)
80 n = 1;
81 else if (pmc_key->vtable->base_type == enum_class_String) {
82 str_key = VTABLE_get_string(interp, pmc_key);
83 n = 1;
85 else if (pmc_key->vtable->base_type == enum_class_Key)
86 n = max_intval; /* we don't yet know how big the key is */
87 else
88 n = VTABLE_elements(interp, pmc_key); /* array of strings */
90 for (i = 0; i < n; ++i) {
91 STRING *part;
93 if (str_key)
94 part = str_key;
95 else if (n == max_intval) {
96 if (!pmc_key) {
97 real_exception(interp, NULL, 1,
98 "Passing a NULL pmc_key into key_string()");
100 part = key_string(interp, pmc_key);
101 pmc_key = key_next(interp, pmc_key);
102 if (! pmc_key)
103 n = i + 1; /* now we know how big the key is */
105 else {
106 if (!pmc_key) {
107 real_exception(interp, NULL, 1,
108 "Passed a NULL pmc_key into VTABLE_get_string_keyed_int");
110 part = VTABLE_get_string_keyed_int(interp, pmc_key, i);
113 sub_ns = VTABLE_get_pmc_keyed_str(interp, ns, part);
115 if (PMC_IS_NULL(sub_ns)
116 /* RT#46157 - stop depending on typed namespace */
117 || sub_ns->vtable->base_type != enum_class_NameSpace)
119 if (!(flags & INTERN_NS_CREAT))
120 return PMCNULL;
122 /* RT#46159 - match HLL of enclosing namespace? */
123 sub_ns = pmc_new(interp,
124 Parrot_get_ctx_HLL_type(interp,
125 enum_class_NameSpace));
126 if (PMC_IS_NULL(sub_ns))
127 return PMCNULL;
128 VTABLE_set_pmc_keyed_str(interp, ns, part, sub_ns);
130 ns = sub_ns;
131 } /* for */
133 return ns;
138 =item C<PMC * Parrot_get_namespace_keyed>
140 Find the namespace relative to the namespace C<base_ns> with the key
141 C<pmc_key>, which may be a String, a Key, or an array of strings. Return
142 the namespace, or NULL if not found.
144 =cut
148 PARROT_API
149 PARROT_WARN_UNUSED_RESULT
150 PARROT_CAN_RETURN_NULL
151 PMC *
152 Parrot_get_namespace_keyed(PARROT_INTERP, ARGIN(PMC *base_ns), ARGIN_NULLOK(PMC *pmc_key))
154 return internal_ns_keyed(interp, base_ns, pmc_key, NULL, 0);
159 =item C<PMC * Parrot_get_namespace_keyed_str>
161 Find the namespace relative to the namespace C<base_ns> with the string key
162 C<str_key>. Return the namespace, or NULL if not found.
164 =cut
168 PARROT_API
169 PARROT_WARN_UNUSED_RESULT
170 PARROT_CAN_RETURN_NULL
171 PMC *
172 Parrot_get_namespace_keyed_str(PARROT_INTERP, ARGIN(PMC *base_ns),
173 ARGIN_NULLOK(STRING *str_key))
175 return internal_ns_keyed(interp, base_ns, PMCNULL, str_key, 0);
180 =item C<PMC * Parrot_make_namespace_keyed>
182 Find, or create if necessary, the namespace relative to the namespace
183 C<base_ns> with the key C<pmc_key>, which may be a String, a Key, or an
184 array of strings. Return the namespace. Errors will result in exceptions.
186 =cut
190 PARROT_API
191 PARROT_WARN_UNUSED_RESULT
192 PARROT_CAN_RETURN_NULL
193 PMC *
194 Parrot_make_namespace_keyed(PARROT_INTERP, ARGIN(PMC *base_ns),
195 ARGIN_NULLOK(PMC *pmc_key))
197 return internal_ns_keyed(interp, base_ns, pmc_key, NULL, INTERN_NS_CREAT);
202 =item C<PMC * Parrot_make_namespace_keyed_str>
204 Find, or create if necessary, the namespace relative to the namespace
205 C<base_ns> with the string key C<str_key>. Return the namespace. Errors
206 will result in exceptions.
208 =cut
212 PARROT_API
213 PARROT_WARN_UNUSED_RESULT
214 PARROT_CAN_RETURN_NULL
215 PMC *
216 Parrot_make_namespace_keyed_str(PARROT_INTERP, ARGIN(PMC *base_ns),
217 ARGIN_NULLOK(STRING *str_key))
219 return internal_ns_keyed(interp, base_ns, NULL, str_key, INTERN_NS_CREAT);
225 =item C<PMC * Parrot_make_namespace_autobase>
227 Find, or create if necessary, a namespace with the key C<key>, which may be a
228 String, a Key, or an array of strings. If it is a String, then the lookup is
229 relative to the current namespace. Otherwise, it is relative to the current HLL
230 root namespace. Return the namespace. Errors will result in exceptions.
232 =cut
236 PARROT_API
237 PARROT_WARN_UNUSED_RESULT
238 PARROT_CAN_RETURN_NULL
239 PMC *
240 Parrot_make_namespace_autobase(PARROT_INTERP, ARGIN_NULLOK(PMC *key))
242 PMC *base_ns;
243 if (VTABLE_isa(interp, key, CONST_STRING(interp, "String")))
244 base_ns = CONTEXT(interp->ctx)->current_namespace;
245 else
246 base_ns = VTABLE_get_pmc_keyed_int(interp, interp->HLL_namespace,
247 CONTEXT(interp->ctx)->current_HLL);
248 return Parrot_make_namespace_keyed(interp, base_ns, key);
253 =item C<PMC * Parrot_get_namespace_autobase>
255 Find a namespace with the key C<key>, which may be a String, a Key, or an
256 array of strings. If it is a String, then the lookup is relative to the
257 current namespace. Otherwise, it is relative to the current HLL root
258 namespace. Return the namespace, or NULL if not found.
260 =cut
264 PARROT_API
265 PARROT_WARN_UNUSED_RESULT
266 PARROT_CAN_RETURN_NULL
267 PMC *
268 Parrot_get_namespace_autobase(PARROT_INTERP, ARGIN_NULLOK(PMC *key))
270 PMC *base_ns;
271 if (VTABLE_isa(interp, key, CONST_STRING(interp, "String")))
272 base_ns = CONTEXT(interp->ctx)->current_namespace;
273 else
274 base_ns = VTABLE_get_pmc_keyed_int(interp, interp->HLL_namespace,
275 CONTEXT(interp->ctx)->current_HLL);
276 return Parrot_get_namespace_keyed(interp, base_ns, key);
282 =item C<PMC * Parrot_get_global>
284 Parrot_get_global allows a null namespace without throwing an exception; it
285 simply returns PMCNULL in that case.
287 NOTE: At present the use of the {get, set}_global functions is mandatory due to the
288 wacky namespace typing of the default Parrot namespace. Eventually it will be
289 safe to just use the standard hash interface (if desired).
291 Look up the global named C<globalname> in the namespace C<ns>. Return the
292 global, or return PMCNULL if C<ns> is null or if the global is not found.
294 KLUDGE ALERT: Currently prefers non-namespaces in case of collision.
296 =cut
302 * {get, set}_global.
304 * Parrot_get_global allows a null namespace without throwing an exception; it
305 * simply returns PMCNULL in that case.
307 * NOTE: At present the use of the {get, set}_global functions is mandatory due to the
308 * wacky namespace typing of the default Parrot namespace. Eventually it will be
309 * safe to just use the standard hash interface (if desired).
312 PARROT_API
313 PARROT_WARN_UNUSED_RESULT
314 PARROT_CAN_RETURN_NULL
315 PMC *
316 Parrot_get_global(PARROT_INTERP, ARGIN_NULLOK(PMC *ns), ARGIN_NULLOK(STRING *globalname))
318 if (PMC_IS_NULL(ns))
319 return PMCNULL;
321 return (PMC *)VTABLE_get_pointer_keyed_str(interp, ns, globalname);
326 =item C<void Parrot_set_global>
328 Set the global named C<globalname> in the namespace C<ns> to the value C<val>.
330 =cut
334 PARROT_API
335 void
336 Parrot_set_global(PARROT_INTERP, ARGIN_NULLOK(PMC *ns),
337 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
339 VTABLE_set_pmc_keyed_str(interp, ns, globalname, val);
345 =item C<PMC * Parrot_find_global_n>
347 Search the namespace PMC C<ns> for an object with name C<globalname>.
348 Return the object, or NULL if not found.
350 RT#46161 - For now this function prefers non-namespaces, it will eventually
351 entirely use the untyped interface.
353 =cut
357 PARROT_API
358 PARROT_WARN_UNUSED_RESULT
359 PARROT_CAN_RETURN_NULL
360 PMC *
361 Parrot_find_global_n(PARROT_INTERP, ARGIN_NULLOK(PMC *ns), ARGIN_NULLOK(STRING *globalname))
363 PMC *res;
365 #if DEBUG_GLOBAL
366 if (globalname)
367 PIO_printf(interp, "find_global name '%Ss'\n", globalname);
368 #endif
370 if (PMC_IS_NULL(ns))
371 res = PMCNULL;
372 else {
374 * RT#46163 - we should be able to use 'get_pmc_keyed' here,
375 * but we can't because Parrot's default namespaces are not
376 * fully typed and there's a pseudo-typed interface that
377 * distinguishes 'get_pmc_keyed' from 'get_pointer_keyed';
378 * the former is for NS and the latter is for non-NS.
380 res = (PMC *)VTABLE_get_pointer_keyed_str(interp, ns, globalname);
383 return PMC_IS_NULL(res) ? NULL : res;
388 =item C<PMC * Parrot_find_global_cur>
390 RT#48260: Not yet documented!!!
392 =cut
396 PARROT_API
397 PARROT_WARN_UNUSED_RESULT
398 PARROT_CAN_RETURN_NULL
399 PMC *
400 Parrot_find_global_cur(PARROT_INTERP, ARGIN_NULLOK(STRING *globalname))
402 PMC * const ns = CONTEXT(interp->ctx)->current_namespace;
403 return Parrot_find_global_n(interp, ns, globalname);
408 =item C<PMC * Parrot_find_global_k>
410 Search the namespace designated by C<pmc_key>, which may be a key PMC,
411 an array of namespace name strings, or a string PMC, for an object
412 with name C<globalname>. Return the object, or NULL if not found.
414 RT#46161 - For now this function prefers non-namespaces, it will eventually
415 entirely use the untyped interface.
417 =cut
421 PARROT_API
422 PARROT_WARN_UNUSED_RESULT
423 PARROT_CAN_RETURN_NULL
424 PMC *
425 Parrot_find_global_k(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc_key), ARGIN(STRING *globalname))
427 PMC * const ns =
428 Parrot_get_namespace_keyed(interp,
429 Parrot_get_ctx_HLL_namespace(interp),
430 pmc_key);
431 return Parrot_find_global_n(interp, ns, globalname);
436 =item C<PMC * Parrot_find_global_s>
438 Search the namespace designated by C<str_key>, or the HLL root if
439 C<str_key> is NULL, for an object with name C<globalname>. Return the
440 object, or NULL if not found.
442 RT#46161 - For now this function prefers non-namespaces, it will eventually
443 entirely use the untyped interface.
445 =cut
449 PARROT_API
450 PARROT_WARN_UNUSED_RESULT
451 PARROT_CAN_RETURN_NULL
452 PMC *
453 Parrot_find_global_s(PARROT_INTERP, ARGIN_NULLOK(STRING *str_key),
454 ARGIN_NULLOK(STRING *globalname))
456 PMC *const ns =
457 Parrot_get_namespace_keyed_str(interp,
458 Parrot_get_ctx_HLL_namespace(interp),
459 str_key);
460 return Parrot_find_global_n(interp, ns, globalname);
465 =item C<void Parrot_store_global_n>
467 Store the PMC C<val> into the namespace PMC C<ns> with name C<globalname>.
469 =cut
473 PARROT_API
474 void
475 Parrot_store_global_n(PARROT_INTERP, ARGIN_NULLOK(PMC *ns),
476 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
478 #if DEBUG_GLOBAL
479 if (globalname)
480 PIO_printf(interp, "store_global name '%Ss'\n", globalname);
481 #endif
483 if (PMC_IS_NULL(ns))
484 return;
486 VTABLE_set_pmc_keyed_str(interp, ns, globalname, val);
491 =item C<void Parrot_store_global_cur>
493 RT#48260: Not yet documented!!!
495 =cut
499 PARROT_API
500 void
501 Parrot_store_global_cur(PARROT_INTERP, ARGIN_NULLOK(STRING *globalname),
502 ARGIN_NULLOK(PMC *val))
504 Parrot_store_global_n(interp,
505 CONTEXT(interp->ctx)->current_namespace,
506 globalname, val);
508 /* RT#46165 - method cache invalidation should occur */
513 =item C<void Parrot_store_global_k>
515 Store the PMC C<val> into the namespace designated by C<pmc_key>,
516 which may be a key PMC, an array of namespace name strings, or a
517 string PMC, with name C<globalname>.
519 RT#46161 - For now this function prefers non-namespaces, it will eventually
520 entirely use the untyped interface.
522 =cut
526 PARROT_API
527 void
528 Parrot_store_global_k(PARROT_INTERP, ARGIN(PMC *pmc_key),
529 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
531 PMC *ns;
534 * RT#46167 - temporary hack to notice when key is actually a string, so that
535 * the legacy logic for invalidating method cache will be called; this is
536 * not good enough but it avoids regressesions for now
538 if (pmc_key->vtable->base_type == enum_class_String) {
539 Parrot_store_global_s(interp, PMC_str_val(pmc_key),
540 globalname, val);
541 return;
544 ns = Parrot_make_namespace_keyed(interp,
545 Parrot_get_ctx_HLL_namespace(interp),
546 pmc_key);
548 Parrot_store_global_n(interp, ns, globalname, val);
550 /* RT#46165 - method cache invalidation should occur */
555 =item C<void Parrot_store_global_s>
557 Store the PMC C<val> into the namespace designated by C<str_key>, or
558 the HLL root if C<str_key> is NULL, with the name C<globalname>.
560 =cut
564 PARROT_API
565 void
566 Parrot_store_global_s(PARROT_INTERP, ARGIN_NULLOK(STRING *str_key),
567 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
569 PMC * const ns = Parrot_make_namespace_keyed_str(interp,
570 Parrot_get_ctx_HLL_namespace(interp),
571 str_key);
573 Parrot_store_global_n(interp, ns, globalname, val);
575 /* RT#46169 - method cache invalidation should be a namespace function */
576 Parrot_invalidate_method_cache(interp, str_key, globalname);
582 =item C<PMC * Parrot_find_global_op>
584 If the global exists in the given namespace PMC, return it. If not, return
585 PMCNULL.
587 =cut
591 PARROT_API
592 PARROT_WARN_UNUSED_RESULT
593 PARROT_CANNOT_RETURN_NULL
594 PMC *
595 Parrot_find_global_op(PARROT_INTERP, ARGIN(PMC *ns),
596 ARGIN(STRING *globalname), ARGIN_NULLOK(void *next))
598 PMC *res;
600 if (!globalname)
601 real_exception(interp, next, E_NameError,
602 "Tried to get null global");
604 res = Parrot_find_global_n(interp, ns, globalname);
605 if (!res)
606 res = PMCNULL;
608 return res;
614 =item C<PMC * Parrot_find_name_op>
616 RT#46171 - THIS IS BROKEN - it doesn't walk up the scopes yet
618 Find the given C<name> in lexicals, then the current namespace, then the HLL
619 root namespace, and finally Parrot builtins. If the name isn't found
620 anywhere, return PMCNULL.
622 =cut
626 PARROT_API
627 PARROT_WARN_UNUSED_RESULT
628 PARROT_CAN_RETURN_NULL
629 PMC *
630 Parrot_find_name_op(PARROT_INTERP, ARGIN(STRING *name), SHIM(void *next))
632 parrot_context_t * const ctx = CONTEXT(interp->ctx);
633 PMC * const lex_pad = Parrot_find_pad(interp, name, ctx);
634 PMC *g;
636 if (PMC_IS_NULL(lex_pad))
637 g = PMCNULL;
638 else
639 g = VTABLE_get_pmc_keyed_str(interp, lex_pad, name);
641 /* RT#46171 - walk up the scopes! duh!! */
643 if (PMC_IS_NULL(g)) {
644 g = Parrot_find_global_cur(interp, name);
646 if (PMC_IS_NULL(g)) {
647 g = Parrot_find_global_n(interp,
648 Parrot_get_ctx_HLL_namespace(interp), name);
650 if (PMC_IS_NULL(g)) {
651 g = Parrot_find_builtin(interp, name);
656 if (PMC_IS_NULL(g))
657 return PMCNULL;
658 else
659 return g;
664 =item C<static PMC * get_namespace_pmc>
666 RT#48260: Not yet documented!!!
668 =cut
672 PARROT_WARN_UNUSED_RESULT
673 PARROT_CAN_RETURN_NULL
674 static PMC *
675 get_namespace_pmc(PARROT_INTERP, ARGIN(PMC *sub))
677 PMC * const nsname = PMC_sub(sub)->namespace_name;
678 PMC * const nsroot = Parrot_get_HLL_namespace(interp, PMC_sub(sub)->HLL_id);
680 /* If we have a NULL, return the HLL namespace */
681 if (PMC_IS_NULL(nsname))
682 return nsroot;
683 /* If we have a String, do a string lookup */
684 else if (nsname->vtable->base_type == enum_class_String)
685 return Parrot_make_namespace_keyed_str(interp, nsroot, PMC_str_val(nsname));
686 /* Otherwise, do a PMC lookup */
687 else
688 return Parrot_make_namespace_keyed(interp, nsroot, nsname);
693 =item C<static void store_sub_in_multi>
695 RT#48260: Not yet documented!!!
697 =cut
701 static void
702 store_sub_in_multi(PARROT_INTERP, ARGIN(PMC *sub), ARGIN(PMC *ns))
704 INTVAL func_nr;
705 char *c_meth;
706 STRING * const subname = PMC_sub(sub)->name;
707 PMC *multisub = VTABLE_get_pmc_keyed_str(interp, ns, subname);
709 /* is there an existing MultiSub PMC? or do we need to create one? */
710 if (PMC_IS_NULL(multisub)) {
711 multisub = pmc_new(interp, enum_class_MultiSub);
712 /* we have to push the sub onto the MultiSub before we try to store
713 it because storing requires information from the sub */
714 VTABLE_push_pmc(interp, multisub, sub);
715 VTABLE_set_pmc_keyed_str(interp, ns, subname, multisub);
717 else
718 VTABLE_push_pmc(interp, multisub, sub);
720 c_meth = string_to_cstring(interp, subname);
721 func_nr = Parrot_MMD_method_idx(interp, c_meth);
722 if (func_nr >= 0)
723 Parrot_mmd_rebuild_table(interp, -1, func_nr);
724 string_cstring_free(c_meth);
729 =item C<void Parrot_store_sub_in_namespace>
731 RT#48260: Not yet documented!!!
733 =cut
737 PARROT_API
738 void
739 Parrot_store_sub_in_namespace(PARROT_INTERP, ARGIN(PMC *sub))
741 const INTVAL cur_id = CONTEXT(interp->ctx)->current_HLL;
743 PMC *ns;
744 /* PF structures aren't fully constructed yet */
745 Parrot_block_DOD(interp);
746 /* store relative to HLL namespace */
747 CONTEXT(interp->ctx)->current_HLL = PMC_sub(sub)->HLL_id;
749 ns = get_namespace_pmc(interp, sub);
751 /* attach a namespace to the sub for lookups */
752 PMC_sub(sub)->namespace_stash = ns;
754 /* store a :multi sub */
755 if (!PMC_IS_NULL(PMC_sub(sub)->multi_signature))
756 store_sub_in_multi(interp, sub, ns);
757 /* store other subs (as long as they're not :anon) */
758 else if (!(PObj_get_FLAGS(sub) & SUB_FLAG_PF_ANON)) {
759 STRING * const name = PMC_sub(sub)->name;
760 PMC * const nsname = PMC_sub(sub)->namespace_name;
762 Parrot_store_global_n(interp, ns, name, sub);
764 /* TEMPORARY HACK - cache invalidation should be a namespace function */
765 if (!PMC_IS_NULL(nsname)) {
766 STRING * const nsname_s = VTABLE_get_string(interp, nsname);
767 Parrot_invalidate_method_cache(interp, nsname_s, name);
771 /* restore HLL_id */
772 CONTEXT(interp->ctx)->current_HLL = cur_id;
773 Parrot_unblock_DOD(interp);
778 =back
780 =head1 SEE ALSO
782 F<include/parrot/global.h>
784 =cut
790 * Local variables:
791 * c-file-style: "parrot"
792 * End:
793 * vim: expandtab shiftwidth=4: