Author: leo
Date: Mon Jan 16 05:26:23 2006
New Revision: 11212

Modified:
   trunk/compilers/imcc/pbc.c
   trunk/src/classes/closure.pmc
   trunk/t/op/lexicals.t
Log:
lexicals - experimental support for package-scoped closures

* .sub bar :outer(foo) creates 'bar' as closure
* if it's invoked as is (no newclosure cloning code), it locates
  'foo' in the call chain and sets outer_ctx to that context
* tests; also remove bogus tests with multiple indentical sub names


Modified: trunk/compilers/imcc/pbc.c
==============================================================================
--- trunk/compilers/imcc/pbc.c  (original)
+++ trunk/compilers/imcc/pbc.c  Mon Jan 16 05:26:23 2006
@@ -656,7 +656,8 @@ add_const_pmc_sub(Interp *interpreter, S
 
 
     type = (r->pcc_sub->calls_a_sub & ITPCCYIELD) ?
-        enum_class_Coroutine : enum_class_Sub;
+        enum_class_Coroutine :
+        unit->outer ? enum_class_Closure : enum_class_Sub;
     /* TODO constant - see also src/packfile.c
     */
     sub_pmc = pmc_new(interpreter, type);

Modified: trunk/src/classes/closure.pmc
==============================================================================
--- trunk/src/classes/closure.pmc       (original)
+++ trunk/src/classes/closure.pmc       Mon Jan 16 05:26:23 2006
@@ -84,6 +84,21 @@ Invokes the closure.
              */
             sub->ctx->outer_ctx = sub->outer_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;
+                }
+                caller = caller->caller_ctx;
+            }
+            if (!caller)
+                real_exception(interpreter, NULL, INVALID_OPERATION,
+                        ":outer '%Ss' not found", 
+                        VTABLE_get_string(INTERP, sub->outer_sub));
+        }
         return next;
     }
 }

Modified: trunk/t/op/lexicals.t
==============================================================================
--- trunk/t/op/lexicals.t       (original)
+++ trunk/t/op/lexicals.t       Mon Jan 16 05:26:23 2006
@@ -465,121 +465,6 @@ main
 I messed with your var
 OUTPUT
 
-
-pir_output_is(<<'CODE', <<'OUTPUT', 'get_outer(outer sub name reused) - always 
uses first sub of same name');
-.sub main :main
-       bar()
-.end
-
-.sub foo :anon :outer('main')
-.end
-
-.sub foo :anon
-.end
-
-.sub foo
-.end
-
-.sub bar :outer('foo')
-       .include 'interpinfo.pasm'
-       $P1 = interpinfo .INTERPINFO_CURRENT_SUB
-       $P2 = $P1.'get_outer'()
-       print $P2
-       print "\n"
-       $P3 = $P2.'get_outer'()
-       print $P3
-       print "\n"
-.end
-CODE
-foo
-main
-OUTPUT
-
-pir_output_like(<<'CODE', <<'OUTPUT', 'get_outer(outer sub name reused) - 
always uses first sub of same name');
-.sub main :main
-       bar()
-.end
-
-.sub foo :anon
-.end
-
-.sub foo :anon :outer('main')
-.end
-
-.sub foo
-.end
-
-.sub bar :outer('foo')
-       .include 'interpinfo.pasm'
-       $P1 = interpinfo .INTERPINFO_CURRENT_SUB
-       $P2 = $P1.'get_outer'()
-       print $P2
-       print "\n"
-       $P3 = $P2.'get_outer'()
-       print $P3
-       print "\n"
-.end
-CODE
-/foo\nNull PMC access in get_string()/
-OUTPUT
-
-pir_output_is(<<'CODE', <<'OUTPUT', 'get_outer(outer sub name reused) - always 
uses first sub of same name');
-.sub main :main
-       bar()
-.end
-
-.sub foo :outer('main')
-.end
-
-.sub foo :anon
-.end
-
-.sub foo :anon
-.end
-
-.sub bar :outer('foo')
-       .include 'interpinfo.pasm'
-       $P1 = interpinfo .INTERPINFO_CURRENT_SUB
-       $P2 = $P1.'get_outer'()
-       print $P2
-       print "\n"
-       $P3 = $P2.'get_outer'()
-       print $P3
-       print "\n"
-.end
-CODE
-foo
-main
-OUTPUT
-
-pir_output_like(<<'CODE', <<'OUTPUT', 'get_outer(outer sub name reused) - 
always uses first sub of same name');
-.sub main :main
-       bar()
-.end
-
-.sub foo
-.end
-
-.sub foo :anon :outer('main')
-.end
-
-.sub foo :anon
-.end
-
-.sub bar :outer('foo')
-       .include 'interpinfo.pasm'
-       $P1 = interpinfo .INTERPINFO_CURRENT_SUB
-       $P2 = $P1.'get_outer'()
-       print $P2
-       print "\n"
-       $P3 = $P2.'get_outer'()
-       print $P3
-       print "\n"
-.end
-CODE
-/foo\nNull PMC access in get_string()/
-OUTPUT
-
 pir_output_is(<<'CODE', <<'OUTPUT', 'closure 3');
 # sub foo {
 #     my ($n) = @_;
@@ -1024,6 +909,59 @@ ok
 ok
 OUTPUT
 
+pir_output_is(<<'CODE', <<'OUTPUT', 'package-scoped closure 1');
+# my $x;
+# sub f{$x++}
+# f()
+# print "$x\n"
+.sub '&main' :main :anon
+    .local pmc sx
+    .lex '$x', sx
+    sx = new .PerlUndef
+    '&f'()
+    print sx   # no find_lex needed - 'sx' is defined here
+    print "\n"
+.end
+
+.sub '&f' :outer('&main') 
+    $P0 = find_lex '$x'           # find_lex needed
+    inc $P0
+.end
+CODE
+1
+OUTPUT
+
+pir_output_is(<<'CODE', <<'OUTPUT', 'package-scoped closure 2');
+# my $x;
+# sub f{$x++}
+# sub g{f();f()}
+# g()
+# print "$x\n"
+.sub '&main' :main :anon
+    .local pmc sx
+    .lex '$x', sx
+    sx = new .PerlUndef
+    '&g'()
+    print sx
+    print "\n"
+.end
+
+.sub '&f' :outer('&main') 
+    $P0 = find_lex '$x'
+    inc $P0
+.end
+
+.sub '&g' :outer('&main') # :outer not needed - no find_lex
+    '&f'()
+    '&f'()
+.end
+
+
+
+CODE
+2
+OUTPUT
+
 
 ## remember to change the number of tests :-)
-BEGIN { plan tests => 40; }
+BEGIN { plan tests => 38; }

Reply via email to