Commits

Anonymous committed f14ce0c

list comprehensions

  • Participants
  • Parent commits 4eb7745

Comments (0)

Files changed (4)

File Grammar/Actions.nqp

     }
 }
 
+method list_comprehension($/) {
+    my $past := PAST::Block.new( :blocktype('immediate'), :node($/) );
+
+    my $list := PAST::Var.new( :scope('register'), :node($/) );
+
+    $past.push( PAST::Op.new( $list,
+                              :inline("    %0 = new ['Pynie';'list']"),
+                              :node($/)));
+
+    # nest scopes
+    my $outermost_scope := $($<list_for>);
+    my $outer_scope := $outermost_scope;
+    for $<list_iter> {
+        my $inner_scope := $($_);
+
+        $outer_scope[-1][-1].push( $inner_scope );
+
+        # this day's inner_scope is the next day's outer_scope        
+        $outer_scope := $inner_scope;
+    }
+    
+    # add expression to innermost scope
+    $outer_scope[-1][-1].push( PAST::Op.new( $list, $($<expression>),
+                                             :pirop('push'),
+                                             :node($/)));
+    
+    $past.push( $outermost_scope );
+    $past.push( $list );  # return value
+
+    make $past;
+}
+
 method list_iter($/, $key) {
     make $( $/{$key} );
 }
 
 method list_for($/) {
-    ## XXX
+    my $past := PAST::Stmts.new( :node($/) );
+
+    # create iterator
+    my $list := $( $<or_test> );
+    my $iter := PAST::Var.new( :scope('register'), :node($/) );
+    $past.push( PAST::Op.new( $iter, $list,
+                              :inline('    %0 = new "Iterator", %1'),
+                              :node($/) ) );
+
+    # make loop body
+    my $tgt := $( $<target> );    # XXX scope, symbol table
+    
+    my $loop := PAST::Stmts.new( :node($/) );
+    my $shifted := PAST::Op.new( $iter,
+                                 :inline('    %r = shift %0'),
+                                 :node($/) );
+    $loop.push( PAST::Op.new( $tgt, $shifted, :pasttype('bind'), :node($/) ) );
+
+    # list_comprehension method can add more stuff into $loop:
+    $past.push( PAST::Op.new( $iter, $loop,
+                              :pasttype('while'),
+                              :node($/) ) );
+
+    make $past;
 }
 
 method list_if($/) {
-    ## XXX
+    my $past := PAST::Stmts.new( :node($/) );
+
+    # prepare so list_comprehension method can put stuff in here:
+    my $inner_stmts := PAST::Stmts.new( :node($/));
+    
+    $past.push( PAST::Op.new( $($<test>), $inner_stmts,
+                              :pasttype('if'),
+                              :node($/) ));
+    make $past;
 }
 
 method primary($/) {

File Grammar/Grammar.pg

 
 rule list_display {
     '['
-        [ <list_literal> {*}       #= list_literal
-        # | <list_comprehension> {*} #= list_comprehension
+        [ <list_comprehension> {*} #= list_comprehension
+        | <list_literal> {*}       #= list_literal
         ]
-     ']'
+    ']'
 }
 
 rule list_literal {
 }
 
 rule list_comprehension {
-     <expression> <list_iter>+
+     <expression> <list_for> <list_iter>*
+     {*}
 }
 
 rule list_iter {
 }
 
 rule list_for {
-    'for' <expression_list> 'in' <testlist>
-    <list_iter>?
+    'for' <target> 'in' <or_test>
+    {*}
 }
 
 rule list_if {
     'if' <test>
-    <list_iter>?
+    {*}
 }
 
 rule test {

File Lib/test/parrot/listcomps.py

+#!./parrot
+
+
+print('test: simple list comp.')
+a = [ i + 3 for i in range(3) ]
+if a == [ 3, 4, 5 ]: print('success: simple list comp.')
+else: print('failure: simple list comp.')
+
+print('test: list comp. with if')
+a = [ i for i in range(6) if i > 3 ]
+if a == [ 4, 5 ]: print('success: list comp. with if')
+else: print('failure: list comp. with if')
+
+print('test: nested list comp.')
+a = [ (i,10+j) for i in range(3) if i > 0 for j in range(4) if j < 3 if j > 0 ]
+if a == [(1, 11), (1, 12), (2, 11), (2, 12)]:
+    print('success: nested list comp.')
+else:
+    print('failure: nested list comp.')
     def test_grammar(self):
         """pynie.pbc Lib/test/parrot/grammar.py"""
 
+    def test_list_comps(self):
+        """pynie.pbc Lib/test/parrot/listcomps.py"""
+    
 
 if __name__ == '__main__':
      unittest.main()