* src/pbc_merge.c:
[parrot.git] / src / global.c
blob127bf6456a4c3e92577aef424fe305b647604379
1 /*
2 Copyright (C) 2004-2008, 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 */
24 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
26 PARROT_WARN_UNUSED_RESULT
27 PARROT_CAN_RETURN_NULL
28 static PMC * get_namespace_pmc(PARROT_INTERP, ARGIN(PMC *sub))
29 __attribute__nonnull__(1)
30 __attribute__nonnull__(2);
32 PARROT_WARN_UNUSED_RESULT
33 PARROT_CAN_RETURN_NULL
34 static PMC * internal_ns_keyed(PARROT_INTERP,
35 ARGIN(PMC *base_ns),
36 ARGIN_NULLOK(PMC *pmc_key),
37 ARGIN_NULLOK(STRING *str_key),
38 int flags)
39 __attribute__nonnull__(1)
40 __attribute__nonnull__(2);
42 static void store_sub_in_multi(PARROT_INTERP,
43 ARGIN(PMC *sub),
44 ARGIN(PMC *ns))
45 __attribute__nonnull__(1)
46 __attribute__nonnull__(2)
47 __attribute__nonnull__(3);
49 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
50 /* HEADERIZER END: static */
52 #define DEBUG_GLOBAL 0
54 /* flags for internal_ns_keyed */
55 #define INTERN_NS_CREAT 1 /* I'm a fan of the classics */
59 =item C<static PMC * internal_ns_keyed>
61 internal_ns_keyed: Internal function to do keyed namespace lookup
62 relative to a given namespace PMC. Understands STRINGs, String PMCs,
63 Key pmcs, and array PMCs containing strings.
65 =cut
69 PARROT_WARN_UNUSED_RESULT
70 PARROT_CAN_RETURN_NULL
71 static PMC *
72 internal_ns_keyed(PARROT_INTERP, ARGIN(PMC *base_ns), ARGIN_NULLOK(PMC *pmc_key),
73 ARGIN_NULLOK(STRING *str_key), int flags)
75 PMC *ns, *sub_ns;
76 INTVAL i, n;
77 static const INTVAL max_intval = (INTVAL)((~(UINTVAL)0) >> 1); /*2s comp*/
79 ns = base_ns;
81 if (str_key)
82 n = 1;
83 else if (pmc_key->vtable->base_type == enum_class_String) {
84 str_key = VTABLE_get_string(interp, pmc_key);
85 n = 1;
87 else if (pmc_key->vtable->base_type == enum_class_Key)
88 n = max_intval; /* we don't yet know how big the key is */
89 else
90 n = VTABLE_elements(interp, pmc_key); /* array of strings */
92 for (i = 0; i < n; ++i) {
93 STRING *part;
95 if (str_key)
96 part = str_key;
97 else if (n == max_intval) {
98 if (!pmc_key)
99 Parrot_ex_throw_from_c_args(interp, NULL, 1,
100 "Trying to use a NULL PMC as a key");
102 part = VTABLE_get_string(interp, pmc_key);
103 pmc_key = key_next(interp, pmc_key);
105 if (!pmc_key)
106 n = i + 1; /* now we know how big the key is */
108 else {
109 if (!pmc_key)
110 Parrot_ex_throw_from_c_args(interp, NULL, 1,
111 "Passed a NULL pmc_key into VTABLE_get_string_keyed_int");
113 part = VTABLE_get_string_keyed_int(interp, pmc_key, i);
116 sub_ns = VTABLE_get_pmc_keyed_str(interp, ns, part);
118 if (PMC_IS_NULL(sub_ns)
119 /* RT#46157 - stop depending on typed namespace */
120 || sub_ns->vtable->base_type != enum_class_NameSpace)
122 if (!(flags & INTERN_NS_CREAT))
123 return PMCNULL;
125 /* RT#46159 - match HLL of enclosing namespace? */
126 sub_ns = pmc_new(interp,
127 Parrot_get_ctx_HLL_type(interp,
128 enum_class_NameSpace));
129 if (PMC_IS_NULL(sub_ns))
130 return PMCNULL;
131 VTABLE_set_pmc_keyed_str(interp, ns, part, sub_ns);
133 ns = sub_ns;
134 } /* for */
136 return ns;
141 =item C<PMC * Parrot_get_namespace_keyed>
143 Find the namespace relative to the namespace C<base_ns> with the key
144 C<pmc_key>, which may be a String, a Key, or an array of strings. Return
145 the namespace, or NULL if not found.
147 =cut
151 PARROT_API
152 PARROT_WARN_UNUSED_RESULT
153 PARROT_CAN_RETURN_NULL
154 PMC *
155 Parrot_get_namespace_keyed(PARROT_INTERP, ARGIN(PMC *base_ns), ARGIN_NULLOK(PMC *pmc_key))
157 return internal_ns_keyed(interp, base_ns, pmc_key, NULL, 0);
162 =item C<PMC * Parrot_get_namespace_keyed_str>
164 Find the namespace relative to the namespace C<base_ns> with the string key
165 C<str_key>. Return the namespace, or NULL if not found.
167 =cut
171 PARROT_API
172 PARROT_WARN_UNUSED_RESULT
173 PARROT_CAN_RETURN_NULL
174 PMC *
175 Parrot_get_namespace_keyed_str(PARROT_INTERP, ARGIN(PMC *base_ns),
176 ARGIN_NULLOK(STRING *str_key))
178 return internal_ns_keyed(interp, base_ns, PMCNULL, str_key, 0);
183 =item C<PMC * Parrot_make_namespace_keyed>
185 Find, or create if necessary, the namespace relative to the namespace
186 C<base_ns> with the key C<pmc_key>, which may be a String, a Key, or an
187 array of strings. Return the namespace. Errors will result in exceptions.
189 =cut
193 PARROT_API
194 PARROT_WARN_UNUSED_RESULT
195 PARROT_CAN_RETURN_NULL
196 PMC *
197 Parrot_make_namespace_keyed(PARROT_INTERP, ARGIN(PMC *base_ns),
198 ARGIN_NULLOK(PMC *pmc_key))
200 return internal_ns_keyed(interp, base_ns, pmc_key, NULL, INTERN_NS_CREAT);
205 =item C<PMC * Parrot_make_namespace_keyed_str>
207 Find, or create if necessary, the namespace relative to the namespace
208 C<base_ns> with the string key C<str_key>. Return the namespace. Errors
209 will result in exceptions.
211 =cut
215 PARROT_API
216 PARROT_WARN_UNUSED_RESULT
217 PARROT_CAN_RETURN_NULL
218 PMC *
219 Parrot_make_namespace_keyed_str(PARROT_INTERP, ARGIN(PMC *base_ns),
220 ARGIN_NULLOK(STRING *str_key))
222 return internal_ns_keyed(interp, base_ns, NULL, str_key, INTERN_NS_CREAT);
228 =item C<PMC * Parrot_make_namespace_autobase>
230 Find, or create if necessary, a namespace with the key C<key>, which may be a
231 String, a Key, or an array of strings. If it is a String, then the lookup is
232 relative to the current namespace. Otherwise, it is relative to the current HLL
233 root namespace. Return the namespace. Errors will result in exceptions.
235 =cut
239 PARROT_API
240 PARROT_WARN_UNUSED_RESULT
241 PARROT_CAN_RETURN_NULL
242 PMC *
243 Parrot_make_namespace_autobase(PARROT_INTERP, ARGIN_NULLOK(PMC *key))
245 PMC *base_ns;
246 if (VTABLE_isa(interp, key, CONST_STRING(interp, "String")))
247 base_ns = CONTEXT(interp)->current_namespace;
248 else
249 base_ns = VTABLE_get_pmc_keyed_int(interp, interp->HLL_namespace,
250 CONTEXT(interp)->current_HLL);
251 return Parrot_make_namespace_keyed(interp, base_ns, key);
256 =item C<PMC * Parrot_get_namespace_autobase>
258 Find a namespace with the key C<key>, which may be a String, a Key, or an
259 array of strings. If it is a String, then the lookup is relative to the
260 current namespace. Otherwise, it is relative to the current HLL root
261 namespace. Return the namespace, or NULL if not found.
263 =cut
267 PARROT_API
268 PARROT_WARN_UNUSED_RESULT
269 PARROT_CAN_RETURN_NULL
270 PMC *
271 Parrot_get_namespace_autobase(PARROT_INTERP, ARGIN_NULLOK(PMC *key))
273 PMC *base_ns;
274 if (VTABLE_isa(interp, key, CONST_STRING(interp, "String")))
275 base_ns = CONTEXT(interp)->current_namespace;
276 else
277 base_ns = VTABLE_get_pmc_keyed_int(interp, interp->HLL_namespace,
278 CONTEXT(interp)->current_HLL);
279 return Parrot_get_namespace_keyed(interp, base_ns, key);
284 =item C<PMC * Parrot_ns_get_name>
286 Retrieve an array of names from a namespace object.
288 =cut
292 PARROT_API
293 PARROT_WARN_UNUSED_RESULT
294 PARROT_CAN_RETURN_NULL
295 PMC *
296 Parrot_ns_get_name(PARROT_INTERP, ARGIN(PMC *_namespace))
298 PMC *names;
299 Parrot_PCCINVOKE(interp, _namespace,
300 CONST_STRING(interp, "get_name"), "->P", &names);
301 return names;
306 =item C<PMC * Parrot_get_global>
308 Parrot_get_global allows a null namespace without throwing an exception; it
309 simply returns PMCNULL in that case.
311 NOTE: At present the use of the {get, set}_global functions is mandatory due to the
312 wacky namespace typing of the default Parrot namespace. Eventually it will be
313 safe to just use the standard hash interface (if desired).
315 Look up the global named C<globalname> in the namespace C<ns>. Return the
316 global, or return PMCNULL if C<ns> is null or if the global is not found.
318 KLUDGE ALERT: Currently prefers non-namespaces in case of collision.
320 =cut
326 * {get, set}_global.
328 * Parrot_get_global allows a null namespace without throwing an exception; it
329 * simply returns PMCNULL in that case.
331 * NOTE: At present the use of the {get, set}_global functions is mandatory due to the
332 * wacky namespace typing of the default Parrot namespace. Eventually it will be
333 * safe to just use the standard hash interface (if desired).
336 PARROT_API
337 PARROT_WARN_UNUSED_RESULT
338 PARROT_CAN_RETURN_NULL
339 PMC *
340 Parrot_get_global(PARROT_INTERP, ARGIN_NULLOK(PMC *ns), ARGIN_NULLOK(STRING *globalname))
342 if (PMC_IS_NULL(ns))
343 return PMCNULL;
345 return (PMC *)VTABLE_get_pointer_keyed_str(interp, ns, globalname);
350 =item C<void Parrot_set_global>
352 Set the global named C<globalname> in the namespace C<ns> to the value C<val>.
354 =cut
358 PARROT_API
359 void
360 Parrot_set_global(PARROT_INTERP, ARGIN_NULLOK(PMC *ns),
361 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
363 VTABLE_set_pmc_keyed_str(interp, ns, globalname, val);
369 =item C<PMC * Parrot_find_global_n>
371 Search the namespace PMC C<ns> for an object with name C<globalname>.
372 Return the object, or NULL if not found.
374 RT#46161 - For now this function prefers non-namespaces, it will eventually
375 entirely use the untyped interface.
377 =cut
381 PARROT_API
382 PARROT_WARN_UNUSED_RESULT
383 PARROT_CAN_RETURN_NULL
384 PMC *
385 Parrot_find_global_n(PARROT_INTERP, ARGIN_NULLOK(PMC *ns), ARGIN_NULLOK(STRING *globalname))
387 PMC *res;
389 #if DEBUG_GLOBAL
390 if (globalname)
391 PIO_printf(interp, "find_global name '%Ss'\n", globalname);
392 #endif
394 if (PMC_IS_NULL(ns))
395 res = PMCNULL;
396 else {
398 * RT#46163 - we should be able to use 'get_pmc_keyed' here,
399 * but we can't because Parrot's default namespaces are not
400 * fully typed and there's a pseudo-typed interface that
401 * distinguishes 'get_pmc_keyed' from 'get_pointer_keyed';
402 * the former is for NS and the latter is for non-NS.
404 res = (PMC *)VTABLE_get_pointer_keyed_str(interp, ns, globalname);
407 return PMC_IS_NULL(res) ? NULL : res;
412 =item C<PMC * Parrot_find_global_cur>
414 Finds and returns the data time named C<globalname> in the current namespace.
416 =cut
420 PARROT_API
421 PARROT_WARN_UNUSED_RESULT
422 PARROT_CAN_RETURN_NULL
423 PMC *
424 Parrot_find_global_cur(PARROT_INTERP, ARGIN_NULLOK(STRING *globalname))
426 PMC * const ns = CONTEXT(interp)->current_namespace;
427 return Parrot_find_global_n(interp, ns, globalname);
432 =item C<PMC * Parrot_find_global_k>
434 Search the namespace designated by C<pmc_key>, which may be a key PMC,
435 an array of namespace name strings, or a string PMC, for an object
436 with name C<globalname>. Return the object, or NULL if not found.
438 RT#46161 - For now this function prefers non-namespaces, it will eventually
439 entirely use the untyped interface.
441 =cut
445 PARROT_API
446 PARROT_WARN_UNUSED_RESULT
447 PARROT_CAN_RETURN_NULL
448 PMC *
449 Parrot_find_global_k(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc_key), ARGIN(STRING *globalname))
451 PMC * const ns =
452 Parrot_get_namespace_keyed(interp,
453 Parrot_get_ctx_HLL_namespace(interp),
454 pmc_key);
455 return Parrot_find_global_n(interp, ns, globalname);
460 =item C<PMC * Parrot_find_global_s>
462 Search the namespace designated by C<str_key>, or the HLL root if
463 C<str_key> is NULL, for an object with name C<globalname>. Return the
464 object, or NULL if not found.
466 RT#46161 - For now this function prefers non-namespaces, it will eventually
467 entirely use the untyped interface.
469 =cut
473 PARROT_API
474 PARROT_WARN_UNUSED_RESULT
475 PARROT_CAN_RETURN_NULL
476 PMC *
477 Parrot_find_global_s(PARROT_INTERP, ARGIN_NULLOK(STRING *str_key),
478 ARGIN_NULLOK(STRING *globalname))
480 PMC *const ns =
481 Parrot_get_namespace_keyed_str(interp,
482 Parrot_get_ctx_HLL_namespace(interp),
483 str_key);
484 return Parrot_find_global_n(interp, ns, globalname);
489 =item C<void Parrot_store_global_n>
491 Store the PMC C<val> into the namespace PMC C<ns> with name C<globalname>.
493 =cut
497 PARROT_API
498 void
499 Parrot_store_global_n(PARROT_INTERP, ARGIN_NULLOK(PMC *ns),
500 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
502 #if DEBUG_GLOBAL
503 if (globalname)
504 PIO_printf(interp, "store_global name '%Ss'\n", globalname);
505 #endif
507 if (PMC_IS_NULL(ns))
508 return;
510 VTABLE_set_pmc_keyed_str(interp, ns, globalname, val);
515 =item C<void Parrot_store_global_cur>
517 Store the value C<val> with name C<globalname> in the current namespace.
519 =cut
523 PARROT_API
524 void
525 Parrot_store_global_cur(PARROT_INTERP, ARGIN_NULLOK(STRING *globalname),
526 ARGIN_NULLOK(PMC *val))
528 Parrot_store_global_n(interp,
529 CONTEXT(interp)->current_namespace,
530 globalname, val);
532 /* RT#46165 - method cache invalidation should occur */
537 =item C<void Parrot_store_global_k>
539 Store the PMC C<val> into the namespace designated by C<pmc_key>,
540 which may be a key PMC, an array of namespace name strings, or a
541 string PMC, with name C<globalname>.
543 RT#46161 - For now this function prefers non-namespaces, it will eventually
544 entirely use the untyped interface.
546 =cut
550 PARROT_API
551 void
552 Parrot_store_global_k(PARROT_INTERP, ARGIN(PMC *pmc_key),
553 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
555 PMC *ns;
558 * RT#46167 - temporary hack to notice when key is actually a string, so that
559 * the legacy logic for invalidating method cache will be called; this is
560 * not good enough but it avoids regressesions for now
562 if (pmc_key->vtable->base_type == enum_class_String) {
563 Parrot_store_global_s(interp, PMC_str_val(pmc_key),
564 globalname, val);
565 return;
568 ns = Parrot_make_namespace_keyed(interp,
569 Parrot_get_ctx_HLL_namespace(interp),
570 pmc_key);
572 Parrot_store_global_n(interp, ns, globalname, val);
574 /* RT#46165 - method cache invalidation should occur */
579 =item C<void Parrot_store_global_s>
581 Store the PMC C<val> into the namespace designated by C<str_key>, or
582 the HLL root if C<str_key> is NULL, with the name C<globalname>.
584 =cut
588 PARROT_API
589 void
590 Parrot_store_global_s(PARROT_INTERP, ARGIN_NULLOK(STRING *str_key),
591 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
593 PMC * const ns = Parrot_make_namespace_keyed_str(interp,
594 Parrot_get_ctx_HLL_namespace(interp),
595 str_key);
597 Parrot_store_global_n(interp, ns, globalname, val);
599 /* RT#46169 - method cache invalidation should be a namespace function */
600 Parrot_invalidate_method_cache(interp, str_key, globalname);
606 =item C<PMC * Parrot_find_global_op>
608 If the global exists in the given namespace PMC, return it. If not, return
609 PMCNULL.
611 =cut
615 PARROT_API
616 PARROT_WARN_UNUSED_RESULT
617 PARROT_CANNOT_RETURN_NULL
618 PMC *
619 Parrot_find_global_op(PARROT_INTERP, ARGIN(PMC *ns),
620 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(void *next))
622 PMC *res;
624 if (!globalname)
625 Parrot_ex_throw_from_c_args(interp, next, EXCEPTION_GLOBAL_NOT_FOUND,
626 "Tried to get null global");
628 res = Parrot_find_global_n(interp, ns, globalname);
629 if (!res)
630 res = PMCNULL;
632 return res;
638 =item C<PMC * Parrot_find_name_op>
640 RT#46171 - THIS IS BROKEN - it doesn't walk up the scopes yet
642 Find the given C<name> in lexicals, then the current namespace, then the HLL
643 root namespace, and finally Parrot builtins. If the name isn't found
644 anywhere, return PMCNULL.
646 =cut
650 PARROT_API
651 PARROT_WARN_UNUSED_RESULT
652 PARROT_CAN_RETURN_NULL
653 PMC *
654 Parrot_find_name_op(PARROT_INTERP, ARGIN(STRING *name), SHIM(void *next))
656 parrot_context_t * const ctx = CONTEXT(interp);
657 PMC * const lex_pad = Parrot_find_pad(interp, name, ctx);
658 PMC *g;
660 if (PMC_IS_NULL(lex_pad))
661 g = PMCNULL;
662 else
663 g = VTABLE_get_pmc_keyed_str(interp, lex_pad, name);
665 /* RT#46171 - walk up the scopes! duh!! */
667 if (PMC_IS_NULL(g))
668 g = Parrot_find_global_cur(interp, name);
670 if (PMC_IS_NULL(g))
671 g = Parrot_find_global_n(interp, Parrot_get_ctx_HLL_namespace(interp), name);
673 if (PMC_IS_NULL(g))
674 return PMCNULL;
675 else
676 return g;
681 =item C<static PMC * get_namespace_pmc>
683 Return the namespace PMC associated with the PMC C<sub>. If C<sub> is NULL,
684 return the Associated HLL namespace PMC instead.
686 =cut
690 PARROT_WARN_UNUSED_RESULT
691 PARROT_CAN_RETURN_NULL
692 static PMC *
693 get_namespace_pmc(PARROT_INTERP, ARGIN(PMC *sub))
695 PMC * const nsname = PMC_sub(sub)->namespace_name;
696 PMC * const nsroot = Parrot_get_HLL_namespace(interp, PMC_sub(sub)->HLL_id);
698 /* If we have a NULL, return the HLL namespace */
699 if (PMC_IS_NULL(nsname))
700 return nsroot;
701 /* If we have a String, do a string lookup */
702 else if (nsname->vtable->base_type == enum_class_String)
703 return Parrot_make_namespace_keyed_str(interp, nsroot, PMC_str_val(nsname));
704 /* Otherwise, do a PMC lookup */
705 else
706 return Parrot_make_namespace_keyed(interp, nsroot, nsname);
711 =item C<static void store_sub_in_multi>
713 Adds the sub C<sub> into a mulisub of the same name in the namespace C<ns>.
714 If no multisub by that name currently exists, we create one.
716 =cut
720 static void
721 store_sub_in_multi(PARROT_INTERP, ARGIN(PMC *sub), ARGIN(PMC *ns))
723 INTVAL func_nr;
724 char *c_meth;
725 STRING * const subname = PMC_sub(sub)->name;
726 PMC *multisub = VTABLE_get_pmc_keyed_str(interp, ns, subname);
728 /* is there an existing MultiSub PMC? or do we need to create one? */
729 if (PMC_IS_NULL(multisub)) {
730 multisub = pmc_new(interp, enum_class_MultiSub);
731 /* we have to push the sub onto the MultiSub before we try to store
732 it because storing requires information from the sub */
733 VTABLE_push_pmc(interp, multisub, sub);
734 VTABLE_set_pmc_keyed_str(interp, ns, subname, multisub);
736 else
737 VTABLE_push_pmc(interp, multisub, sub);
739 c_meth = string_to_cstring(interp, subname);
740 func_nr = Parrot_MMD_method_idx(interp, c_meth);
741 if (func_nr >= 0)
742 Parrot_mmd_rebuild_table(interp, -1, func_nr);
743 string_cstring_free(c_meth);
748 =item C<void Parrot_store_sub_in_namespace>
750 Adds the PMC C<sub> into the current namespace. Adds the sub to a multi of the
751 same name if it's defined as a multi.
753 =cut
757 PARROT_API
758 void
759 Parrot_store_sub_in_namespace(PARROT_INTERP, ARGIN(PMC *sub))
761 const INTVAL cur_id = CONTEXT(interp)->current_HLL;
763 PMC *ns;
764 /* PF structures aren't fully constructed yet */
765 Parrot_block_GC_mark(interp);
766 /* store relative to HLL namespace */
767 CONTEXT(interp)->current_HLL = PMC_sub(sub)->HLL_id;
769 ns = get_namespace_pmc(interp, sub);
771 /* attach a namespace to the sub for lookups */
772 PMC_sub(sub)->namespace_stash = ns;
774 /* store a :multi sub */
775 if (!PMC_IS_NULL(PMC_sub(sub)->multi_signature))
776 store_sub_in_multi(interp, sub, ns);
777 /* store other subs (as long as they're not :anon) */
778 else if (!(PObj_get_FLAGS(sub) & SUB_FLAG_PF_ANON)) {
779 STRING * const name = PMC_sub(sub)->name;
780 PMC * const nsname = PMC_sub(sub)->namespace_name;
782 Parrot_store_global_n(interp, ns, name, sub);
784 /* TEMPORARY HACK - cache invalidation should be a namespace function */
785 if (!PMC_IS_NULL(nsname)) {
786 STRING * const nsname_s = VTABLE_get_string(interp, nsname);
787 Parrot_invalidate_method_cache(interp, nsname_s, name);
791 /* restore HLL_id */
792 CONTEXT(interp)->current_HLL = cur_id;
793 Parrot_unblock_GC_mark(interp);
798 =back
800 =head1 SEE ALSO
802 F<include/parrot/global.h>
804 =cut
810 * Local variables:
811 * c-file-style: "parrot"
812 * End:
813 * vim: expandtab shiftwidth=4: