develooper Front page | perl.cvs.parrot | Postings from January 2009

[svn:parrot] r35542 - in trunk/languages/perl6/src: builtins parser

From:
jonathan
Date:
January 14, 2009 10:55
Subject:
[svn:parrot] r35542 - in trunk/languages/perl6/src: builtins parser
Message ID:
20090114185509.CC7CACB9AE@x12.develooper.com
Author: jonathan
Date: Wed Jan 14 10:55:09 2009
New Revision: 35542

Modified:
   trunk/languages/perl6/src/builtins/guts.pir
   trunk/languages/perl6/src/parser/actions.pm

Log:
[rakudo] Parametric roles now clone methods, meaning that we get them attached to the right parameters.

Modified: trunk/languages/perl6/src/builtins/guts.pir
==============================================================================
--- trunk/languages/perl6/src/builtins/guts.pir	(original)
+++ trunk/languages/perl6/src/builtins/guts.pir	Wed Jan 14 10:55:09 2009
@@ -438,7 +438,9 @@
   role:
     # This is a little fun. We only want to create the Parrot role and suck
     # in the methods once per role definition. We do this and it is attached to
-    # the namespace. Next time, we will find and clone it.
+    # the namespace. Then we attach this "master role" to a new one we create
+    # per invocation, so the methods can be newclosure'd and added into it in
+    # the body.
     .local pmc info, metarole
     ns = get_hll_namespace nsarray
     metarole = get_class ns
@@ -449,12 +451,22 @@
     info['name'] = $P0
     info['namespace'] = nsarray
     metarole = new 'Role', info
-  
   have_role:
-    # XXX At this point, we need to create a clone of the role, but it's a bit
-    # more special than that; we also need to clone and lexically capture the
-    # methods of the role so they will get the parameters captured.
-    .return (metarole)
+    
+    # Copy list of roles done by the metarole.
+    .local pmc result, tmp, it
+    result = new 'Role'
+    setprop result, '$!orig_role', metarole
+    tmp = metarole.'roles'()
+    it = iter tmp
+  roles_loop:
+    unless it goto roles_loop_end
+    tmp = shift it
+    result.'add_role'(tmp)
+    goto roles_loop
+  roles_loop_end:
+
+    .return (result)
 .end
 
 

Modified: trunk/languages/perl6/src/parser/actions.pm
==============================================================================
--- trunk/languages/perl6/src/parser/actions.pm	(original)
+++ trunk/languages/perl6/src/parser/actions.pm	Wed Jan 14 10:55:09 2009
@@ -1544,23 +1544,41 @@
     );
 
     #  ...and at the end of the block's initializer (after any other
-    #  items added by the block), we finalize the composition. This
-    # returns a proto, which we need to keep around and also return at
-    # the end of initialization for anonymous classes. We always need to
-    # return it for roles, since we do a role by invoking the multi-sub
-    # it produces (but those don't want to be immediate).
-    if $<module_name> eq "" && ($?PKGDECL eq 'class' || $?PKGDECL eq 'grammar')
-            || $?PKGDECL eq 'role' {
+    #  items added by the block), we finalize the composition. 
+    if $?PKGDECL eq 'role' {
+        #  For a role, we now need to produce a new one which clones the original,
+        #  but without the methods. Then we need to add back the methods. We emit
+        #  PIR here to do it rather than doing a call, since we need to call
+        #  new_closure from the correct scope.
+        $block[0].push(PAST::Op.new(:inline(
+                '    .local pmc orig_role, meths, meth_iter',
+                '    orig_role = getprop "$!orig_role", %0',
+                '    meths = orig_role."methods"()',
+                '    meth_iter = iter meths',
+                '  it_loop:',
+                '    unless meth_iter goto it_loop_end',
+                '    $S0 = shift meth_iter',
+                '    $P0 = meths[$S0]',
+                '    $P0 = newclosure $P0',
+                '    %0."add_method"($S0, $P0)',
+                '    goto it_loop',
+                '  it_loop_end:',
+                '    .return (%0)'
+            ),
+            $?METACLASS
+        ));
+    }
+    elsif $<module_name> eq "" && ($?PKGDECL eq 'class' || $?PKGDECL eq 'grammar') {
+        #  We need to keep the proto around and return it at the end of
+        #  initialization for anonymous classes.
         $block[0].push(PAST::Op.new(
             :pasttype('bind'),
             PAST::Var.new(:name('proto_store'), :scope('register'), :isdecl(1)),
             PAST::Op.new( :name('!meta_compose'), $?METACLASS)
         ));
         $block.push(PAST::Var.new(:name('proto_store'), :scope('register')));
-        if $?PKGDECL ne 'role' {
-            $block.blocktype('immediate');
-            $block.pirflags('');
-        }
+        $block.blocktype('immediate');
+        $block.pirflags('');
     }
     else {
         $block[0].push( PAST::Op.new( :name('!meta_compose'), $?METACLASS) );



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About