2 # Copyright (C) 2001-2008, The Perl Foundation.
7 use lib qw( . lib ../lib ../../lib );
10 use Parrot::Test tests => 47;
14 t/op/lexicals.t - Lexical Ops
18 % prove t/op/lexicals.t
22 Tests various lexical scratchpad operations, as described in PDD20.
26 pasm_output_is( <<'CODE', <<'OUTPUT', '.lex parsing - PASM (\'$a\') succeeds' );
35 pir_output_is( <<'CODE', <<'OUTPUT', '.lex parsing - PIR' );
44 pir_output_is( <<'CODE', <<'OUTPUT', '.lex parsing - PIR, $P' );
54 pir_output_is( <<'CODE', <<'OUTPUT', '.lex parsing - PIR, local var' );
64 pasm_output_is( <<'CODE', <<'OUTPUT', '.lex - same PMC twice (PASM)' );
80 pir_output_is( <<'CODE', <<'OUTPUT', '.lex - same PMC twice fails (.local pmc ab)' );
97 pir_output_is( <<'CODE', <<'OUTPUT', '.lex - same lex twice' );
107 pir_output_is( <<'CODE', <<'OUTPUT', 'api parsing' );
113 .include 'interpinfo.pasm'
114 load_bytecode "pcore.pir" # TODO autoload/preload
115 interpinfo $P1, .INTERPINFO_CURRENT_SUB
116 $P2 = $P1.'get_lexinfo'()
117 $P2 = $P1.'get_lexenv'()
125 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexinfo' );
129 .include "interpinfo.pasm"
130 interpinfo $P1, .INTERPINFO_CURRENT_SUB
131 $P2 = $P1.'get_lexinfo'()
142 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexinfo - no lexicals' );
144 .include "interpinfo.pasm"
145 interpinfo $P1, .INTERPINFO_CURRENT_SUB
146 $P2 = $P1.'get_lexinfo'()
148 print "LexInfo not NULL\n"
157 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - no pad' );
159 .local pmc pad, interp
161 pad = interp["lexpad"]
163 print "pad not NULL\n"
173 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - no pad inherited in coro' );
178 .local pmc pad, interp
180 pad = interp["lexpad"]
182 print "pad not NULL\n"
192 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - set var via pad' );
194 .local pmc pad, interp
196 pad = interp["lexpad"]
198 unless null pad goto ok
199 print "pad is NULL\n"
215 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - set two vars via pad (2 lex -> 2 pmc)' );
219 .local pmc pad, interp
221 pad = interp["lexpad"]
223 unless null pad goto ok
224 print "pad is NULL\n"
245 pir_output_is( <<'CODE', <<'OUTPUT', 'synopsis example' );
259 pasm_output_is( <<'CODE', <<'OUTPUT', ':lex parsing - PASM' );
269 pir_output_is( <<'CODE', <<'OUTPUT', ':lex parsing - PIR' );
279 pasm_output_is( <<'CODE', <<'OUTPUT', ':outer parsing - PASM' );
283 .pcc_sub :outer('main') foo:
289 pir_output_is( <<'CODE', <<'OUTPUT', ':outer parsing - PIR' );
293 .sub foo :outer('main')
299 pir_output_is( <<'CODE', <<'OUTPUT', ':outer parsing - ident' );
306 .sub foo :outer(main)
312 pir_error_output_like( <<'CODE', <<'OUTPUT', ':outer parsing - missing :outer' );
316 .sub foo :outer(oops)
319 /Undefined :outer sub 'oops'\./
322 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexinfo from pad' );
325 .local pmc pad, interp, info
327 pad = interp["lexpad"]
328 unless null pad goto ok
329 print "pad is NULL\n"
333 info = pad.'get_lexinfo'()
344 pir_output_is( <<'CODE', <<'OUTPUT', ':lex parsing - verify info and pad' );
350 .local pmc pad, interp, info
352 pad = interp["lexpad"]
353 unless null pad goto ok
354 print "pad is NULL\n"
361 info = pad.'get_lexinfo'()
373 pir_output_is( <<'CODE', <<'OUTPUT', 'get_outer' );
377 .sub foo :outer('main')
378 .include "interpinfo.pasm"
379 interpinfo $P1, .INTERPINFO_CURRENT_SUB
380 $P2 = $P1."get_outer"()
388 pir_output_is( <<'CODE', <<'OUTPUT', 'get_outer 2' );
392 .sub foo :outer('main')
395 .sub bar :outer('foo')
396 .include "interpinfo.pasm"
397 interpinfo $P1, .INTERPINFO_CURRENT_SUB
398 $P2 = $P1."get_outer"()
401 $P3 = $P2."get_outer"()
410 pir_output_is( <<'CODE', <<'OUTPUT', 'get_outer via interp' );
412 .const .Sub foo = "foo"
415 foo_cl = newclosure foo
419 .sub foo :outer('main')
420 .const .Sub bar = "bar"
422 bar_cl = newclosure bar
425 .sub bar :outer('foo')
426 .local pmc sub, interp, pad
428 sub = interp["outer"]
431 sub = interp["outer"; "sub"]
434 sub = interp["outer"; 2]
437 sub = interp["outer"; "sub"; 2]
441 $P0 = "I messed with your var\n"
442 pad = interp["outer"; "lexpad"; 2]
450 I messed with your var
453 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 3' );
459 # print &$f(3), "\n";
461 # print &$g(3), "\n";
462 # print &$f(3), "\n";
463 # print &$g(4), "\n";
470 .const .Sub anon = "anon"
471 $P0 = newclosure anon
475 .sub anon :outer(foo)
478 # in practice we need copying the arg but as it is passed
479 # as native int, we already have a fresh pmc
510 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 4' );
511 # code by Piers Cawley
514 ;;; Indicate that the computation has failed, and that the program
515 ;;; should try another path. We rebind this variable as needed.
517 (lambda () (error "Program failed")))
519 ;;; Choose an arbitrary value and return it, with backtracking.
520 ;;; You are not expected to understand this.
521 (define (choose . all-choices)
522 (let ((old-fail fail))
523 (call-with-current-continuation
524 (lambda (continuation)
525 (define (try choices)
532 (lambda () (continuation (try (cdr choices)))))
534 (try all-choices)))))
536 ;;; Find two numbers with a product of 15.
537 (let ((x (choose 1 3 5))
539 (for-each display `("Trying " ,x " and " ,y #\newline))
540 (unless (= (* x y) 15)
542 (for-each display `("Found " ,x " * " ,y " = 15" #\newline)))
547 .local pmc fail, arr1, arr2, x, y, choose
553 .lex 'choose', choose
554 .const .Sub choose_sub = "_choose"
555 .const .Sub fail_sub = "_fail"
556 fail = newclosure fail_sub
557 arr1 = new 'ResizablePMCArray'
561 arr2 = new 'ResizablePMCArray'
566 choose = newclosure choose_sub
570 #print " from arr1\n"
572 # need to create a new closure: these closures have different state
573 choose = newclosure choose_sub
577 #print " from arr2\n"
581 if $I0 == 15 goto success
583 print "Shouldn't get here without a failure report\n"
594 .sub _choose :outer(main)
597 .local pmc our_try, old_fail, cc, try
598 .lex 'old_fail', old_fail
602 old_fail = find_lex "fail"
603 .include "interpinfo.pasm"
604 $P1 = interpinfo .INTERPINFO_CURRENT_CONT
606 .const .Sub tr_sub = "_try"
607 newclosure our_try, tr_sub
608 store_lex "try", our_try
609 $P2 = our_try(choices)
613 .sub _try :outer(_choose)
619 if choices goto have_choices
620 $P1 = find_lex "old_fail"
621 store_lex "fail", $P1
624 .const .Sub f = "new_fail"
626 store_lex "fail", $P2
627 $P3 = find_lex "choices"
633 .sub new_fail :outer(_try)
636 #print "In new_fail\n"
637 our_cc = find_lex "cc"
638 our_try = find_lex "try"
639 $P2 = find_lex "choices"
644 .sub _fail :outer(main)
645 print "Program failed\n"
651 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 5' );
652 # FIXME - we need to detect the destruction of the P registers
653 # associated with the Contexts for the calls of xyzzy and plugh.
654 # Otherwise, this test is just a repeat of others
679 .const .Sub bar_sub = "bar"
680 $P1 = newclosure bar_sub
684 .sub bar :anon :outer(foo)
697 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 6' );
698 # Leo's version of xyzzy original by particle, p5 by chip #'
734 .const .Sub closure = 'bar'
735 $P2 = newclosure closure
739 .sub bar :anon :outer(foo)
757 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 7 - evaled' );
794 .sub bar :anon :outer(foo)
804 compiler = compreg "PIR"
806 $P2 = $P1[0] # first sub of eval
820 pir_error_output_like( <<'CODE', <<'OUT', 'closure 8' );
822 # p6 example from pmichaud
823 # { my $x = 5; { print $x; my $x = 4; print $x; } }
825 ## According to S04 this is an error
834 .sub anon_1 :anon :outer(main)
847 pir_error_output_like( <<'CODE', <<'OUTPUT', 'get non existing' );
852 .sub foo :outer('main')
856 .sub bar :outer('foo')
858 $P2 = find_lex 'no_such'
861 /Lexical 'no_such' not found/
864 pir_output_is( <<'CODE', <<'OUTPUT', 'find_name on lexicals' );
881 pir_output_is( <<'CODE', <<'OUTPUT', 'multiple names' );
903 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 1' );
908 .sub '&main' :main :anon
914 print sx # no find_lex needed - 'sx' is defined here
926 .sub '&f' :outer('&main')
927 $P0 = find_lex '$x' # find_lex needed
936 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 2' );
942 .sub '&main' :main :anon
961 .sub '&f' :outer('&main')
966 .sub '&g' :outer('&main') # :outer not needed - no find_lex
976 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 3 - autoclose' );
978 # sub g ($y) { $x + $y }; g($x);
989 .sub '&g' :outer('&f')
998 .sub '&main' :main :anon
1013 pir_error_output_like( <<'CODE', <<'OUTPUT', 'package-scoped closure 4 - autoclose' );
1015 # sub g () { print $x };
1023 .sub '&g' :outer('&f')
1029 .sub '&main' :main :anon
1037 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 5 - autoclose' );
1039 # sub g () { print "$x\n" };
1048 .sub '&g' :outer('&f')
1055 .sub '&main' :main :anon
1063 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 6 - autoclose' );
1065 # sub g () { print "$x\n" };
1075 .sub '&g' :outer('&f')
1082 .sub '&main' :main :anon
1091 pir_output_is( <<'CODE', <<'OUTPUT', 'find_lex: (Perl6 OUTER::)', todo => 'not yet implemented' );
1097 .sub 'get_outer' :outer('main')
1099 $P0 = find_lex '$x', 1
1106 pir_output_is( <<'CODE', <<'OUTPUT', 'Example for RT #44395' );
1110 # The following PIR should be like:
1120 # create some closures, outer scope
1130 print "Sub $sub_num was called $not_shared times. Any sub was called $shared times.\n";
1138 foreach ( @closures ) {
1147 .sub test_closures :main
1149 .lex '@closures', $P0
1150 $P0 = new 'ResizablePMCArray'
1152 # create some closures, outer scope
1155 # and call them in turn.
1158 if $I0 >= 4 goto DONE_LOOP0
1161 if $I1 >= 3 goto DONE_LOOP1
1173 # Return n closures, each with lexical references to "$n" and "$sub_num".
1174 .sub 'outer_scope' :outer('test_closures')
1182 if $I3 > 3 goto DONE
1191 .sub 'inner_scope' :outer('outer_scope')
1194 .lex '$sub_num', $P0
1198 .lex '$not_shared', $P1
1202 find_lex $P2, '@closures'
1203 .const .Sub $P3 = 'anonymous'
1210 .sub 'anonymous' :outer('inner_scope')
1212 find_lex $P0, '$sub_num'
1213 find_lex $P1, '$not_shared'
1214 find_lex $P2, '$shared'
1218 print " was called "
1220 print " times. Any sub was called "
1232 Sub 1 was called 1 times. Any sub was called 1 times.
1233 Sub 2 was called 1 times. Any sub was called 2 times.
1234 Sub 3 was called 1 times. Any sub was called 3 times.
1235 Sub 1 was called 2 times. Any sub was called 4 times.
1236 Sub 2 was called 2 times. Any sub was called 5 times.
1237 Sub 3 was called 2 times. Any sub was called 6 times.
1238 Sub 1 was called 3 times. Any sub was called 7 times.
1239 Sub 2 was called 3 times. Any sub was called 8 times.
1240 Sub 3 was called 3 times. Any sub was called 9 times.
1241 Sub 1 was called 4 times. Any sub was called 10 times.
1242 Sub 2 was called 4 times. Any sub was called 11 times.
1243 Sub 3 was called 4 times. Any sub was called 12 times.
1246 pir_output_is( <<'CODE', <<'OUTPUT', 'Double-inner scope called from closure (RT #56184)' );
1253 .sub 'foo' :outer('main')
1258 $P0 = get_global 'bar'
1259 bar = newclosure $P0
1263 .sub 'bar' :outer('foo')
1273 .sub 'bar_inner' :outer('bar')
1285 pir_output_is( <<'CODE', <<'OUTPUT', "RT#56398: Patrick's request" );
1292 .sub 'foo' :lexid('foo')
1300 .sub 'inner' :outer('foo')
1318 pir_output_is( <<'CODE', <<'OUTPUT', "RT#56398: Bob's recursion bug");
1324 .param int recursive_p
1325 unless recursive_p goto do_lex
1326 print "rpwi: recursive case\n"
1329 .lex "(SAVED *SHARP-EQUAL-ALIST*)", $P40
1330 $P40 = new 'Integer'
1332 .const .Sub $P80 = "(:INTERNAL rpwi 0)"
1333 newclosure $P81, $P80
1334 ## $P81 = clone $P80
1336 print "rpwi: lex case\n"
1341 .sub "(:INTERNAL rpwi 0)" :anon :outer('rpwi')
1342 print "[restoring *SHARP-EQUAL-ALIST*]\n"
1343 find_lex $P40, "(SAVED *SHARP-EQUAL-ALIST*)"
1350 rpwi: recursive case
1351 [restoring *SHARP-EQUAL-ALIST*]
1355 pir_output_is( <<'CODE', <<'OUTPUT', "RT#56398: Jonathan's recursive case" );
1357 $P0 = new 'ResizablePMCArray'
1359 $P1 = new 'ResizablePMCArray'
1360 $P2 = new 'ResizablePMCArray'
1364 $P3 = new 'ResizablePMCArray'
1371 'dump_thing'($P0, '# ')
1377 .lex '$thing', thing
1378 .lex '$prefix', prefix
1380 $P0 = find_global 'anon_1'
1381 $P1 = newclosure $P0
1384 $P2 = find_lex '$thing'
1385 $I0 = isa $P2, 'ResizablePMCArray'
1386 unless $I0 goto not_ResizablePMCArray
1388 $P3 = find_lex '$prefix'
1391 $P4 = find_global 'anon_2'
1392 $P5 = newclosure $P4
1393 $P6 = find_lex '$thing'
1395 $P7 = find_lex '$prefix'
1400 not_ResizablePMCArray:
1401 $P8 = find_lex '$prefix'
1403 $P9 = find_lex '$thing'
1409 .sub 'anon_1' :outer('dump_thing')
1411 .lex '$subthing', subthing
1412 $P0 = find_lex '$subthing'
1413 $P1 = find_lex '$prefix'
1415 $P2 = concat $P1, ' '
1416 'dump_thing'($P0, $P2)
1419 .sub 'anon_2' :outer('dump_thing')
1422 $P0 = find_lex '$recur'
1430 .local pmc result, it
1431 result = new 'ResizablePMCArray'
1434 unless it goto loop_end
1462 # cperl-indent-level: 4
1465 # vim: expandtab shiftwidth=4: