Author: leo
Date: Mon Nov 14 07:23:30 2005
New Revision: 9970
Modified:
trunk/src/sub.c
trunk/t/op/lexicals.t
Log:
lexicals 21 - another test: Piers' famous example
* more fun with continuations: backtracking and closures
* converted to pdd20 lexicals from t/op/gc_13.pir
* small bug fixes for outer ctx lookup
* works
Modified: trunk/src/sub.c
==============================================================================
--- trunk/src/sub.c (original)
+++ trunk/src/sub.c Mon Nov 14 07:23:30 2005
@@ -436,7 +436,7 @@ Parrot_find_pad(Interp* interpreter, STR
lex_pad = ctx->lex_pad;
if (PMC_IS_NULL(lex_pad))
return NULL;
- sub = PMC_sub(sub)->outer_sub;
+ sub = ctx->current_sub;
}
return NULL;
}
Modified: trunk/t/op/lexicals.t
==============================================================================
--- trunk/t/op/lexicals.t (original)
+++ trunk/t/op/lexicals.t Mon Nov 14 07:23:30 2005
@@ -16,7 +16,7 @@ Tests various lexical scratchpad operati
=cut
-use Parrot::Test tests => 33;
+use Parrot::Test tests => 34;
output_is(<<'CODE', <<'OUTPUT', '.lex parsing - PASM');
.pcc_sub main:
@@ -381,6 +381,145 @@ CODE
27
OUTPUT
+pir_output_is(<<'CODE', <<'OUTPUT', 'closure 4');
+# code by Piers Cawley
+=pod
+
+ ;;; Indicate that the computation has failed, and that the program
+ ;;; should try another path. We rebind this variable as needed.
+ (define fail
+ (lambda () (error "Program failed")))
+
+ ;;; Choose an arbitrary value and return it, with backtracking.
+ ;;; You are not expected to understand this.
+ (define (choose . all-choices)
+ (let ((old-fail fail))
+ (call-with-current-continuation
+ (lambda (continuation)
+ (define (try choices)
+ (if (null? choices)
+ (begin
+ (set! fail old-fail)
+ (fail))
+ (begin
+ (set! fail
+ (lambda () (continuation (try (cdr choices)))))
+ (car choices))))
+ (try all-choices)))))
+
+ ;;; Find two numbers with a product of 15.
+ (let ((x (choose 1 3 5))
+ (y (choose 1 5 9)))
+ (for-each display `("Trying " ,x " and " ,y #\newline))
+ (unless (= (* x y) 15)
+ (fail))
+ (for-each display `("Found " ,x " * " ,y " = 15" #\newline)))
+
+=cut
+
+.sub main :main
+ .local pmc fail, arr1, arr2, x, y, choose
+ .lex 'fail', fail
+ .lex 'arr1', arr1
+ .lex 'arr2', arr2
+ .lex 'x', x
+ .lex 'y', y
+ .lex 'choose', choose
+ .const .Sub choose_sub = "_choose"
+ .const .Sub fail_sub = "_fail"
+ fail = newclosure fail_sub
+ arr1 = new PerlArray
+ arr1[0] = 1
+ arr1[1] = 3
+ arr1[2] = 5
+ arr2 = new PerlArray
+ arr2[0] = 1
+ arr2[1] = 5
+ arr2[2] = 9
+
+ choose = newclosure choose_sub
+ x = choose(arr1)
+ #print "Chosen "
+ #print x
+ #print " from arr1\n"
+
+ # need to create a new closure: these closures have different state
+ choose = newclosure choose_sub
+ y = choose(arr2)
+ #print "Chosen "
+ #print y
+ #print " from arr2\n"
+ $I1 = x
+ $I2 = y
+ $I0 = $I1 * $I2
+ if $I0 == 15 goto success
+ fail()
+ print "Shouldn't get here without a failure report\n"
+ branch the_end
+success:
+ print x
+ print " * "
+ print y
+ print " == 15!\n"
+the_end:
+ end
+.end
+
+.sub _choose :outer(main)
+ .param PerlArray choices
+ .local pmc our_try, old_fail, cc, try
+ .lex 'old_fail', old_fail
+ .lex 'cc', cc
+ .lex 'try', try
+ #print "In choose\n"
+ old_fail = find_lex "fail"
+ .include "interpinfo.pasm"
+ $P1 = interpinfo .INTERPINFO_CURRENT_CONT
+ store_lex "cc", $P1
+ .const .Sub tr_sub = "_try"
+ newclosure our_try, tr_sub
+ store_lex "try", our_try
+ $P2 = our_try(choices)
+ .return($P2)
+.end
+
+.sub _try :outer(_choose)
+ .param PerlArray choices
+ .lex 'choices', $P0
+ #print "In try\n"
+ clone $P0, choices
+ if choices goto have_choices
+ $P1 = find_lex "old_fail"
+ store_lex "fail", $P1
+ $P1()
+have_choices:
+ .const .Sub f = "new_fail"
+ newclosure $P2, f
+ store_lex "fail", $P2
+ $P3 = find_lex "choices"
+ shift $P4, $P3
+
+ .return($P4)
+.end
+
+.sub new_fail :outer(_try)
+ .local pmc our_try
+ .local pmc our_cc
+ #print "In new_fail\n"
+ our_cc = find_lex "cc"
+ our_try = find_lex "try"
+ $P2 = find_lex "choices"
+ $P3 = our_try($P2)
+ our_cc($P3)
+.end
+
+.sub _fail
+ print "Program failed\n"
+.end
+CODE
+3 * 5 == 15!
+OUTPUT
+
pir_output_like(<<'CODE', <<'OUTPUT', 'get non existing');
.sub "main"
.lex 'a', $P0