Author: chromatic
Date: Thu May 17 18:59:37 2007
New Revision: 18582

Modified:
   trunk/src/pmc/class.pmc
   trunk/src/pmc/role.pmc
   trunk/t/pmc/class.t

Log:
[OO] Fix does() (RT #42974).

Note for the record that the return values of string_compare() and 
string_equal() suck.  That's why this bug stuck around for so long.  That's my 
apologia anyhow.

Modified: trunk/src/pmc/class.pmc
==============================================================================
--- trunk/src/pmc/class.pmc     (original)
+++ trunk/src/pmc/class.pmc     Thu May 17 18:59:37 2007
@@ -1096,26 +1096,28 @@
 
 */
     PCCMETHOD void does(STRING *role_name) {
-        INTVAL i, role_count;
-        PMC *role_list = ((Parrot_Class *)PMC_data(SELF))->roles;
+        INTVAL i, role_count, isa;
+        PMC *role_list = (PMC_data_typed(SELF, Parrot_Class *))->roles;
 
-        /* not a coding standards violation; the macro expands greatly! */
-        if (!role_list) {
+        if (!role_list)
             PCCRETURN(INTVAL 0);
-        }
 
         role_count = VTABLE_elements(interp, role_list);
 
         for (i = 0; i < role_count; i++) {
-            STRING *r_name;
-            PMC    *role     = VTABLE_get_pmc_keyed_int(interp, role_list, i);
-            (STRING *r_name) = PCCINVOKE(interp, role, "name");
+            INTVAL  role_does;
+            PMC    *role       = VTABLE_get_pmc_keyed_int(interp, role_list, 
i);
+
+            (INTVAL role_does) = PCCINVOKE(interp, role, "does",
+                                           STRING *role_name);
 
-            if (string_compare(interp, role_name, r_name))
+            if (role_does)
                 PCCRETURN(INTVAL 1);
         }
 
-        PCCRETURN(INTVAL 0);
+        (INTVAL isa) = PCCINVOKE(interp, SELF, "isa", STRING *role_name);
+
+        PCCRETURN(INTVAL isa);
     }
 } /* END pmclass */
 

Modified: trunk/src/pmc/role.pmc
==============================================================================
--- trunk/src/pmc/role.pmc      (original)
+++ trunk/src/pmc/role.pmc      Thu May 17 18:59:37 2007
@@ -611,6 +611,11 @@
             PMC* alias_method :optional :named["alias_method"],
             int got_alias_method :opt_flag) {
         Parrot_Role *role_info = PARROT_ROLE(SELF);
+        STRING *s_name, *r_name;
+
+        (STRING *s_name) = PCCINVOKE( interp, SELF, "name" );
+        (STRING *r_name) = PCCINVOKE( interp, role, "name" );
+
         Parrot_ComposeRole(interp, role, exclude_method, got_exclude_method,
                            alias_method, got_alias_method,
                            role_info->methods, role_info->roles);
@@ -638,6 +643,42 @@
         PCCRETURN(PMC *found);
     }
 
+/*
+
+=item C<void does(STRING *role)>
+
+Returns true if this role (or any role composed into this one) performs the
+named role.  This will recurse through all roles as far back as it can.
+
+=cut
+
+*/
+
+    PCCMETHOD void does(STRING *name) {
+        INTVAL  i, count;
+        STRING *r_name;
+        PMC    *roles, *role;
+
+        (STRING *r_name) = PCCINVOKE(interp, SELF, "name");
+
+        if (string_equal(interp, r_name, name) == 0)
+            PCCRETURN(INTVAL 1);
+
+        (PMC *roles)     = PCCINVOKE(interp, SELF, "roles");
+        count            = VTABLE_elements(interp, roles);
+
+        for (i = 0; i < count; i++) {
+            INTVAL does;
+            role          = VTABLE_get_pmc_keyed_int(interp, roles, i);
+            (INTVAL does) = PCCINVOKE(interp, role, "does", STRING *name);
+
+            if (does)
+                PCCRETURN(INTVAL 1);
+        }
+
+        PCCRETURN(INTVAL 0);
+    }
+
 } /* end pmclass Role */
 
 

Modified: trunk/t/pmc/class.t
==============================================================================
--- trunk/t/pmc/class.t (original)
+++ trunk/t/pmc/class.t Thu May 17 18:59:37 2007
@@ -6,7 +6,7 @@
 use warnings;
 use lib qw( . lib ../lib ../../lib );
 use Test::More;
-use Parrot::Test tests => 15;
+use Parrot::Test tests => 16;
 
 =head1 NAME
 
@@ -553,6 +553,52 @@
 Does Class
 OUT
 
+# L<PDD15/Class PMC API/=item does>
+pir_output_is( <<'CODE', <<'OUT', 'more does() - RT #42974' );
+.const int TESTS = 2
+
+.sub 'main' :main
+    load_bytecode 'Test/More.pir'
+    .local pmc exp, test_ns
+    test_ns = get_namespace ['Test::More']
+    exp     = new 'Exporter'
+    exp.'source'(test_ns)
+    exp.'import'('plan ok is diag isa_ok' :named('globals'))
+
+    plan(TESTS)
+
+    .local pmc attrs
+    attrs = new 'Hash'
+
+    .local pmc red, green, blue
+    attrs['name'] = 'Red'
+    red           = new 'Role', attrs
+
+    attrs['name'] = 'Green'
+    green         = new 'Role', attrs
+
+    attrs['name'] = 'Blue'
+    blue          = new 'Role', attrs
+
+    green.'add_role'( blue )
+
+    .local pmc color
+    color = new 'Class'
+
+    $S0 = 'Red'
+    $I0 = color.'does'($S0)
+    is($I0, 0, 'does not Red')
+
+    color.'add_role'( red )
+    $I0 = color.'does'($S0)
+    is($I0, 1, 'does Red')
+.end
+CODE
+1..2
+ok 1 - does not Red
+ok 2 - does Red
+OUT
+
 # Local Variables:
 #   mode: cperl
 #   cperl-indent-level: 4

Reply via email to