fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pmc / pmcproxy.pmc
blob42f8133d4276d7adc223f07639b85a66b906fd67
1 /*
2 Copyright (C) 2001-2008, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/pmcproxy.pmc - proxy class object for a PMC enabling introspection
9 =head1 DESCRIPTION
11 This class is used to describe a PMC. It can sit in an inheritance hierarchy
12 of a PDD15 class as well as allowing introspection of the PMC.
14 PMCProxy is not derived from any other PMC.
16 =head2 Structure
18 This class stores its state in the Parrot_Class structure, using the
19 following fields.
21 =over 4
23 =item C<id>
25 The type number of the PMC that is being described.
27 =item C<name>
29 The name of the PMC -- a STRING.
31 =item C<namespace>
33 The namespace the PMC is associated with, if any.
35 =item C<parents>
37 An array of immediate parent classes.
38 An empty ResizablePMCArray PMC is allocated during initialization.
40 =item C<all_parents>
42 A cached array of ourself and all parent classes, in MRO order.
43 A ResizablePMCArray PMC is allocated during initialization,
44 and is populated with the current class.
46 =back
48 NOTE: No doubt we will need other things later; this is a start.
50 =cut
54 #include "parrot/oo_private.h"
58 =head2 Functions
60 =over 4
62 =cut
66 /* HEADERIZER HFILE: none */
67 /* HEADERIZER BEGIN: static */
68 /* HEADERIZER END: static */
71 pmclass PMCProxy extends Class auto_attrs {
75 =item C<void init()>
77 Initializes a PMCProxy PMC.
79 =cut
83     VTABLE void init() {
84         Parrot_PMCProxy_attributes * const _pmc = PARROT_PMCPROXY(SELF);
85         STRING                     * const name = CONST_STRING(INTERP, "proxy");
86         PMC                        * const new_attribute
87              = Parrot_pmc_new(INTERP, enum_class_Hash);
89         SUPER();
91         /* Set up the attribute storage for the proxy instance */
92         VTABLE_set_string_keyed_str(INTERP, new_attribute, CONST_STRING(INTERP, "name"), name);
93         VTABLE_set_pmc_keyed_str(INTERP, _pmc->attrib_metadata, name, new_attribute);
95         CLASS_is_anon_CLEAR(SELF);
96     }
98     VTABLE void init_int(INTVAL type_num) {
99         Parrot_Class_attributes *proxy_info;
100         INTVAL mro_length, i;
102         /* Ensure that it's a valid type number. */
103         if (type_num > INTERP->n_vtable_max || type_num <= 0)
104             Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
105                 "Attempt to create PMC Proxy for invalid type number!");
107         /* Set up the object. */
108         SELF.init();
110         /* Set up number, name and namespace. */
111         proxy_info             = PARROT_CLASS(SELF);
112         proxy_info->id         = type_num;
113         proxy_info->name       = INTERP->vtables[type_num]->whoami;
114         proxy_info->_namespace = INTERP->vtables[type_num]->_namespace;
116         /* Build MRO (skip ourself). */
117         mro_length = VTABLE_elements(INTERP, INTERP->vtables[type_num]->mro);
118         for (i = 1; i < mro_length; ++i) {
119             PMC    *pclass = VTABLE_get_pmc_keyed_int(INTERP, INTERP->vtables[type_num]->mro, i);
120             PMC    *cns    = pclass->vtable->_namespace;
121             STRING *cname  = pclass->vtable->whoami;
122             if (Parrot_str_not_equal(INTERP, cname, CONST_STRING(INTERP, "scalar"))) {
123                 PMC *pproxy = Parrot_oo_get_class(INTERP, cns);
124                 VTABLE_push_pmc(INTERP, proxy_info->all_parents, pproxy);
125             }
126         }
128         /* PMCs just do single inheritance, so we'll assume that if we have a
129          * second entry in our MRO, it goes in the parents list. */
130         if (VTABLE_elements(INTERP, proxy_info->all_parents) >= 2)
131             VTABLE_push_pmc(INTERP, proxy_info->parents,
132                     VTABLE_get_pmc_keyed_int(INTERP, proxy_info->all_parents, 1));
134         if (!PMC_IS_NULL(proxy_info->_namespace) &&
135             PMC_IS_NULL(VTABLE_get_class(INTERP, proxy_info->_namespace))) {
137             /* Link the proxy and the namespace, caching the proxy object for
138              * later retrieval on class lookup. */
139              Parrot_pcc_invoke_method_from_c_args(INTERP, proxy_info->_namespace, CONST_STRING(INTERP, "set_class"), "P->", SELF);
141             /* Extract any methods from the namespace */
142             Parrot_oo_extract_methods_from_namespace(INTERP, SELF,
143                     proxy_info->_namespace);
144         }
146         { /* Create inherited attributes */
147             /* Each attribute is prefixed with his type
148              * and terminated by an space,
149              * the list is '\0' terminated
150              */
151             const char * attr = INTERP->vtables[type_num]->attribute_defs;
152             while (* attr) {
153                 const char * const current = attr + 1;
154                 size_t l;
155                 char attrtype = * attr;
156                 while (* attr != ' ') ++attr;
157                 l= attr - current;
158                 if (attrtype != ':') {
159                     STRING *sattr = Parrot_str_new(INTERP, current, l);
160                     SELF.add_attribute(sattr, NULL);
161                 }
162                 ++attr;
163             }
164         }
165     }
167     VTABLE void init_pmc(PMC *init_data) {
168         const INTVAL type_num = VTABLE_get_integer(INTERP, init_data);
169         SELF.init_int(type_num);
170     }
174 =item C<PMC *instantiate(PMC *init)>
176 Creates an instance of the PMC.
178 =cut
181     VTABLE PMC *instantiate(PMC *init) {
182         Parrot_Class_attributes * const _pmc = PARROT_CLASS(SELF);
184         if (!PMC_IS_NULL(init))
185             return Parrot_pmc_new_init(INTERP, _pmc->id, init);
187         return Parrot_pmc_new(INTERP, _pmc->id);
188     }
192 =item C<INTVAL isa_pmc(PMC *classname)>
194 Returns whether the class is or inherits from C<*classname>.
196 =cut
200     VTABLE INTVAL isa_pmc(PMC *lookup) {
201         Parrot_Class_attributes * const _proxy = PARROT_CLASS(SELF);
202         INTVAL        i, num_classes;
203         STRING       *classname;
204         PMC          *classobj;
206         if (PMC_IS_NULL(lookup))
207             return 0;
209         if (SUPER(lookup))
210             return 1;
212         classobj = Parrot_oo_get_class(INTERP, lookup);
214         if (PMC_IS_NULL(classobj))
215             return 0;
217         classname = VTABLE_get_string(INTERP, classobj);
219         /* Check if the passed name is the same as the stored short name. */
220         if (Parrot_str_equal(INTERP, classname, _proxy->name))
221             return 1;
223         /* Check if the class object is the same as self's class object */
224         if (VTABLE_is_same(INTERP, SELF, classobj))
225             return 1;
227         /* Check if the passed name is the same as the fully qualified name. */
228         if (Parrot_str_equal(INTERP, classname, VTABLE_get_string(INTERP, SELF)))
229             return 1;
231         /* Look in the isa hash. */
232         if (INTERP->vtables[_proxy->id]) {
233             Hash *isa_hash = INTERP->vtables[_proxy->id]->isa_hash;
234             PARROT_ASSERT(isa_hash);
235             if (parrot_hash_exists(INTERP, isa_hash, classname))
236                 return 1;
237         }
239         /* Iterate over all the parents and check if they respond true
240          * for 'isa' on the original comparison. */
241         num_classes = VTABLE_elements(INTERP, _proxy->parents);
243         for (i = 0; i < num_classes; ++i) {
244             PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP,
245                 _proxy->parents, i);
247             if (VTABLE_isa_pmc(INTERP, cur_class, lookup))
248                 return 1;
249         }
251         return 0;
252     }
256 =item C<INTVAL isa(STRING *classname)>
258 Returns whether the class is or inherits from C<*classname>.
260 =cut
264     VTABLE INTVAL isa(STRING *classname) {
265         Parrot_Class_attributes * const _proxy = PARROT_CLASS(SELF);
266         const STRING * const pmc_proxy = CONST_STRING(INTERP, "PMCProxy");
268         if (Parrot_str_equal(INTERP, classname, pmc_proxy))
269             return 1;
271         if (SUPER(classname))
272             return 1;
274         /* Look in the isa hash. */
275         if (INTERP->vtables[_proxy->id]) {
276             Hash *isa_hash = INTERP->vtables[_proxy->id]->isa_hash;
278             if (!isa_hash && Parrot_str_equal(INTERP,
279                      INTERP->vtables[_proxy->id]->whoami, classname)) {
280                 return 1;
281             }
283             if (isa_hash && parrot_hash_exists(INTERP, isa_hash, classname))
284                 return 1;
285         }
287         return 0;
288     }
292 =item C<INTVAL does(STRING *role_name)>
294 Returns whether the class does the role with the given C<*rolename>.
296 =cut
300     VTABLE INTVAL does(STRING *role_name) {
301         Parrot_Class_attributes * const attrs = PARROT_CLASS(SELF);
302         const INTVAL id = attrs->id;
303         const INTVAL type_does = Parrot_pmc_type_does(INTERP, role_name, id);
304         if (type_does)
305             return 1;
306         return VTABLE_isa(INTERP, SELF, role_name);
307     }
311 =item C<INTVAL type()>
313 Returns the integer type of the class.
315 =cut
320     VTABLE INTVAL type() {
321         const Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
322         return _class->id;
323     }
327 =item C<PMC *inspect()>
329 Returns a Hash describing the PMC, with key/value pairs as described in
330 inspect_str.
332 =cut
335     VTABLE PMC *inspect()
336     {
337         /* Create a hash, then use inspect_str to get all of the data to
338          * fill it up with. */
339         STRING * const name_str    = CONST_STRING(INTERP, "name");
340         STRING * const ns_str      = CONST_STRING(INTERP, "namespace");
341         STRING * const meth_str    = CONST_STRING(INTERP, "methods");
342         STRING * const parents_str = CONST_STRING(INTERP, "parents");
344         PMC * const metadata = Parrot_pmc_new(INTERP, enum_class_Hash);
346         VTABLE_set_pmc_keyed_str(INTERP, metadata, name_str,
347             VTABLE_inspect_str(INTERP, SELF, name_str));
348         VTABLE_set_pmc_keyed_str(INTERP, metadata, ns_str,
349             VTABLE_inspect_str(INTERP, SELF, ns_str));
350         VTABLE_set_pmc_keyed_str(INTERP, metadata, meth_str,
351             VTABLE_inspect_str(INTERP, SELF, meth_str));
352         VTABLE_set_pmc_keyed_str(INTERP, metadata, parents_str,
353             VTABLE_inspect_str(INTERP, SELF, parents_str));
355         return metadata;
356     }
360 =item C<STRING *name()>
362 Gets the name of the PMC.
364 =cut
368     METHOD name() {
369         Parrot_Class_attributes * const _pmc     = PARROT_CLASS(SELF);
370         STRING       * const ret_name = _pmc->name;
371         RETURN(STRING *ret_name);
372     }
376 =item C<void get_namespace()>
378 Gets the namespace that this class is attached to.
380 =cut
384     METHOD get_namespace() {
385         Parrot_Class_attributes * const _pmc          = PARROT_CLASS(SELF);
386         PMC          * const ret_namespace = _pmc->_namespace;
387         RETURN(PMC *ret_namespace);
388     }
392 =item C<void new(PMC *args)>
394 Creates an instance of the PMC.
396 =cut
400     METHOD new(PMC *args :optional, int got_args :opt_flag) {
401         PMC * const obj = VTABLE_instantiate(INTERP, SELF, args);
402         UNUSED(got_args);
403         RETURN(PMC *obj);
404     }
408 =item C<void methods()>
410 Return a hash where the keys are method names and the values are methods.
412 =cut
416     METHOD methods() {
417         PMC * const ret_methods = VTABLE_inspect_str(INTERP, SELF, CONST_STRING(INTERP, "methods"));
418         RETURN(PMC *ret_methods);
419     }
423 =item C<void parents()>
425 Return the parents array PMC.
427 =cut
431     METHOD parents() {
432         PMC * const ret_parents = VTABLE_inspect_str(INTERP, SELF, CONST_STRING(INTERP, "parents"));
433         RETURN(PMC *ret_parents);
434     }
438 =item C<void inspect(STRING *what :optional)>
440 Gets all introspection data for the PMC or, if the optional string
441 parameter is supplied, a particular item of introspection data.
443 =cut
447     METHOD inspect(STRING *what :optional, int got_what :opt_flag) {
448         /* Just delegate to the appropriate vtable. */
449         PMC * const found =
450             got_what
451                 ? VTABLE_inspect_str(INTERP, SELF, what)
452                 : VTABLE_inspect(INTERP, SELF);
454         RETURN(PMC *found);
455     }
459 =item C<STRING *get_string()>
461 Return the name of the low-level class (without the HLL namespace).
463 =cut
467     VTABLE STRING *get_string() {
468         Parrot_Class_attributes * const proxy_info = PARROT_CLASS(SELF);
469         return proxy_info->name;
470     }
473 } /* END pmclass */
477 =back
479 =head1 SEE ALSO
481 F<docs/pdds/pdd17_pmc.pod>.
483 =cut
488  * Local variables:
489  *   c-file-style: "parrot"
490  * End:
491  * vim: expandtab shiftwidth=4:
492  */