* t/op/lexicals-2.t (added), MANIFEST:
[parrot.git] / src / global.c
blob4927d0d884957cbf130644d411a94e2a7facd8ac
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 */
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 real_exception(interp, NULL, 1,
100 "Passing a NULL pmc_key into key_string()");
102 part = key_string(interp, pmc_key);
103 pmc_key = key_next(interp, pmc_key);
104 if (! pmc_key)
105 n = i + 1; /* now we know how big the key is */
107 else {
108 if (!pmc_key) {
109 real_exception(interp, NULL, 1,
110 "Passed a NULL pmc_key into VTABLE_get_string_keyed_int");
112 part = VTABLE_get_string_keyed_int(interp, pmc_key, i);
115 sub_ns = VTABLE_get_pmc_keyed_str(interp, ns, part);
117 if (PMC_IS_NULL(sub_ns)
118 /* RT#46157 - stop depending on typed namespace */
119 || sub_ns->vtable->base_type != enum_class_NameSpace)
121 if (!(flags & INTERN_NS_CREAT))
122 return PMCNULL;
124 /* RT#46159 - match HLL of enclosing namespace? */
125 sub_ns = pmc_new(interp,
126 Parrot_get_ctx_HLL_type(interp,
127 enum_class_NameSpace));
128 if (PMC_IS_NULL(sub_ns))
129 return PMCNULL;
130 VTABLE_set_pmc_keyed_str(interp, ns, part, sub_ns);
132 ns = sub_ns;
133 } /* for */
135 return ns;
140 =item C<PMC * Parrot_get_namespace_keyed>
142 Find the namespace relative to the namespace C<base_ns> with the key
143 C<pmc_key>, which may be a String, a Key, or an array of strings. Return
144 the namespace, or NULL if not found.
146 =cut
150 PARROT_API
151 PARROT_WARN_UNUSED_RESULT
152 PARROT_CAN_RETURN_NULL
153 PMC *
154 Parrot_get_namespace_keyed(PARROT_INTERP, ARGIN(PMC *base_ns), ARGIN_NULLOK(PMC *pmc_key))
156 return internal_ns_keyed(interp, base_ns, pmc_key, NULL, 0);
161 =item C<PMC * Parrot_get_namespace_keyed_str>
163 Find the namespace relative to the namespace C<base_ns> with the string key
164 C<str_key>. Return the namespace, or NULL if not found.
166 =cut
170 PARROT_API
171 PARROT_WARN_UNUSED_RESULT
172 PARROT_CAN_RETURN_NULL
173 PMC *
174 Parrot_get_namespace_keyed_str(PARROT_INTERP, ARGIN(PMC *base_ns),
175 ARGIN_NULLOK(STRING *str_key))
177 return internal_ns_keyed(interp, base_ns, PMCNULL, str_key, 0);
182 =item C<PMC * Parrot_make_namespace_keyed>
184 Find, or create if necessary, the namespace relative to the namespace
185 C<base_ns> with the key C<pmc_key>, which may be a String, a Key, or an
186 array of strings. Return the namespace. Errors will result in exceptions.
188 =cut
192 PARROT_API
193 PARROT_WARN_UNUSED_RESULT
194 PARROT_CAN_RETURN_NULL
195 PMC *
196 Parrot_make_namespace_keyed(PARROT_INTERP, ARGIN(PMC *base_ns),
197 ARGIN_NULLOK(PMC *pmc_key))
199 return internal_ns_keyed(interp, base_ns, pmc_key, NULL, INTERN_NS_CREAT);
204 =item C<PMC * Parrot_make_namespace_keyed_str>
206 Find, or create if necessary, the namespace relative to the namespace
207 C<base_ns> with the string key C<str_key>. Return the namespace. Errors
208 will result in exceptions.
210 =cut
214 PARROT_API
215 PARROT_WARN_UNUSED_RESULT
216 PARROT_CAN_RETURN_NULL
217 PMC *
218 Parrot_make_namespace_keyed_str(PARROT_INTERP, ARGIN(PMC *base_ns),
219 ARGIN_NULLOK(STRING *str_key))
221 return internal_ns_keyed(interp, base_ns, NULL, str_key, INTERN_NS_CREAT);
227 =item C<PMC * Parrot_make_namespace_autobase>
229 Find, or create if necessary, a namespace with the key C<key>, which may be a
230 String, a Key, or an array of strings. If it is a String, then the lookup is
231 relative to the current namespace. Otherwise, it is relative to the current HLL
232 root namespace. Return the namespace. Errors will result in exceptions.
234 =cut
238 PARROT_API
239 PARROT_WARN_UNUSED_RESULT
240 PARROT_CAN_RETURN_NULL
241 PMC *
242 Parrot_make_namespace_autobase(PARROT_INTERP, ARGIN_NULLOK(PMC *key))
244 PMC *base_ns;
245 if (VTABLE_isa(interp, key, CONST_STRING(interp, "String")))
246 base_ns = CONTEXT(interp)->current_namespace;
247 else
248 base_ns = VTABLE_get_pmc_keyed_int(interp, interp->HLL_namespace,
249 CONTEXT(interp)->current_HLL);
250 return Parrot_make_namespace_keyed(interp, base_ns, key);
255 =item C<PMC * Parrot_get_namespace_autobase>
257 Find a namespace with the key C<key>, which may be a String, a Key, or an
258 array of strings. If it is a String, then the lookup is relative to the
259 current namespace. Otherwise, it is relative to the current HLL root
260 namespace. Return the namespace, or NULL if not found.
262 =cut
266 PARROT_API
267 PARROT_WARN_UNUSED_RESULT
268 PARROT_CAN_RETURN_NULL
269 PMC *
270 Parrot_get_namespace_autobase(PARROT_INTERP, ARGIN_NULLOK(PMC *key))
272 PMC *base_ns;
273 if (VTABLE_isa(interp, key, CONST_STRING(interp, "String")))
274 base_ns = CONTEXT(interp)->current_namespace;
275 else
276 base_ns = VTABLE_get_pmc_keyed_int(interp, interp->HLL_namespace,
277 CONTEXT(interp)->current_HLL);
278 return Parrot_get_namespace_keyed(interp, base_ns, key);
283 =item C<PMC * Parrot_ns_get_name>
285 Retrieve an array of names from a namespace object.
287 =cut
291 PARROT_API
292 PARROT_WARN_UNUSED_RESULT
293 PARROT_CAN_RETURN_NULL
294 PMC *
295 Parrot_ns_get_name(PARROT_INTERP, ARGIN(PMC *_namespace))
297 PMC *names;
298 Parrot_PCCINVOKE(interp, _namespace,
299 CONST_STRING(interp, "get_name"), "->P", &names);
300 return names;
305 =item C<PMC * Parrot_get_global>
307 Parrot_get_global allows a null namespace without throwing an exception; it
308 simply returns PMCNULL in that case.
310 NOTE: At present the use of the {get, set}_global functions is mandatory due to the
311 wacky namespace typing of the default Parrot namespace. Eventually it will be
312 safe to just use the standard hash interface (if desired).
314 Look up the global named C<globalname> in the namespace C<ns>. Return the
315 global, or return PMCNULL if C<ns> is null or if the global is not found.
317 KLUDGE ALERT: Currently prefers non-namespaces in case of collision.
319 =cut
325 * {get, set}_global.
327 * Parrot_get_global allows a null namespace without throwing an exception; it
328 * simply returns PMCNULL in that case.
330 * NOTE: At present the use of the {get, set}_global functions is mandatory due to the
331 * wacky namespace typing of the default Parrot namespace. Eventually it will be
332 * safe to just use the standard hash interface (if desired).
335 PARROT_API
336 PARROT_WARN_UNUSED_RESULT
337 PARROT_CAN_RETURN_NULL
338 PMC *
339 Parrot_get_global(PARROT_INTERP, ARGIN_NULLOK(PMC *ns), ARGIN_NULLOK(STRING *globalname))
341 if (PMC_IS_NULL(ns))
342 return PMCNULL;
344 return (PMC *)VTABLE_get_pointer_keyed_str(interp, ns, globalname);
349 =item C<void Parrot_set_global>
351 Set the global named C<globalname> in the namespace C<ns> to the value C<val>.
353 =cut
357 PARROT_API
358 void
359 Parrot_set_global(PARROT_INTERP, ARGIN_NULLOK(PMC *ns),
360 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
362 VTABLE_set_pmc_keyed_str(interp, ns, globalname, val);
368 =item C<PMC * Parrot_find_global_n>
370 Search the namespace PMC C<ns> for an object with name C<globalname>.
371 Return the object, or NULL if not found.
373 RT#46161 - For now this function prefers non-namespaces, it will eventually
374 entirely use the untyped interface.
376 =cut
380 PARROT_API
381 PARROT_WARN_UNUSED_RESULT
382 PARROT_CAN_RETURN_NULL
383 PMC *
384 Parrot_find_global_n(PARROT_INTERP, ARGIN_NULLOK(PMC *ns), ARGIN_NULLOK(STRING *globalname))
386 PMC *res;
388 #if DEBUG_GLOBAL
389 if (globalname)
390 PIO_printf(interp, "find_global name '%Ss'\n", globalname);
391 #endif
393 if (PMC_IS_NULL(ns))
394 res = PMCNULL;
395 else {
397 * RT#46163 - we should be able to use 'get_pmc_keyed' here,
398 * but we can't because Parrot's default namespaces are not
399 * fully typed and there's a pseudo-typed interface that
400 * distinguishes 'get_pmc_keyed' from 'get_pointer_keyed';
401 * the former is for NS and the latter is for non-NS.
403 res = (PMC *)VTABLE_get_pointer_keyed_str(interp, ns, globalname);
406 return PMC_IS_NULL(res) ? NULL : res;
411 =item C<PMC * Parrot_find_global_cur>
413 RT#48260: Not yet documented!!!
415 =cut
419 PARROT_API
420 PARROT_WARN_UNUSED_RESULT
421 PARROT_CAN_RETURN_NULL
422 PMC *
423 Parrot_find_global_cur(PARROT_INTERP, ARGIN_NULLOK(STRING *globalname))
425 PMC * const ns = CONTEXT(interp)->current_namespace;
426 return Parrot_find_global_n(interp, ns, globalname);
431 =item C<PMC * Parrot_find_global_k>
433 Search the namespace designated by C<pmc_key>, which may be a key PMC,
434 an array of namespace name strings, or a string PMC, for an object
435 with name C<globalname>. Return the object, or NULL if not found.
437 RT#46161 - For now this function prefers non-namespaces, it will eventually
438 entirely use the untyped interface.
440 =cut
444 PARROT_API
445 PARROT_WARN_UNUSED_RESULT
446 PARROT_CAN_RETURN_NULL
447 PMC *
448 Parrot_find_global_k(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc_key), ARGIN(STRING *globalname))
450 PMC * const ns =
451 Parrot_get_namespace_keyed(interp,
452 Parrot_get_ctx_HLL_namespace(interp),
453 pmc_key);
454 return Parrot_find_global_n(interp, ns, globalname);
459 =item C<PMC * Parrot_find_global_s>
461 Search the namespace designated by C<str_key>, or the HLL root if
462 C<str_key> is NULL, for an object with name C<globalname>. Return the
463 object, or NULL if not found.
465 RT#46161 - For now this function prefers non-namespaces, it will eventually
466 entirely use the untyped interface.
468 =cut
472 PARROT_API
473 PARROT_WARN_UNUSED_RESULT
474 PARROT_CAN_RETURN_NULL
475 PMC *
476 Parrot_find_global_s(PARROT_INTERP, ARGIN_NULLOK(STRING *str_key),
477 ARGIN_NULLOK(STRING *globalname))
479 PMC *const ns =
480 Parrot_get_namespace_keyed_str(interp,
481 Parrot_get_ctx_HLL_namespace(interp),
482 str_key);
483 return Parrot_find_global_n(interp, ns, globalname);
488 =item C<void Parrot_store_global_n>
490 Store the PMC C<val> into the namespace PMC C<ns> with name C<globalname>.
492 =cut
496 PARROT_API
497 void
498 Parrot_store_global_n(PARROT_INTERP, ARGIN_NULLOK(PMC *ns),
499 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
501 #if DEBUG_GLOBAL
502 if (globalname)
503 PIO_printf(interp, "store_global name '%Ss'\n", globalname);
504 #endif
506 if (PMC_IS_NULL(ns))
507 return;
509 VTABLE_set_pmc_keyed_str(interp, ns, globalname, val);
514 =item C<void Parrot_store_global_cur>
516 RT#48260: Not yet documented!!!
518 =cut
522 PARROT_API
523 void
524 Parrot_store_global_cur(PARROT_INTERP, ARGIN_NULLOK(STRING *globalname),
525 ARGIN_NULLOK(PMC *val))
527 Parrot_store_global_n(interp,
528 CONTEXT(interp)->current_namespace,
529 globalname, val);
531 /* RT#46165 - method cache invalidation should occur */
536 =item C<void Parrot_store_global_k>
538 Store the PMC C<val> into the namespace designated by C<pmc_key>,
539 which may be a key PMC, an array of namespace name strings, or a
540 string PMC, with name C<globalname>.
542 RT#46161 - For now this function prefers non-namespaces, it will eventually
543 entirely use the untyped interface.
545 =cut
549 PARROT_API
550 void
551 Parrot_store_global_k(PARROT_INTERP, ARGIN(PMC *pmc_key),
552 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
554 PMC *ns;
557 * RT#46167 - temporary hack to notice when key is actually a string, so that
558 * the legacy logic for invalidating method cache will be called; this is
559 * not good enough but it avoids regressesions for now
561 if (pmc_key->vtable->base_type == enum_class_String) {
562 Parrot_store_global_s(interp, PMC_str_val(pmc_key),
563 globalname, val);
564 return;
567 ns = Parrot_make_namespace_keyed(interp,
568 Parrot_get_ctx_HLL_namespace(interp),
569 pmc_key);
571 Parrot_store_global_n(interp, ns, globalname, val);
573 /* RT#46165 - method cache invalidation should occur */
578 =item C<void Parrot_store_global_s>
580 Store the PMC C<val> into the namespace designated by C<str_key>, or
581 the HLL root if C<str_key> is NULL, with the name C<globalname>.
583 =cut
587 PARROT_API
588 void
589 Parrot_store_global_s(PARROT_INTERP, ARGIN_NULLOK(STRING *str_key),
590 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(PMC *val))
592 PMC * const ns = Parrot_make_namespace_keyed_str(interp,
593 Parrot_get_ctx_HLL_namespace(interp),
594 str_key);
596 Parrot_store_global_n(interp, ns, globalname, val);
598 /* RT#46169 - method cache invalidation should be a namespace function */
599 Parrot_invalidate_method_cache(interp, str_key, globalname);
605 =item C<PMC * Parrot_find_global_op>
607 If the global exists in the given namespace PMC, return it. If not, return
608 PMCNULL.
610 =cut
614 PARROT_API
615 PARROT_WARN_UNUSED_RESULT
616 PARROT_CANNOT_RETURN_NULL
617 PMC *
618 Parrot_find_global_op(PARROT_INTERP, ARGIN(PMC *ns),
619 ARGIN_NULLOK(STRING *globalname), ARGIN_NULLOK(void *next))
621 PMC *res;
623 if (!globalname)
624 real_exception(interp, next, E_NameError,
625 "Tried to get null global");
627 res = Parrot_find_global_n(interp, ns, globalname);
628 if (!res)
629 res = PMCNULL;
631 return res;
637 =item C<PMC * Parrot_find_name_op>
639 RT#46171 - THIS IS BROKEN - it doesn't walk up the scopes yet
641 Find the given C<name> in lexicals, then the current namespace, then the HLL
642 root namespace, and finally Parrot builtins. If the name isn't found
643 anywhere, return PMCNULL.
645 =cut
649 PARROT_API
650 PARROT_WARN_UNUSED_RESULT
651 PARROT_CAN_RETURN_NULL
652 PMC *
653 Parrot_find_name_op(PARROT_INTERP, ARGIN(STRING *name), SHIM(void *next))
655 parrot_context_t * const ctx = CONTEXT(interp);
656 PMC * const lex_pad = Parrot_find_pad(interp, name, ctx);
657 PMC *g;
659 if (PMC_IS_NULL(lex_pad))
660 g = PMCNULL;
661 else
662 g = VTABLE_get_pmc_keyed_str(interp, lex_pad, name);
664 /* RT#46171 - walk up the scopes! duh!! */
666 if (PMC_IS_NULL(g)) {
667 g = Parrot_find_global_cur(interp, name);
669 if (PMC_IS_NULL(g)) {
670 g = Parrot_find_global_n(interp,
671 Parrot_get_ctx_HLL_namespace(interp), name);
673 if (PMC_IS_NULL(g)) {
674 g = Parrot_find_builtin(interp, name);
679 if (PMC_IS_NULL(g))
680 return PMCNULL;
681 else
682 return g;
687 =item C<static PMC * get_namespace_pmc>
689 RT#48260: Not yet documented!!!
691 =cut
695 PARROT_WARN_UNUSED_RESULT
696 PARROT_CAN_RETURN_NULL
697 static PMC *
698 get_namespace_pmc(PARROT_INTERP, ARGIN(PMC *sub))
700 PMC * const nsname = PMC_sub(sub)->namespace_name;
701 PMC * const nsroot = Parrot_get_HLL_namespace(interp, PMC_sub(sub)->HLL_id);
703 /* If we have a NULL, return the HLL namespace */
704 if (PMC_IS_NULL(nsname))
705 return nsroot;
706 /* If we have a String, do a string lookup */
707 else if (nsname->vtable->base_type == enum_class_String)
708 return Parrot_make_namespace_keyed_str(interp, nsroot, PMC_str_val(nsname));
709 /* Otherwise, do a PMC lookup */
710 else
711 return Parrot_make_namespace_keyed(interp, nsroot, nsname);
716 =item C<static void store_sub_in_multi>
718 RT#48260: Not yet documented!!!
720 =cut
724 static void
725 store_sub_in_multi(PARROT_INTERP, ARGIN(PMC *sub), ARGIN(PMC *ns))
727 INTVAL func_nr;
728 char *c_meth;
729 STRING * const subname = PMC_sub(sub)->name;
730 PMC *multisub = VTABLE_get_pmc_keyed_str(interp, ns, subname);
732 /* is there an existing MultiSub PMC? or do we need to create one? */
733 if (PMC_IS_NULL(multisub)) {
734 multisub = pmc_new(interp, enum_class_MultiSub);
735 /* we have to push the sub onto the MultiSub before we try to store
736 it because storing requires information from the sub */
737 VTABLE_push_pmc(interp, multisub, sub);
738 VTABLE_set_pmc_keyed_str(interp, ns, subname, multisub);
740 else
741 VTABLE_push_pmc(interp, multisub, sub);
743 c_meth = string_to_cstring(interp, subname);
744 func_nr = Parrot_MMD_method_idx(interp, c_meth);
745 if (func_nr >= 0)
746 Parrot_mmd_rebuild_table(interp, -1, func_nr);
747 string_cstring_free(c_meth);
752 =item C<void Parrot_store_sub_in_namespace>
754 RT#48260: Not yet documented!!!
756 =cut
760 PARROT_API
761 void
762 Parrot_store_sub_in_namespace(PARROT_INTERP, ARGIN(PMC *sub))
764 const INTVAL cur_id = CONTEXT(interp)->current_HLL;
766 PMC *ns;
767 /* PF structures aren't fully constructed yet */
768 Parrot_block_GC_mark(interp);
769 /* store relative to HLL namespace */
770 CONTEXT(interp)->current_HLL = PMC_sub(sub)->HLL_id;
772 ns = get_namespace_pmc(interp, sub);
774 /* attach a namespace to the sub for lookups */
775 PMC_sub(sub)->namespace_stash = ns;
777 /* store a :multi sub */
778 if (!PMC_IS_NULL(PMC_sub(sub)->multi_signature))
779 store_sub_in_multi(interp, sub, ns);
780 /* store other subs (as long as they're not :anon) */
781 else if (!(PObj_get_FLAGS(sub) & SUB_FLAG_PF_ANON)) {
782 STRING * const name = PMC_sub(sub)->name;
783 PMC * const nsname = PMC_sub(sub)->namespace_name;
785 Parrot_store_global_n(interp, ns, name, sub);
787 /* TEMPORARY HACK - cache invalidation should be a namespace function */
788 if (!PMC_IS_NULL(nsname)) {
789 STRING * const nsname_s = VTABLE_get_string(interp, nsname);
790 Parrot_invalidate_method_cache(interp, nsname_s, name);
794 /* restore HLL_id */
795 CONTEXT(interp)->current_HLL = cur_id;
796 Parrot_unblock_GC_mark(interp);
801 =back
803 =head1 SEE ALSO
805 F<include/parrot/global.h>
807 =cut
813 * Local variables:
814 * c-file-style: "parrot"
815 * End:
816 * vim: expandtab shiftwidth=4: