1/*
2Copyright (C) 2001-2014, Parrot Foundation.
3
4=head1 NAME
5
6src/pmc/role.pmc - Role PMC
7
8=head1 DESCRIPTION
9
10This class implements the Role PMC, a unit of class composition as outlined in
11F<docs/pdds/pdd15_objects.pod>.
12
13Role is not derived from any other PMC.
14
15=head2 Structure
16
17The Role PMC structure (C<Parrot_Role>) consists of five items:
18
19=over 4
20
21=item C<name>
22
23The name of the role -- a STRING.
24An empty STRING is allocated during initialization.
25
26=item C<namespace>
27
28The namespace the role is associated with, if any.
29A Null PMC is allocated during initialization.
30
31=item C<roles>
32
33The list of roles from which this role is composed, if any.
34An empty ResizablePMCArray is allocated during initialization.
35
36=item C<methods>
37
38The directory of method names and methods this role implements.
39An empty Hash PMC is allocated during initialization.
40
41=item C<attrib_metadata>
42
43The directory of attribute names and attribute metadata this role contains.
44An empty Hash PMC is allocated during initialization.
45
46=cut
47
48*/
49
50#include "pmc/pmc_namespace.h"
51
52/* HEADERIZER HFILE: none */
53/* HEADERIZER BEGIN: static */
54/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
55
56static void init_role_from_hash(PARROT_INTERP,
57    ARGIN(PMC *self),
58    ARGIN(PMC *info))
59        __attribute__nonnull__(1)
60        __attribute__nonnull__(2)
61        __attribute__nonnull__(3);
62
63#define ASSERT_ARGS_init_role_from_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
64       PARROT_ASSERT_ARG(interp) \
65    , PARROT_ASSERT_ARG(self) \
66    , PARROT_ASSERT_ARG(info))
67/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
68/* HEADERIZER END: static */
69
70/*
71
72=item C<static void init_role_from_hash(PARROT_INTERP, PMC *self, PMC *info)>
73
74Takes a hash and initializes the role based on it.
75
76=cut
77
78*/
79
80static void
81init_role_from_hash(PARROT_INTERP, ARGIN(PMC *self), ARGIN(PMC *info))
82{
83    ASSERT_ARGS(init_role_from_hash)
84    Parrot_Role_attributes * const role     = PARROT_ROLE(self);
85    STRING * const ns_string      = CONST_STRING(interp, "NameSpace");
86    STRING * const name_str       = CONST_STRING(interp, "name");
87    STRING * const namespace_str  = CONST_STRING(interp, "namespace");
88    STRING * const set_class_str  = CONST_STRING(interp, "set_class");
89    STRING * const roles_str      = CONST_STRING(interp, "roles");
90    STRING * const attributes_str = CONST_STRING(interp, "attributes");
91    STRING * const methods_str    = CONST_STRING(interp, "methods");
92
93    int have_name, have_ns;
94    PMC *old_ns;
95    int i;
96
97    /* Ensure we actually have some initialization info. */
98    if (PMC_IS_NULL(info))
99        return;
100
101    /* Check if we have a name and/or a namespace. */
102    have_name = VTABLE_exists_keyed_str(interp, info, name_str);
103
104    have_ns = VTABLE_exists_keyed_str(interp, info, namespace_str);
105
106    /* Take a copy of the current namespace the role is attached to. */
107    old_ns = role->_namespace;
108
109    /* Let's roll (no pun intended!) If we have a namespace and a name,
110     * set both. */
111    if (have_name && have_ns) {
112        /* If we weren't passed a NameSpace PMC, assume it's something we have
113         * to look one up with and do so. */
114        PMC *_namespace = VTABLE_get_pmc_keyed_str(interp, info, namespace_str);
115        if (!VTABLE_isa(interp, _namespace, ns_string))
116            _namespace = Parrot_ns_make_namespace_autobase(interp, _namespace);
117
118        /* If we get something null back it's an error; otherwise, store it. */
119        if (!PMC_IS_NULL(_namespace))
120            role->_namespace = _namespace;
121        else
122            Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_GLOBAL_NOT_FOUND,
123                    "Namespace not found");
124
125        /* Set a (string) name. */
126        role->name = VTABLE_get_string_keyed_str(interp, info, name_str);
127    }
128
129    /* Otherwise, we may just have a name. */
130    else if (have_name) {
131        /* Set the name. */
132        role->name = VTABLE_get_string_keyed_str(interp, info, name_str);
133
134        /* Namespace is nested in the current namespace and with the name of
135         * the role. */
136        role->_namespace = Parrot_ns_make_namespace_keyed_str(interp,
137            Parrot_pcc_get_namespace(interp, CURRENT_CONTEXT(interp)), role->name);
138    }
139
140    /* Otherwise, we may just have a namespace. */
141    else if (have_ns) {
142        /* If we weren't passed a NameSpace PMC, assume it's something we have
143         * to look one up with and do so. */
144        PMC *_namespace = VTABLE_get_pmc_keyed_str(interp, info, namespace_str);
145        if (!VTABLE_isa(interp, _namespace, ns_string))
146            _namespace = Parrot_ns_make_namespace_autobase(interp, _namespace);
147
148        /* If we get something null back it's an error; otherwise, store it. */
149        if (PMC_IS_NULL(_namespace))
150            Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_GLOBAL_NOT_FOUND,
151                    "Namespace not found");
152
153        role->_namespace = _namespace;
154        /* Name is that of the most nested part of the namespace. */
155        role->name = VTABLE_get_string(interp, _namespace);
156    }
157
158    /* If we were attached to a namespce and are now attached to a new one,
159     * need to unset ourselves in the old namespace. */
160    if (!PMC_IS_NULL(old_ns) && role->_namespace != old_ns) {
161        Parrot_pcc_invoke_method_from_c_args(interp, old_ns, set_class_str, "P->", PMCNULL);
162    }
163
164    /* Link namespace to this role, if there is one. */
165    if (!PMC_IS_NULL(role->_namespace)) {
166        Parrot_pcc_invoke_method_from_c_args(interp, role->_namespace, set_class_str, "P->", self);
167    }
168
169    /* Initialize roles, if we have any. */
170    if (VTABLE_exists_keyed_str(interp, info, roles_str)) {
171        /* Loop over roles array and compose them. */
172        PMC    * const role_list = VTABLE_get_pmc_keyed_str(interp, info, roles_str);
173        const int role_count     = VTABLE_elements(interp, role_list);
174
175        for (i = 0; i < role_count; ++i) {
176            PMC * const cur_role = VTABLE_get_pmc_keyed_int(interp, role_list, i);
177            VTABLE_add_role(interp, self, cur_role);
178        }
179    }
180
181    /* Initialize attributes, if we have any. */
182    if (VTABLE_exists_keyed_str(interp, info, attributes_str)) {
183        /* Loop over attributes array and add them. */
184        PMC    * const attrib_name_list = VTABLE_get_pmc_keyed_str(interp, info, attributes_str);
185
186        const int attrib_count = VTABLE_elements(interp, attrib_name_list);
187
188        for (i = 0; i < attrib_count; ++i) {
189            STRING * const attrib_name = VTABLE_get_string_keyed_int(interp,
190                attrib_name_list, i);
191            VTABLE_add_attribute(interp, self, attrib_name, PMCNULL);
192        }
193    }
194
195    /* Initialize methods, if we have any. */
196    if (VTABLE_exists_keyed_str(interp, info, methods_str)) {
197        /* Get the methods hash. */
198        PMC    * const methods     = VTABLE_get_pmc_keyed_str(interp, info, methods_str);
199
200        /* Iterate over the list of methods. */
201        PMC    * const iter        = VTABLE_get_iter(interp, methods);
202
203        while (VTABLE_get_bool(interp, iter)) {
204            /* Add the method. */
205            STRING * const method_name = VTABLE_shift_string(interp, iter);
206            PMC    * const method_pmc  =
207                VTABLE_get_pmc_keyed_str(interp, methods, method_name);
208            VTABLE_add_method(interp, self, method_name, method_pmc);
209        }
210    }
211
212    /* Extract any methods from the namespace */
213    Parrot_oo_extract_methods_from_namespace(interp, self, role->_namespace);
214}
215
216/*
217
218=back
219
220=head2 Functions
221
222=over 4
223
224=cut
225
226*/
227
228pmclass Role auto_attrs {
229    ATTR STRING *name;            /* The name of the role. */
230    ATTR PMC    *_namespace;      /* The namespace it's linked to, if any. */
231    ATTR PMC    *roles;           /* Roles from which this role is composed. */
232    ATTR PMC    *methods;         /* Hash of method names to methods. */
233    ATTR PMC    *attrib_metadata; /* Hash of attributes to hashes metadata. */
234
235/*
236
237=item C<void init()>
238
239Initializes a Role PMC.
240
241=item C<void init_pmc(PMC *init_data)>
242
243Creates a Role and initializes it using the settings from the Hash passed in
244C<init_data>.
245
246=cut
247
248*/
249
250    VTABLE void init() {
251        Parrot_Role_attributes * const role =
252                (Parrot_Role_attributes *) PMC_data(SELF);
253
254        /* Set flags for custom GC mark. */
255        PObj_custom_mark_SET(SELF);
256
257        /* Set up the object. */
258        role->name            = CONST_STRING(INTERP, "");
259        role->_namespace      = PMCNULL;
260        role->roles           = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
261        role->methods         = Parrot_pmc_new(INTERP, enum_class_Hash);
262        role->attrib_metadata = Parrot_pmc_new(INTERP, enum_class_Hash);
263    }
264
265    VTABLE void init_pmc(PMC *init_data) {
266        /* Create the role. */
267        SELF.init();
268
269        /* Initialize the role with the supplied data. */
270        init_role_from_hash(INTERP, SELF, init_data);
271    }
272
273/*
274
275=item C<void mark()>
276
277Mark referenced strings and PMCs in the structure as live.
278
279=cut
280
281*/
282
283    VTABLE void mark() :no_wb {
284        Parrot_Role_attributes * const role = PARROT_ROLE(SELF);
285
286        Parrot_gc_mark_STRING_alive(INTERP, role->name);
287        Parrot_gc_mark_PMC_alive(INTERP, role->_namespace);
288        Parrot_gc_mark_PMC_alive(INTERP, role->roles);
289        Parrot_gc_mark_PMC_alive(INTERP, role->methods);
290        Parrot_gc_mark_PMC_alive(INTERP, role->attrib_metadata);
291    }
292
293/*
294
295=item C<void add_attribute(STRING *name, PMC *type)>
296
297Adds the given attribute with an optional type.
298Enters the attribute in the C<attributes> array.
299
300=cut
301
302*/
303
304    VTABLE void add_attribute(STRING *name, PMC *type) {
305        Parrot_Role_attributes * const role  = PARROT_ROLE(SELF);
306        PMC           * const new_attribute  = Parrot_pmc_new(INTERP, enum_class_Hash);
307
308        /* Set name and type. */
309        VTABLE_set_string_keyed_str(INTERP, new_attribute, CONST_STRING(INTERP, "name"), name);
310
311        if (!PMC_IS_NULL(type))
312            VTABLE_set_pmc_keyed_str(INTERP, new_attribute, CONST_STRING(INTERP, "type"), type);
313
314        /* Enter the attribute in the attributes array. */
315        VTABLE_set_pmc_keyed_str(INTERP, role->attrib_metadata,
316            name, new_attribute);
317    }
318
319/*
320
321=item C<void add_method(STRING *name, PMC *sub)>
322
323Adds the given sub PMC as a method with the given name.
324
325=cut
326
327*/
328
329    VTABLE void add_method(STRING *name, PMC *sub) {
330        Parrot_Role_attributes * const role = PARROT_ROLE(SELF);
331
332        /* If we have already added a method with this name... */
333        if (VTABLE_exists_keyed_str(INTERP, role->methods, name)) {
334            /* XXX Need to handle multi methods here. */
335            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_UNIMPLEMENTED,
336                "Currently, adding multiple methods of the same name"
337                " is not supported.");
338        }
339        else {
340            /* Enter it into the table. */
341            VTABLE_set_pmc_keyed_str(INTERP, role->methods, name, sub);
342        }
343    }
344
345/*
346
347=item C<void remove_method(STRING *name, PMC *sub)>
348
349Removes the method with the given name.
350
351=cut
352
353*/
354    VTABLE void remove_method(STRING *name) {
355        Parrot_Role_attributes * const role = PARROT_ROLE(SELF);
356        if (VTABLE_exists_keyed_str(INTERP, role->methods, name))
357            VTABLE_delete_keyed_str(INTERP, role->methods, name);
358        else
359            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
360                "No method named '%S' to remove in role '%S'.",
361                name, VTABLE_get_string(INTERP, SELF));
362    }
363
364/*
365
366=item C<void add_role(PMC *role)>
367
368Composes the supplied Role PMC into this role, provided there are no
369conflicts.
370
371=cut
372
373*/
374
375    VTABLE void add_role(PMC *role) {
376        Parrot_Role_attributes * const this_role = PARROT_ROLE(SELF);
377
378        /* Do the composition. */
379        Parrot_ComposeRole(INTERP, role, PMCNULL, 0, PMCNULL, 0,
380               this_role->methods, this_role->roles);
381    }
382
383
384/*
385
386=item C<PMC *inspect_str(STRING *what)>
387
388Provides introspection of a specific piece of information about the role. The
389available information is:
390
391=over 4
392
393=item name - String PMC containing the name of the role
394
395=item namespce - NameSpace PMC of the namespace attached to the role
396
397=item attributes - Hash keyed on attribute name, value is hash describing it
398
399=item methods - Hash keyed on method name, value is an invokable PMC. Includes
400methods composed in from roles.
401
402=item roles - Array of Role PMCs. Includes roles done by the roles that were
403composed into this role.
404
405=back
406
407=cut
408
409*/
410
411    VTABLE PMC *inspect_str(STRING *what) :no_wb {
412        Parrot_Role_attributes * const role  = PARROT_ROLE(SELF);
413
414        /* What should we return? */
415        PMC         *found;
416
417        if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "name"))) {
418            found = Parrot_pmc_new(INTERP, enum_class_String);
419            VTABLE_set_string_native(INTERP, found, role->name);
420        }
421        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "namespace"))) {
422            /* Don't clone the namespace, as it's not part of our state. */
423            return role->_namespace;
424        }
425        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "attributes"))) {
426            found = role->attrib_metadata;
427        }
428        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "methods"))) {
429            found = role->methods;
430        }
431        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "roles"))) {
432            found = role->roles;
433        }
434        else {
435            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
436                "Unknown introspection value '%S'", what);
437        }
438
439        /* Clone and return. */
440        if (PMC_IS_NULL(found)) { return PMCNULL; }
441        if (found->vtable->base_type == enum_class_Hash) {
442            /* for Hash return values, create and return a shallow
443             * clone because the VTABLE_clone does a deep clone */
444            PMC * const hash = Parrot_pmc_new(INTERP, enum_class_Hash);
445            PMC * const iter = VTABLE_get_iter(INTERP, found);
446            while (VTABLE_get_bool(INTERP, iter)) {
447                STRING * const key   = VTABLE_shift_string(INTERP, iter);
448                PMC *    const value = VTABLE_get_pmc_keyed_str(INTERP, found, key);
449                VTABLE_set_pmc_keyed_str(INTERP, hash, key, value);
450            }
451            return hash;
452        }
453        return VTABLE_clone(INTERP, found);
454    }
455
456
457/*
458
459=item C<PMC *inspect()>
460
461Returns a Hash describing the role, with key/value pairs as described in
462inspect_str.
463
464=cut
465
466*/
467
468    VTABLE PMC *inspect() :no_wb {
469        /* Create a hash, then use inspect_str to get all of the data to
470         * fill it up with. */
471        PMC * const metadata = Parrot_pmc_new(INTERP, enum_class_Hash);
472
473        STRING * const name       = CONST_STRING(INTERP, "name");
474        STRING * const _namespace = CONST_STRING(INTERP, "namespace");
475        STRING * const attributes = CONST_STRING(INTERP, "attributes");
476        STRING * const methods    = CONST_STRING(INTERP, "methods");
477        STRING * const roles      = CONST_STRING(INTERP, "roles");
478
479        VTABLE_set_pmc_keyed_str(INTERP, metadata, name,
480            VTABLE_inspect_str(INTERP, SELF, name));
481
482        VTABLE_set_pmc_keyed_str(INTERP, metadata, _namespace,
483            VTABLE_inspect_str(INTERP, SELF, _namespace));
484
485        VTABLE_set_pmc_keyed_str(INTERP, metadata, attributes,
486            VTABLE_inspect_str(INTERP, SELF, attributes));
487
488        VTABLE_set_pmc_keyed_str(INTERP, metadata, methods,
489            VTABLE_inspect_str(INTERP, SELF, methods));
490
491        VTABLE_set_pmc_keyed_str(INTERP, metadata, roles,
492            VTABLE_inspect_str(INTERP, SELF, roles));
493        return metadata;
494    }
495
496/*
497
498=item C<STRING *get_string()>
499
500Return the name of the role (without the HLL namespace).
501
502=cut
503
504*/
505
506    VTABLE STRING *get_string() :no_wb {
507        const Parrot_Role_attributes * const role = PARROT_ROLE(SELF);
508        PMC               * const _namespace = role->_namespace;
509
510        if (!PMC_IS_NULL(_namespace)) {
511            /* Call the 'get_name' method on the role's associated namespace
512             * to retrieve a fully qualified list of names, then join the list
513             * with a semicolon.
514             */
515            PMC * const names = Parrot_ns_get_name(INTERP, _namespace);
516
517            if (!PMC_IS_NULL(names)) {
518                /* remove the HLL namespace name */
519                VTABLE_shift_string(INTERP, names);
520                return Parrot_str_join(INTERP, CONST_STRING(INTERP, ";"), names);
521            }
522        }
523
524        /* Otherwise, copy the stored string name of the class. */
525        return role->name;
526    }
527
528/*
529
530=item C<INTVAL does(STRING *rolename)>
531
532Returns whether the class does the role with the given C<*rolename>.
533
534=cut
535
536*/
537    VTABLE INTVAL does(STRING *role_name) :no_wb {
538        const Parrot_Role_attributes * const role  = PARROT_ROLE(SELF);
539        INTVAL      i, count;
540
541        if (STRING_equal(INTERP, role->name, role_name))
542            return 1;
543
544        count = VTABLE_elements(INTERP, role->roles);
545        for (i = 0; i < count; ++i) {
546            PMC * const cur_role = VTABLE_get_pmc_keyed_int(INTERP, role->roles, i);
547            if (VTABLE_does(INTERP, cur_role, role_name))
548                return 1;
549        }
550
551        return 0;
552    }
553
554/*
555
556=item C<INTVAL does_pmc(PMC *role)>
557
558Returns whether the class does the given C<*role>.
559
560=cut
561
562*/
563    VTABLE INTVAL does_pmc(PMC *role) :no_wb {
564        const Parrot_Role_attributes * const this_role  = PARROT_ROLE(SELF);
565        INTVAL      i, count;
566
567        if (role == SELF)
568            return 1;
569
570        count = VTABLE_elements(INTERP, this_role->roles);
571        for (i = 0; i < count; ++i) {
572            PMC * const cur_role = VTABLE_get_pmc_keyed_int(INTERP, this_role->roles, i);
573            if (VTABLE_does_pmc(INTERP, cur_role, role))
574                return 1;
575        }
576
577        return 0;
578    }
579
580    /*
581     * Below here are methods that eventually will go in a role
582     * that is composed into here to optionally give a nice interface from
583     * PIR (ParrotRole isa Role does RoleMethods or something like this).
584     */
585
586
587/*
588
589=back
590
591=head2 Methods
592
593=over 4
594
595=item C<METHOD
596    name(STRING *name :optional, int got_name :opt_flag)>
597
598Sets the name of the role, and updates the namespace accordingly.
599
600=cut
601
602*/
603
604    METHOD name(STRING *name :optional, int got_name :opt_flag) {
605        Parrot_Role_attributes *role     = PARROT_ROLE(SELF);
606        STRING                 *ret_name = NULL;
607
608        if (got_name) {
609            /* We'll build a hash just containing the name, then give this to
610             * init_role_from_hash - saves some code duplication. */
611            PMC * const naming_hash = Parrot_pmc_new(INTERP, enum_class_Hash);
612            VTABLE_set_string_keyed_str(INTERP, naming_hash, CONST_STRING(INTERP, "name"), name);
613            init_role_from_hash(INTERP, SELF, naming_hash);
614        }
615
616        ret_name = role->name;
617        RETURN(STRING *ret_name);
618    }
619
620
621/*
622
623=item C<METHOD
624    get_namespace()>
625
626Gets the namespace associated with this role, if any.
627
628=cut
629
630*/
631
632    METHOD get_namespace() :no_wb {
633        PMC * const ret_namespace = PARROT_ROLE(SELF)->_namespace;
634        RETURN(PMC *ret_namespace);
635    }
636
637
638/*
639
640=item C<METHOD
641    attributes()>
642
643Return a hash where the keys are attribute names and the values are hashes
644providing a set of key/value pairs describing the attribute.
645
646=cut
647
648*/
649    METHOD attributes() :no_wb {
650        PMC * const ret_attrib_metadata = VTABLE_inspect_str(INTERP, SELF, CONST_STRING(INTERP, "attributes"));
651        RETURN(PMC *ret_attrib_metadata);
652    }
653
654
655/*
656
657=item C<METHOD
658    add_attribute(STRING *attribute_name,
659            PMC *attribute_type :optional, int got_type :opt_flag)>
660
661Add an attribute to the role. Requires a name and, optionally, a type.
662
663=cut
664
665*/
666    METHOD add_attribute(STRING *attribute_name,
667            PMC *attribute_type :optional, int got_type :opt_flag) {
668        VTABLE_add_attribute(INTERP, SELF, attribute_name,
669            got_type ? attribute_type : PMCNULL);
670    }
671
672
673/*
674
675=item C<METHOD methods()>
676
677Return a hash where the keys are method names and the values are methods.
678
679=cut
680
681*/
682    METHOD methods() :no_wb {
683        PMC * const ret_methods = VTABLE_inspect_str(INTERP, SELF, CONST_STRING(INTERP, "methods"));
684        RETURN(PMC *ret_methods);
685    }
686
687
688/*
689
690=item C<METHOD add_method(STRING *name, PMC *sub)>
691
692Adds the given sub PMC as a method with the given name.
693
694=cut
695
696*/
697    METHOD add_method(STRING *name, PMC *sub) {
698        VTABLE_add_method(INTERP, SELF, name, sub);
699    }
700
701/*
702
703=item C<void remove_method(STRING *name)>
704
705Removes the method with the given name.
706
707=cut
708
709*/
710    METHOD remove_method(STRING *name) {
711        VTABLE_remove_method(INTERP, SELF, name);
712    }
713
714
715/*
716
717=item C<METHOD roles()>
718
719Return the roles array PMC.
720
721=cut
722
723*/
724    METHOD roles() :no_wb {
725        PMC * const ret_roles = VTABLE_inspect_str(INTERP, SELF, CONST_STRING(INTERP, "roles"));
726        RETURN(PMC *ret_roles);
727    }
728
729
730/*
731
732=item C<METHOD
733    add_role(PMC *role,
734            PMC *exclude_method     :optional :named("exclude_method"),
735            int  got_exclude_method :opt_flag,
736            PMC *alias_method       :optional :named("alias_method"),
737            int  got_alias_method   :opt_flag)>
738
739Compose the given role into this one, using the given exclusions and aliases.
740
741=cut
742
743*/
744    METHOD add_role(PMC *role,
745            PMC *exclude_method     :optional :named("exclude_method"),
746            int  got_exclude_method :opt_flag,
747            PMC *alias_method       :optional :named("alias_method"),
748            int  got_alias_method   :opt_flag) {
749        Parrot_Role_attributes *role_info = PARROT_ROLE(SELF);
750        STRING *s_name   = NULL;
751        STRING *r_name   = NULL;
752
753        (STRING *s_name) = PCCINVOKE(INTERP, SELF, "name");
754        (STRING *r_name) = PCCINVOKE(INTERP, role, "name");
755        UNUSED(s_name);
756        UNUSED(r_name);
757
758        Parrot_ComposeRole(INTERP, role, exclude_method, got_exclude_method,
759                           alias_method, got_alias_method,
760                           role_info->methods, role_info->roles);
761    }
762
763/*
764
765=item C<void inspect(STRING *what :optional)>
766
767Gets all introspection data for the role or, if the optional string
768parameter is supplied, a particular item of introspection data.
769
770=cut
771
772*/
773    METHOD inspect(STRING *what :optional, int got_what :opt_flag) :no_wb {
774        PMC *found;
775
776        /* Just delegate to the appropriate vtable. */
777        if (got_what)
778            found = VTABLE_inspect_str(INTERP, SELF, what);
779        else
780            found = VTABLE_inspect(INTERP, SELF);
781
782        RETURN(PMC *found);
783    }
784
785/*
786
787=item C<void does(STRING *role)>
788
789Returns true if this role (or any role composed into this one) performs the
790named role.  This will recurse through all roles as far back as it can.
791
792=cut
793
794*/
795
796    METHOD does(STRING *name) :no_wb {
797        const INTVAL does = VTABLE_does(INTERP, SELF, name);
798        RETURN(INTVAL does);
799    }
800
801} /* end pmclass Role */
802
803
804/*
805
806=back
807
808=head1 STABILITY
809
810Unstable. This PMC is under active development; major portions of the
811interface have not yet been completed.
812
813=head1 SEE ALSO
814
815F<docs/pdds/pdd15_objects.pod>.
816
817=cut
818
819*/
820
821/*
822 * Local variables:
823 *   c-file-style: "parrot"
824 * End:
825 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
826 */
827