Author: leo
Date: Tue Jan 17 04:17:18 2006
New Revision: 11221

Modified:
   trunk/compilers/imcc/pbc.c
   trunk/include/parrot/sub.h
   trunk/src/classes/closure.pmc
   trunk/src/classes/sub.pmc
   trunk/t/op/lexicals.t
Log:
lexicals - experimental support for autoclosing

* sub f ($x) { sub g () { print $x };  } f(10);  g(); 
* this prints 10 now
* tests


Modified: trunk/compilers/imcc/pbc.c
==============================================================================
--- trunk/compilers/imcc/pbc.c  (original)
+++ trunk/compilers/imcc/pbc.c  Tue Jan 17 04:17:18 2006
@@ -594,6 +594,7 @@ find_outer(Interp *interpreter, IMC_Unit
     for (s = globals.cs->first; s; s = s->next) {
         sub = s->unit->instructions->r[0];
         if (!strcmp(sub->name, unit->outer->name)) {
+            PObj_get_FLAGS(s->unit->sub_pmc) |= SUB_FLAG_IS_OUTER;
             return s->unit->sub_pmc;
         }
     }

Modified: trunk/include/parrot/sub.h
==============================================================================
--- trunk/include/parrot/sub.h  (original)
+++ trunk/include/parrot/sub.h  Tue Jan 17 04:17:18 2006
@@ -24,6 +24,8 @@ typedef enum {
     SUB_FLAG_CORO_FF      = PObj_private0_FLAG,
     SUB_FLAG_C_HANDLER    = PObj_private0_FLAG,
 
+    SUB_FLAG_IS_OUTER     = PObj_private1_FLAG,
+
     SUB_FLAG_TAILCALL     = PObj_private2_FLAG,
     SUB_FLAG_GENERATOR    = PObj_private3_FLAG,
 

Modified: trunk/src/classes/closure.pmc
==============================================================================
--- trunk/src/classes/closure.pmc       (original)
+++ trunk/src/classes/closure.pmc       Tue Jan 17 04:17:18 2006
@@ -77,27 +77,51 @@ Invokes the closure.
 
     void* invoke (void* next) {
         struct Parrot_sub * sub = PMC_sub(SELF);
+        PMC *cont, *outer_sub;
+
         next = SUPER(next);
+        outer_sub = sub->outer_sub;
         if (sub->outer_ctx) {
             /* during newclosure, outer's ctx was stored in
              * sub->outer_ctx
              */
             sub->ctx->outer_ctx = sub->outer_ctx;
         }
+        else if ((PObj_get_FLAGS(outer_sub) & SUB_FLAG_IS_OUTER &&
+            PMC_sub(outer_sub)->ctx)) {
+            /* the sub was invoked earlier - it still has the context
+             * due to the SUB_FLAG_IS_OUTER flag
+             */
+            sub->outer_ctx = sub->ctx->outer_ctx = PMC_sub(outer_sub)->ctx;
+        }
         else {
             /* closure is just invoked - located :outer's ctx */
             parrot_context_t *caller = sub->ctx->caller_ctx;
             while (caller) {
-                if (caller->current_sub == sub->outer_sub) {
-                    sub->ctx->outer_ctx = caller;
-                    break;
+                if (caller->current_sub == outer_sub) {
+                    cont = caller->current_cont;
+                    cont->vtable = 
Parrot_base_vtables[enum_class_Continuation];
+                    sub->outer_ctx = sub->ctx->outer_ctx = caller;
+                    caller->ref_count++;
+                    return next;
                 }
                 caller = caller->caller_ctx;
             }
-            if (!caller)
-                real_exception(interpreter, NULL, INVALID_OPERATION,
-                        ":outer '%Ss' not found", 
-                        VTABLE_get_string(INTERP, sub->outer_sub));
+            if (!caller) {
+                /* outer has never been invoked, we fake a subroutine call
+                 * which builds the LexPad and return immediately
+                 * this will usually just lead to a Null PMC access
+                 * exception
+                 */
+                INTERP->current_cont = NEED_CONTINUATION;
+                (void)VTABLE_invoke(INTERP, sub->outer_sub, next);
+                caller = CONTEXT(INTERP->ctx);
+                cont = caller->current_cont;
+                cont->vtable = Parrot_base_vtables[enum_class_Continuation];
+                sub->outer_ctx = sub->ctx->outer_ctx = caller;
+                caller->ref_count++;
+                (void)VTABLE_invoke(INTERP, cont, next);
+            }
         }
         return next;
     }

Modified: trunk/src/classes/sub.pmc
==============================================================================
--- trunk/src/classes/sub.pmc   (original)
+++ trunk/src/classes/sub.pmc   Tue Jan 17 04:17:18 2006
@@ -83,7 +83,8 @@ Initializes the subroutine.
     /*
      * Sub PMC's flags usage:
      * - private0 ... Coroutine flip/flop - C exception handler
-     * - private1 ... unused
+     * - private1 ... _IS_OUTER - have to preserve context
+     *                as some other sub has :outer(this) 
      * - private2 ... tailcall invoked this Sub
      * - private3 ... pythonic coroutine generator flag
      * - private4 ... :main (nee @MAIN)
@@ -307,6 +308,11 @@ Invokes the subroutine.
          * set context of the sub
          */
         sub->ctx = context;
+        if (PObj_get_FLAGS(SELF) & SUB_FLAG_IS_OUTER) {
+            /* don't destroy context */
+            ccont->vtable = Parrot_base_vtables[enum_class_Continuation];
+            context->ref_count++;
+        }
 
         if (!PMC_IS_NULL(INTERP->current_object)) {
             context->current_object = INTERP->current_object;

Modified: trunk/t/op/lexicals.t
==============================================================================
--- trunk/t/op/lexicals.t       (original)
+++ trunk/t/op/lexicals.t       Tue Jan 17 04:17:18 2006
@@ -955,13 +955,124 @@ pir_output_is(<<'CODE', <<'OUTPUT', 'pac
     '&f'()
     '&f'()
 .end
+CODE
+2
+OUTPUT
+
+pir_output_is(<<'CODE', <<'OUTPUT', 'package-scoped closure 3 - autoclose');
+#     sub f ($x) { 
+#         sub g ($y) { $x + $y }; g($x); 
+#     } 
+#     f(10); # 20 
+#     g(100); # 110
+.sub '&f' 
+    .param pmc x
+    .lex '$x', x
+    $P0 = '&g'(x)
+    .return ($P0)
+.end
+
+.sub '&g' :outer('&f')
+    .param pmc y
+    .lex '$y', y
+    .local pmc x
+    x = find_lex '$x'
+    $P0 = n_add x, y
+    .return ($P0)
+.end
 
+.sub '&main' :main :anon
+    $P0 = '&f'(10)
+    print $P0
+    print "\n"
+    $P0 = '&g'(100)
+    print $P0
+    print "\n"
+.end
 
 
 CODE
-2
+20
+110
+OUTPUT
+
+pir_output_like(<<'CODE', <<'OUTPUT', 'package-scoped closure 4 - autoclose');
+#     sub f ($x) { 
+#         sub g () { print $x }; 
+#     } 
+#     g(); 
+.sub '&f' 
+    .param pmc x
+    .lex '$x', x
+.end
+
+.sub '&g' :outer('&f')
+    .local pmc x
+    x = find_lex '$x'
+    print x
+.end
+
+.sub '&main' :main :anon
+    '&g'()
+    print "never\n"
+.end
+CODE
+/Null PMC access/
+OUTPUT
+
+pir_output_is(<<'CODE', <<'OUTPUT', 'package-scoped closure 5 - autoclose');
+#     sub f ($x) { 
+#         sub g () { print "$x\n" }; 
+#     } 
+#     f(10); 
+#     g(); 
+.sub '&f' 
+    .param pmc x
+    .lex '$x', x
+.end
+
+.sub '&g' :outer('&f')
+    .local pmc x
+    x = find_lex '$x'
+    print x
+    print "\n"
+.end
+
+.sub '&main' :main :anon
+    '&f'(10)
+    '&g'()
+.end
+CODE
+10
 OUTPUT
 
+pir_output_is(<<'CODE', <<'OUTPUT', 'package-scoped closure 6 - autoclose');
+#     sub f ($x) { 
+#         sub g () { print "$x\n" }; 
+#     } 
+#     f(10); 
+#     f(20); 
+#     g(); 
+.sub '&f' 
+    .param pmc x
+    .lex '$x', x
+.end
+
+.sub '&g' :outer('&f')
+    .local pmc x
+    x = find_lex '$x'
+    print x
+    print "\n"
+.end
+
+.sub '&main' :main :anon
+    '&f'(10)
+    '&f'(20)
+    '&g'()
+.end
+CODE
+20
+OUTPUT
 
 ## remember to change the number of tests :-)
-BEGIN { plan tests => 38; }
+BEGIN { plan tests => 42; }

Reply via email to