Commits

Anonymous committed 5fa9ed5

Closure support for inner defs when returned by function.
When returning from a defined function, any subroutines returned need a
'newclosure' generated. This is so that inner defs will generate closures
properly. This may not be the best way to solve this problem, and it also
does not handle assignment statements.

  • Participants
  • Parent commits b2e5d78

Comments (0)

Files changed (5)

+2009-08-02  Bradley M. Kuhn  <bkuhn@ebb.org>
+
+	* src/builtins/helper.pir: Created file.
+	(is_type_sub): Wrote sub.
+
+	* setup.py (BUILTINS_PIR): Added helper.pir to list.
+
+	* Grammar.pg (return_expression_list): Added rule.
+
+	* Actions.nqp (return_expression_list): Wrote method.
+	(do_newclosure_if_sub): Wrote sub.
+	(return_stmt): use return_expression_list instead of
+	expression_list.
+
 2009-08-01  Bradley M. Kuhn  <bkuhn@ebb.org>
 
 	* Actions.nqp (lambda_form): generate newclosure 'pirop' for

File Grammar/Actions.nqp

 
 method return_stmt($/) {
     my $past := PAST::Op.new( :pasttype('return'), :node($/) );
-    if $<expression_list> {
-        my $retvals := $( $<expression_list>[0] );
+    if $<return_expression_list> {
+        my $retvals := $( $<return_expression_list>[0] );
         $past.push($retvals);
     }
     make $past;
     make $past;
 }
 
+sub do_newclosure_if_sub($expression) {
+  my $block := PAST::Block.new(:blocktype("immediate"));
+  # Save the expression in 'exprval'.
+  $block.push(PAST::Op.new(:pasttype('bind'),
+                           PAST::Var.new(:name('exprval'),
+                                         :scope('register'), :isdecl(1)),
+                           $expression.ast));
+  # We now have the if statement
+  $block.push(PAST::Op.new(
+                           # this inline Op is the conditional statement
+                           # of the if.  It tests to see if the type of
+                           # the 'exprval' variable is "Sub", using the
+                           # is_type_sub
+                           PAST::Op.new(:pasttype('call'), :name("is_type_sub"),
+                                        PAST::Var.new( :name('exprval'),
+                                                       :scope('register'))),
+                           # If it turns out to be a subroutine, we want
+                           # to force a newclosure on it.
+                           PAST::Op.new(:inline('    newclosure %r, %0'),
+                                        PAST::Var.new( :name('exprval'),
+                                                       :scope('register'))),
+                           # Otherwise, return the value of expression
+                           PAST::Op.new(:inline('   %r = %0'),
+                                        PAST::Var.new( :name('exprval'),
+                                          :scope('register'))),
+                           :pasttype('if')));
+  return $block;
+}
+
+# return_expression_list makes sure that when return any functions, they
+# contain a closure (using newclosuere, see do_newclosure_if_sub above)
+# for any functions returned.  We do this on the return since we are about
+# to leave scope.
+
+method return_expression_list($/) {
+    my $past;
+    if (+$<expression> == 1) {
+      $past := do_newclosure_if_sub($<expression>[0]);
+    }
+    else {
+        $past := PAST::Op.new( :name('listmaker'), :node($/) );
+        for $<expression> {
+            $past.push( do_newclosure_if_sub($($_)) );
+        }
+    }
+    make $past;
+}
+
 
 method identifier($/) {
     make PAST::Var.new( :name( ~$/ ),

File Grammar/Grammar.pg

 }
 
 rule return_stmt {
-    'return' <expression_list>?
+    'return' <return_expression_list>?
     {*}
 }
 
      <expression> [',' <expression> ]* ','? {*}
 }
 
+rule return_expression_list {
+     <expression> [',' <expression> ]* ','? {*}
+}
+
 rule tuple_or_scalar {
     | <tuple_constructor> {*} #= tuple_constructor
     | <expression> {*}        #= expression
 
 BUILTINS_PIR = [
   'src/builtins/funcs.pir', 
+  'src/builtins/helper.pir', 
   'src/builtins/io.pir', 
   'src/builtins/lists.pir', 
   'src/builtins/oper.pir',

File src/builtins/helper.pir

+# Copyright (C) 2009, Bradley M. Kuhn
+# License: Artistic-2.0-or-later
+
+=head1 NAME
+
+src/builtins/helper.pir - helper functions
+
+=head1 Functions
+
+=over 4
+
+=cut
+
+=item is_type_sub(val)
+
+Returns true iff. the typeof the argument, val, is "Sub".
+
+=cut
+
+.sub 'is_type_sub'
+    .param pmc val
+    .local pmc valtype
+    typeof valtype, val
+    eq valtype, "Sub", return_true
+    .return(0)
+return_true:
+    .return(1)
+.end