2 # Copyright (C) 2001-2010, Parrot Foundation.
7 use lib qw( . lib ../lib ../../lib );
12 $ENV{TEST_PROG_ARGS} ||= '';
14 plan( skip_all => 'lexicals not thawed properly from PBC, TT #1171' )
15 if $ENV{TEST_PROG_ARGS} =~ /--run-pbc/;
21 t/op/lexicals.t - Lexical Ops
25 % prove t/op/lexicals.t
29 Tests various lexical scratchpad operations, as described in PDD20.
33 pasm_output_is( <<'CODE', <<'OUTPUT', '.lex parsing - PASM (\'$a\') succeeds' );
42 pir_output_is( <<'CODE', <<'OUTPUT', '.lex parsing - PIR' );
51 pir_output_is( <<'CODE', <<'OUTPUT', '.lex parsing - PIR, $P' );
61 pir_output_is( <<'CODE', <<'OUTPUT', '.lex parsing - PIR, local var' );
71 pasm_output_is( <<'CODE', <<'OUTPUT', '.lex - same PMC twice (PASM)' );
87 pir_output_is( <<'CODE', <<'OUTPUT', '.lex - same PMC twice fails (.local pmc ab)' );
104 pir_output_is( <<'CODE', <<'OUTPUT', '.lex - same lex twice' );
114 pir_output_is( <<'CODE', <<'OUTPUT', 'api parsing' );
120 .include 'interpinfo.pasm'
121 load_bytecode 'pcore.pbc' # TODO autoload/preload
122 interpinfo $P1, .INTERPINFO_CURRENT_SUB
123 $P2 = $P1.'get_lexinfo'()
124 $P2 = $P1.'get_lexenv'()
132 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexinfo' );
136 .include "interpinfo.pasm"
137 interpinfo $P1, .INTERPINFO_CURRENT_SUB
138 $P2 = $P1.'get_lexinfo'()
149 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexinfo - no lexicals' );
151 .include "interpinfo.pasm"
152 interpinfo $P1, .INTERPINFO_CURRENT_SUB
153 $P2 = $P1.'get_lexinfo'()
155 print "LexInfo not NULL\n"
164 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - no pad' );
166 .local pmc pad, interp
168 pad = interp["lexpad"]
170 print "pad not NULL\n"
180 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - no pad inherited in coro' );
185 .local pmc pad, interp
187 pad = interp["lexpad"]
189 print "pad not NULL\n"
199 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - set var via pad' );
201 .local pmc pad, interp
203 pad = interp["lexpad"]
205 unless null pad goto ok
206 print "pad is NULL\n"
222 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - set two vars via pad (2 lex -> 2 pmc)' );
226 .local pmc pad, interp
228 pad = interp["lexpad"]
229 unless null pad goto ok
230 print "pad is NULL\n"
251 pir_output_is( <<'CODE', <<'OUTPUT', 'synopsis example' );
265 pasm_output_is( <<'CODE', <<'OUTPUT', ':lex parsing - PASM' );
275 pir_output_is( <<'CODE', <<'OUTPUT', ':lex parsing - PIR' );
285 pasm_output_is( <<'CODE', <<'OUTPUT', ':outer parsing - PASM' );
289 .pcc_sub :outer('main') foo:
295 pir_output_is( <<'CODE', <<'OUTPUT', ':outer parsing - PIR' );
299 .sub foo :outer('main')
305 pir_output_is( <<'CODE', <<'OUTPUT', ':outer parsing - ident' );
312 .sub foo :outer(main)
318 pir_error_output_like( <<'CODE', <<'OUTPUT', ':outer parsing - missing :outer' );
322 .sub foo :outer(oops)
325 /Undefined :outer sub 'oops'\./
328 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexinfo from pad' );
331 .local pmc pad, interp, info
333 pad = interp["lexpad"]
334 unless null pad goto ok
335 print "pad is NULL\n"
339 info = pad.'get_lexinfo'()
350 pir_output_is( <<'CODE', <<'OUTPUT', ':lex parsing - verify info and pad' );
356 .local pmc pad, interp, info
358 pad = interp["lexpad"]
359 unless null pad goto ok
360 print "pad is NULL\n"
367 info = pad.'get_lexinfo'()
379 pir_output_is( <<'CODE', <<'OUTPUT', 'get_outer' );
383 .sub foo :outer('main')
384 .include "interpinfo.pasm"
385 interpinfo $P1, .INTERPINFO_CURRENT_SUB
386 $P2 = $P1."get_outer"()
394 pir_output_is( <<'CODE', <<'OUTPUT', 'get_outer 2' );
398 .sub foo :outer('main')
401 .sub bar :outer('foo')
402 .include "interpinfo.pasm"
403 interpinfo $P1, .INTERPINFO_CURRENT_SUB
404 $P2 = $P1."get_outer"()
407 $P3 = $P2."get_outer"()
416 pir_output_is( <<'CODE', <<'OUTPUT', 'get_outer via interp' );
418 .const 'Sub' foo = "foo"
421 foo_cl = newclosure foo
425 .sub foo :outer('main')
426 .const 'Sub' bar = "bar"
428 bar_cl = newclosure bar
431 .sub bar :outer('foo')
432 .local pmc sub, interp, pad
434 sub = interp["outer"]
437 sub = interp["outer"; "sub"]
440 sub = interp["outer"; 2]
443 sub = interp["outer"; "sub"; 2]
447 $P0 = "I messed with your var\n"
448 pad = interp["outer"; "lexpad"; 2]
456 I messed with your var
459 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 3' );
465 # print &$f(3), "\n";
467 # print &$g(3), "\n";
468 # print &$f(3), "\n";
469 # print &$g(4), "\n";
476 .const 'Sub' anon = "anon"
477 $P0 = newclosure anon
481 .sub anon :outer(foo)
484 # in practice we need copying the arg but as it is passed
485 # as native int, we already have a fresh pmc
516 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 4' );
517 # code by Piers Cawley
520 ;;; Indicate that the computation has failed, and that the program
521 ;;; should try another path. We rebind this variable as needed.
523 (lambda () (error "Program failed")))
525 ;;; Choose an arbitrary value and return it, with backtracking.
526 ;;; You are not expected to understand this.
527 (define (choose . all-choices)
528 (let ((old-fail fail))
529 (call-with-current-continuation
530 (lambda (continuation)
531 (define (try choices)
538 (lambda () (continuation (try (cdr choices)))))
540 (try all-choices)))))
542 ;;; Find two numbers with a product of 15.
543 (let ((x (choose 1 3 5))
545 (for-each display `("Trying " ,x " and " ,y #\newline))
546 (unless (= (* x y) 15)
548 (for-each display `("Found " ,x " * " ,y " = 15" #\newline)))
553 .local pmc fail, arr1, arr2, x, y, choose
559 .lex 'choose', choose
560 .const 'Sub' choose_sub = "_choose"
561 .const 'Sub' fail_sub = "_fail"
562 fail = newclosure fail_sub
563 arr1 = new 'ResizablePMCArray'
567 arr2 = new 'ResizablePMCArray'
572 choose = newclosure choose_sub
576 #print " from arr1\n"
578 # need to create a new closure: these closures have different state
579 choose = newclosure choose_sub
583 #print " from arr2\n"
587 if $I0 == 15 goto success
589 print "Shouldn't get here without a failure report\n"
600 .sub _choose :outer(main)
603 .local pmc our_try, old_fail, cc, try
604 .lex 'old_fail', old_fail
608 old_fail = find_lex "fail"
609 .include "interpinfo.pasm"
610 $P1 = interpinfo .INTERPINFO_CURRENT_CONT
612 .const 'Sub' tr_sub = "_try"
613 newclosure our_try, tr_sub
614 store_lex "try", our_try
615 $P2 = our_try(choices)
619 .sub _try :outer(_choose)
625 if choices goto have_choices
626 $P1 = find_lex "old_fail"
627 store_lex "fail", $P1
630 .const 'Sub' f = "new_fail"
632 store_lex "fail", $P2
633 $P3 = find_lex "choices"
639 .sub new_fail :outer(_try)
642 #print "In new_fail\n"
643 our_cc = find_lex "cc"
644 our_try = find_lex "try"
645 $P2 = find_lex "choices"
650 .sub _fail :outer(main)
651 print "Program failed\n"
657 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 5' );
658 # FIXME - we need to detect the destruction of the P registers
659 # associated with the Contexts for the calls of xyzzy and plugh.
660 # Otherwise, this test is just a repeat of others
685 .const 'Sub' bar_sub = "bar"
686 $P1 = newclosure bar_sub
690 .sub bar :anon :outer(foo)
703 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 6' );
704 # Leo's version of xyzzy original by particle, p5 by chip #'
740 .const 'Sub' closure = 'bar'
741 $P2 = newclosure closure
745 .sub bar :anon :outer(foo)
763 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 7 - evaled' );
800 .sub bar :anon :outer(foo)
810 compiler = compreg "PIR"
812 $P2 = $P1[0] # first sub of eval
826 pir_error_output_like( <<'CODE', <<'OUT', 'closure 8' );
828 # p6 example from pmichaud
829 # { my $x = 5; { print $x; my $x = 4; print $x; } }
831 ## According to S04 this is an error
840 .sub anon_1 :anon :outer(main)
853 pir_error_output_like( <<'CODE', <<'OUTPUT', 'get non existing' );
858 .sub foo :outer('main')
862 .sub bar :outer('foo')
864 $P2 = find_lex 'no_such'
867 /Lexical 'no_such' not found/
870 pir_output_is( <<'CODE', <<'OUTPUT', 'find_name on lexicals' );
887 pir_output_is( <<'CODE', <<'OUTPUT', 'multiple names' );
909 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 1' );
914 .sub '&main' :main :anon
920 print sx # no find_lex needed - 'sx' is defined here
932 .sub '&f' :outer('&main')
933 $P0 = find_lex '$x' # find_lex needed
942 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 2' );
948 .sub '&main' :main :anon
967 .sub '&f' :outer('&main')
972 .sub '&g' :outer('&main') # :outer not needed - no find_lex
982 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 3 - autoclose' );
984 # sub g ($y) { $x + $y }; g($x);
995 .sub '&g' :outer('&f')
1004 .sub '&main' :main :anon
1019 pir_error_output_like( <<'CODE', <<'OUTPUT', 'package-scoped closure 4 - autoclose' );
1021 # sub g () { print $x };
1029 .sub '&g' :outer('&f')
1035 .sub '&main' :main :anon
1043 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 5 - autoclose' );
1045 # sub g () { print "$x\n" };
1054 .sub '&g' :outer('&f')
1061 .sub '&main' :main :anon
1069 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 6 - autoclose' );
1071 # sub g () { print "$x\n" };
1081 .sub '&g' :outer('&f')
1088 .sub '&main' :main :anon
1097 pir_output_is( <<'CODE', <<'OUTPUT', 'find_lex: (Perl6 OUTER::)', todo => 'not yet implemented' );
1103 .sub 'get_outer' :outer('main')
1105 $P0 = find_lex '$x', 1
1112 pir_output_is( <<'CODE', <<'OUTPUT', 'nested scopes' );
1116 # The following PIR should be like:
1126 # create some closures, outer scope
1136 print "Sub $sub_num was called $not_shared times. Any sub was called $shared times.\n";
1144 foreach ( @closures ) {
1153 .sub test_closures :main
1155 .lex '@closures', $P0
1156 $P0 = new 'ResizablePMCArray'
1158 # create some closures, outer scope
1161 # and call them in turn.
1164 if $I0 >= 4 goto DONE_LOOP0
1167 if $I1 >= 3 goto DONE_LOOP1
1179 # Return n closures, each with lexical references to "$n" and "$sub_num".
1180 .sub 'outer_scope' :outer('test_closures')
1188 if $I3 > 3 goto DONE
1197 .sub 'inner_scope' :outer('outer_scope')
1200 .lex '$sub_num', $P0
1204 .lex '$not_shared', $P1
1208 find_lex $P2, '@closures'
1209 .const 'Sub' $P3 = 'anonymous'
1216 .sub 'anonymous' :outer('inner_scope')
1218 find_lex $P0, '$sub_num'
1219 find_lex $P1, '$not_shared'
1220 find_lex $P2, '$shared'
1224 print " was called "
1226 print " times. Any sub was called "
1238 Sub 1 was called 1 times. Any sub was called 1 times.
1239 Sub 2 was called 1 times. Any sub was called 2 times.
1240 Sub 3 was called 1 times. Any sub was called 3 times.
1241 Sub 1 was called 2 times. Any sub was called 4 times.
1242 Sub 2 was called 2 times. Any sub was called 5 times.
1243 Sub 3 was called 2 times. Any sub was called 6 times.
1244 Sub 1 was called 3 times. Any sub was called 7 times.
1245 Sub 2 was called 3 times. Any sub was called 8 times.
1246 Sub 3 was called 3 times. Any sub was called 9 times.
1247 Sub 1 was called 4 times. Any sub was called 10 times.
1248 Sub 2 was called 4 times. Any sub was called 11 times.
1249 Sub 3 was called 4 times. Any sub was called 12 times.
1252 pir_output_is( <<'CODE', <<'OUTPUT', 'Double-inner scope called from closure' );
1259 .sub 'foo' :outer('main')
1264 $P0 = get_global 'bar'
1265 bar = newclosure $P0
1269 .sub 'bar' :outer('foo')
1272 .const 'Sub' $P0 = 'bar_inner'
1281 .sub 'bar_inner' :outer('bar')
1293 pir_output_is( <<'CODE', <<'OUTPUT', "Patrick's request" );
1300 .sub 'foo' :subid('foo')
1308 .sub 'inner' :outer('foo')
1326 pir_output_is( <<'CODE', <<'OUTPUT', "Bob's recursion bug");
1332 .param int recursive_p
1333 unless recursive_p goto do_lex
1334 print "rpwi: recursive case\n"
1337 .lex "(SAVED *SHARP-EQUAL-ALIST*)", $P40
1338 $P40 = new 'Integer'
1340 .const 'Sub' $P80 = "(:INTERNAL rpwi 0)"
1341 newclosure $P81, $P80
1342 ## $P81 = clone $P80
1344 print "rpwi: lex case\n"
1349 .sub "(:INTERNAL rpwi 0)" :anon :outer('rpwi')
1350 print "[restoring *SHARP-EQUAL-ALIST*]\n"
1351 find_lex $P40, "(SAVED *SHARP-EQUAL-ALIST*)"
1358 rpwi: recursive case
1359 [restoring *SHARP-EQUAL-ALIST*]
1363 pir_output_is( <<'CODE', <<'OUTPUT', "Jonathan's recursive case" );
1365 $P0 = new 'ResizablePMCArray'
1367 $P1 = new 'ResizablePMCArray'
1368 $P2 = new 'ResizablePMCArray'
1372 $P3 = new 'ResizablePMCArray'
1379 'dump_thing'($P0, '# ')
1385 .lex '$thing', thing
1386 .lex '$prefix', prefix
1388 $P0 = get_hll_global 'anon_1'
1389 $P1 = newclosure $P0
1392 $P2 = find_lex '$thing'
1393 $I0 = isa $P2, 'ResizablePMCArray'
1394 unless $I0 goto not_ResizablePMCArray
1396 $P3 = find_lex '$prefix'
1399 $P4 = get_hll_global 'anon_2'
1400 $P5 = newclosure $P4
1401 $P6 = find_lex '$thing'
1403 $P7 = find_lex '$prefix'
1408 not_ResizablePMCArray:
1409 $P8 = find_lex '$prefix'
1411 $P9 = find_lex '$thing'
1417 .sub 'anon_1' :outer('dump_thing')
1419 .lex '$subthing', subthing
1420 $P0 = find_lex '$subthing'
1421 $P1 = find_lex '$prefix'
1423 $P2 = concat $P1, ' '
1424 'dump_thing'($P0, $P2)
1427 .sub 'anon_2' :outer('dump_thing')
1430 $P0 = find_lex '$recur'
1438 .local pmc result, it
1439 result = new 'ResizablePMCArray'
1442 unless it goto loop_end
1468 pir_output_is( <<'CODE', <<'OUTPUT', 'TT #536: lexical sub lookup' );
1470 .const 'Sub' $P0 = 'lexfoo'
1482 say ' - looking up lexical sub'
1489 say ' - looked up global sub, not lexical'
1492 ok 1 - looking up lexical sub
1493 ok 2 - looking up lexical sub
1496 pir_output_is( <<'CODE', <<'OUTPUT', 'find_dynamic_lex basic' );
1501 $P1 = find_dynamic_lex '$*VAR'
1502 if null $P1 goto p1_null
1509 $P1 = find_dynamic_lex '$*VAR'
1517 pir_output_is( <<'CODE', <<'OUTPUT', "find_dynamic_lex doesn't search outer" );
1530 .sub 'foo' :outer('main')
1531 $P1 = find_dynamic_lex '$*VAR'
1533 $P1 = find_lex '$*VAR'
1542 pir_output_is( <<'CODE', <<'OUTPUT', 'find_dynamic_lex two levels deep' );
1554 $P1 = find_dynamic_lex '$*VAR'
1561 pir_error_output_like( <<'CODE', <<'OUTPUT', '.lex should not accept $S#');
1567 /error.*Cannot use S register with \.lex/
1570 pir_error_output_like( <<'CODE', <<'OUTPUT', '.lex should not accept $I#');
1576 /error.*Cannot use I register with \.lex/
1579 pir_error_output_like( <<'CODE', <<'OUTPUT', '.lex should not accept $N#');
1585 /error.*Cannot use N register with \.lex/
1588 pir_error_output_like( <<'CODE', <<'OUTPUT', 'store_lex should not accept $S#');
1591 store_lex '$var', $S0
1597 pir_error_output_like( <<'CODE', <<'OUTPUT', 'store_lex should not accept $I#');
1600 store_lex '$var', $I0
1606 pir_error_output_like( <<'CODE', <<'OUTPUT', 'store_lex should not accept $N#');
1609 store_lex '$pi', $N0
1617 # cperl-indent-level: 4
1620 # vim: expandtab shiftwidth=4: