Author: pmichaud
Date: Fri Jan  2 12:14:15 2009
New Revision: 34835

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

Log:
[rakudo]:  First cut at attributes in classes.


Modified: branches/rvar/languages/perl6/perl6.pir
==============================================================================
--- branches/rvar/languages/perl6/perl6.pir     (original)
+++ branches/rvar/languages/perl6/perl6.pir     Fri Jan  2 12:14:15 2009
@@ -101,6 +101,11 @@
     $P0 = new 'List'
     set_hll_global ['Perl6';'Grammar';'Actions'], '@?PKGDECL', $P0
 
+    ## create a (shared) metaclass node
+    $P0 = get_hll_global ['PAST'], 'Var'
+    $P0 = $P0.'new'( 'name'=>'metaclass', 'scope'=>'register' )
+    set_hll_global ['Perl6';'Grammar';'Actions'], '$?METACLASS', $P0
+
     ##  create a list of END blocks to be run
     $P0 = new 'List'
     set_hll_global ['Perl6'], '@?END_BLOCKS', $P0

Modified: branches/rvar/languages/perl6/src/builtins/guts.pir
==============================================================================
--- branches/rvar/languages/perl6/src/builtins/guts.pir (original)
+++ branches/rvar/languages/perl6/src/builtins/guts.pir Fri Jan  2 12:14:15 2009
@@ -428,6 +428,46 @@
 .end
 
 
+=item !meta_attribute(metaclass, name, itype [, 'type'=>type] )
+
+Add attribute C<name> to C<metaclass> with the given C<itype>
+and C<type>.
+
+=cut
+
+.sub '!meta_attribute'
+    .param pmc metaclass
+    .param string name
+    .param string itype
+    .param pmc attr            :slurpy :named
+
+    # If the name doesn't have a twigil, we give it one.
+    $S0 = substr name, 1, 1
+    if $S0 == '!' goto have_name
+    substr name, 1, 0, '!'
+  have_name:
+
+    # Add the attribute to the metaclass.
+    metaclass.'add_attribute'(name)
+
+    # Set the itype for the attribute.
+    .local pmc attrhash, it
+    $P0 = metaclass.'attributes'()
+    attrhash = $P0[name]
+    attrhash['itype'] = itype
+
+    # and set any other attributes that came in via the slurpy hash
+    it = iter attr
+  attr_loop:
+    unless it goto attr_done
+    $S0 = shift it
+    $P0 = attr[$S0]
+    attrhash[$S0] = $P0
+    goto attr_loop
+  attr_done:
+.end
+
+
 =item !keyword_class(name)
 
 Internal helper method to create a class.

Modified: branches/rvar/languages/perl6/src/parser/actions.pm
==============================================================================
--- branches/rvar/languages/perl6/src/parser/actions.pm (original)
+++ branches/rvar/languages/perl6/src/parser/actions.pm Fri Jan  2 12:14:15 2009
@@ -1374,7 +1374,7 @@
 
     #  Add any traits coming from the package declarator.
     #  Traits in the body have already been added to the block.
-    my $metaclass := PAST::Var.new( :name('metaclass'), :scope('register') );
+    our $?METACLASS;
     if $<trait> {
         for @($<trait>) {
             #  Trait nodes come in as PAST::Op( :name('list') ).
@@ -1384,7 +1384,7 @@
             if $trait[1] eq 'also' { $block<isalso> := 1; }
             else {
                 $trait.name('!meta_trait');
-                $trait.unshift($metaclass);
+                $trait.unshift($?METACLASS);
                 $init.push($trait);
             }
         }
@@ -1403,15 +1403,18 @@
 
     #  ...and at the end of the block's initializer (after any other
     #  items added by the block), we finalize the composition
-    $block[0].push( PAST::Op.new( :name('!meta_compose'), $metaclass) );
+    $block[0].push( PAST::Op.new( :name('!meta_compose'), $?METACLASS) );
 
     make $block;
 }
 
 
 method scope_declarator($/) {
-    my $sym  := ~$<sym>;
-    my $past := $( $<scoped> );
+    my $sym   := ~$<sym>;
+    my $past  := $( $<scoped> );
+    my $scope := 'lexical';
+    if    $sym eq 'our' { $scope := 'package'; }
+    elsif $sym eq 'has' { $scope := 'attribute'; }
 
     if $past.isa(PAST::Var) {
         $past := PAST::Op.new( $past );
@@ -1421,12 +1424,10 @@
     for @($past) {
         if $_.isa(PAST::Var) {
             my $var := $_;
-            my $scope := 'lexical';
-            if $sym eq 'our' {
-                $scope := 'package';
-                $var.lvalue(1);
-            }
-    
+
+            my $type;
+            if +@($var<type>) { $type := $var<type>[0]; }  # FIXME
+
             # This is a variable declaration, so we set the scope in
             # the block.  The symbol entry also tells us the
             # implementation type of the variable (itype), any
@@ -1436,22 +1437,37 @@
             @?BLOCK[0].symbol( $var.name(), :scope($scope) );
             $var.scope($scope);
             $var.isdecl(1);
-           
+            if $scope eq 'package' { $var.lvalue(1); }
             my $init_value := $var.viviself(); 
-            my $viviself   := PAST::Op.new( :pirop('new PsP'), $var<itype> );
-            if $init_value { $viviself.push( $init_value ); }
-            $var.viviself( $viviself );
-
-            if +@($var<type>) {
-                $var := PAST::Op.new( :pirop('setprop'), 
-                                      $var, 'type', $var<type>[0] );
+
+            if $scope eq 'attribute' {
+                our $?METACLASS;
+                my $has := PAST::Op.new( :name('!meta_attribute'), 
+                               $?METACLASS, $var.name(), $var<itype> );
+                if $type { $type.named('type'); $has.push($type); }
+                if $init_value { 
+                    $init_value.named('init_value');
+                    $has.push($init_value);
+                }
+                @?BLOCK[0].push( $has );
+            }
+            else { 
+                # $scope eq 'package' | 'lexical'
+                my $viviself := PAST::Op.new( :pirop('new PsP'), $var<itype> );
+                if $init_value { $viviself.push( $init_value ); }
+                $var.viviself( $viviself );
+                if $type { 
+                    $var := PAST::Op.new( :pirop('setprop'), 
+                                          $var, 'type', $type );
+                }
             }
             $past[$i] := $var;
         }
         $i++;
     }
-    if +@($past) == 1 { $past := $past[0]; }
-    else { $past.name('infix:,'); $past.pasttype('call'); }
+    if    $scope eq 'attribute' { $past := PAST::Stmts.new(); }
+    elsif +@($past) == 1        { $past := $past[0]; }
+    else  { $past.name('infix:,'); $past.pasttype('call'); }
     make $past;
 }
 
@@ -1565,6 +1581,14 @@
             $past.scope('package');
             $past.viviself( container_itype($sigil) );
         }
+
+        ##  if ! twigil, it's a private attribute
+        if $twigil eq '!' {
+            $varname := $sigil ~ $twigil ~ $name;
+            $past.name($varname);
+            $past.scope('attribute');
+            $past.unshift( PAST::Var.new( :name('self'), :scope('lexical') ) );
+        }
     }
     elsif $key eq 'special_variable' {
         $past := $( $<special_variable> );

Reply via email to