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', 'api parsing' );
110 .include 'interpinfo.pasm'
111 load_bytecode 'pcore.pbc' # TODO autoload/preload
112 interpinfo $P1, .INTERPINFO_CURRENT_SUB
113 $P2 = $P1.'get_lexinfo'()
114 $P2 = $P1.'get_lexenv'()
122 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexinfo' );
126 .include "interpinfo.pasm"
127 interpinfo $P1, .INTERPINFO_CURRENT_SUB
128 $P2 = $P1.'get_lexinfo'()
139 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexinfo - no lexicals' );
141 .include "interpinfo.pasm"
142 interpinfo $P1, .INTERPINFO_CURRENT_SUB
143 $P2 = $P1.'get_lexinfo'()
145 print "LexInfo not NULL\n"
154 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - no pad' );
156 .local pmc pad, interp
158 pad = interp["lexpad"]
160 print "pad not NULL\n"
170 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - no pad inherited in coro' );
175 .local pmc pad, interp
177 pad = interp["lexpad"]
179 print "pad not NULL\n"
189 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - set var via pad' );
191 .local pmc pad, interp
193 pad = interp["lexpad"]
195 unless null pad goto ok
196 print "pad is NULL\n"
212 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexpad - set two vars via pad (2 lex -> 2 pmc)' );
216 .local pmc pad, interp
218 pad = interp["lexpad"]
219 unless null pad goto ok
220 print "pad is NULL\n"
241 pir_output_is( <<'CODE', <<'OUTPUT', 'synopsis example' );
255 pasm_output_is( <<'CODE', <<'OUTPUT', ':lex parsing - PASM' );
265 pir_output_is( <<'CODE', <<'OUTPUT', ':lex parsing - PIR' );
275 pasm_output_is( <<'CODE', <<'OUTPUT', ':outer parsing - PASM' );
279 .pcc_sub :outer('main') foo:
285 pir_output_is( <<'CODE', <<'OUTPUT', ':outer parsing - PIR' );
289 .sub foo :outer('main')
295 pir_output_is( <<'CODE', <<'OUTPUT', ':outer parsing - ident' );
302 .sub foo :outer(main)
308 pir_error_output_like( <<'CODE', <<'OUTPUT', ':outer parsing - missing :outer' );
312 .sub foo :outer(oops)
315 /Undefined :outer sub 'oops'\./
318 pir_output_is( <<'CODE', <<'OUTPUT', 'get_lexinfo from pad' );
321 .local pmc pad, interp, info
323 pad = interp["lexpad"]
324 unless null pad goto ok
325 print "pad is NULL\n"
329 info = pad.'get_lexinfo'()
340 pir_output_is( <<'CODE', <<'OUTPUT', ':lex parsing - verify info and pad' );
346 .local pmc pad, interp, info
348 pad = interp["lexpad"]
349 unless null pad goto ok
350 print "pad is NULL\n"
357 info = pad.'get_lexinfo'()
369 pir_output_is( <<'CODE', <<'OUTPUT', 'get_outer' );
373 .sub foo :outer('main')
374 .include "interpinfo.pasm"
375 interpinfo $P1, .INTERPINFO_CURRENT_SUB
376 $P2 = $P1."get_outer"()
384 pir_output_is( <<'CODE', <<'OUTPUT', 'get_outer 2' );
388 .sub foo :outer('main')
391 .sub bar :outer('foo')
392 .include "interpinfo.pasm"
393 interpinfo $P1, .INTERPINFO_CURRENT_SUB
394 $P2 = $P1."get_outer"()
397 $P3 = $P2."get_outer"()
406 pir_output_is( <<'CODE', <<'OUTPUT', 'get_outer via interp' );
408 .const 'Sub' foo = "foo"
411 foo_cl = newclosure foo
415 .sub foo :outer('main')
416 .const 'Sub' bar = "bar"
418 bar_cl = newclosure bar
421 .sub bar :outer('foo')
422 .local pmc sub, interp, pad
424 sub = interp["outer"]
427 sub = interp["outer"; "sub"]
430 sub = interp["outer"; 2]
433 sub = interp["outer"; "sub"; 2]
437 $P0 = "I messed with your var\n"
438 pad = interp["outer"; "lexpad"; 2]
446 I messed with your var
449 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 3' );
455 # print &$f(3), "\n";
457 # print &$g(3), "\n";
458 # print &$f(3), "\n";
459 # print &$g(4), "\n";
466 .const 'Sub' anon = "anon"
467 $P0 = newclosure anon
471 .sub anon :outer(foo)
474 # in practice we need copying the arg but as it is passed
475 # as native int, we already have a fresh pmc
506 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 4' );
507 # code by Piers Cawley
510 ;;; Indicate that the computation has failed, and that the program
511 ;;; should try another path. We rebind this variable as needed.
513 (lambda () (error "Program failed")))
515 ;;; Choose an arbitrary value and return it, with backtracking.
516 ;;; You are not expected to understand this.
517 (define (choose . all-choices)
518 (let ((old-fail fail))
519 (call-with-current-continuation
520 (lambda (continuation)
521 (define (try choices)
528 (lambda () (continuation (try (cdr choices)))))
530 (try all-choices)))))
532 ;;; Find two numbers with a product of 15.
533 (let ((x (choose 1 3 5))
535 (for-each display `("Trying " ,x " and " ,y #\newline))
536 (unless (= (* x y) 15)
538 (for-each display `("Found " ,x " * " ,y " = 15" #\newline)))
543 .local pmc fail, arr1, arr2, x, y, choose
549 .lex 'choose', choose
550 .const 'Sub' choose_sub = "_choose"
551 .const 'Sub' fail_sub = "_fail"
552 fail = newclosure fail_sub
553 arr1 = new 'ResizablePMCArray'
557 arr2 = new 'ResizablePMCArray'
562 choose = newclosure choose_sub
566 #print " from arr1\n"
568 # need to create a new closure: these closures have different state
569 choose = newclosure choose_sub
573 #print " from arr2\n"
577 if $I0 == 15 goto success
579 print "Shouldn't get here without a failure report\n"
590 .sub _choose :outer(main)
593 .local pmc our_try, old_fail, cc, try
594 .lex 'old_fail', old_fail
598 old_fail = find_lex "fail"
599 .include "interpinfo.pasm"
600 $P1 = interpinfo .INTERPINFO_CURRENT_CONT
602 .const 'Sub' tr_sub = "_try"
603 newclosure our_try, tr_sub
604 store_lex "try", our_try
605 $P2 = our_try(choices)
609 .sub _try :outer(_choose)
615 if choices goto have_choices
616 $P1 = find_lex "old_fail"
617 store_lex "fail", $P1
620 .const 'Sub' f = "new_fail"
622 store_lex "fail", $P2
623 $P3 = find_lex "choices"
629 .sub new_fail :outer(_try)
632 #print "In new_fail\n"
633 our_cc = find_lex "cc"
634 our_try = find_lex "try"
635 $P2 = find_lex "choices"
640 .sub _fail :outer(main)
641 print "Program failed\n"
647 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 5' );
648 # FIXME - we need to detect the destruction of the P registers
649 # associated with the Contexts for the calls of xyzzy and plugh.
650 # Otherwise, this test is just a repeat of others
675 .const 'Sub' bar_sub = "bar"
676 $P1 = newclosure bar_sub
680 .sub bar :anon :outer(foo)
693 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 6' );
694 # Leo's version of xyzzy original by particle, p5 by chip #'
730 .const 'Sub' closure = 'bar'
731 $P2 = newclosure closure
735 .sub bar :anon :outer(foo)
753 pir_output_is( <<'CODE', <<'OUTPUT', 'closure 7 - evaled' );
790 .sub bar :anon :outer(foo)
800 compiler = compreg "PIR"
802 $P2 = $P1[0] # first sub of eval
816 pir_error_output_like( <<'CODE', <<'OUT', 'closure 8' );
818 # p6 example from pmichaud
819 # { my $x = 5; { print $x; my $x = 4; print $x; } }
821 ## According to S04 this is an error
830 .sub anon_1 :anon :outer(main)
843 pir_output_is( <<'CODE', <<'OUTPUT', 'get undefined lexical' );
848 .sub foo :outer('main')
852 .sub bar :outer('foo')
854 $P2 = find_lex 'no_such'
856 print "Undefined name not NULL\n"
865 pir_output_is( <<'CODE', <<'OUTPUT', 'find_name on lexicals' );
882 pir_output_is( <<'CODE', <<'OUTPUT', 'multiple names' );
904 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 1' );
909 .sub '&main' :main :anon
915 print sx # no find_lex needed - 'sx' is defined here
927 .sub '&f' :outer('&main')
928 $P0 = find_lex '$x' # find_lex needed
937 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 2' );
943 .sub '&main' :main :anon
962 .sub '&f' :outer('&main')
967 .sub '&g' :outer('&main') # :outer not needed - no find_lex
977 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 3 - autoclose' );
979 # sub g ($y) { $x + $y }; g($x);
990 .sub '&g' :outer('&f')
999 .sub '&main' :main :anon
1014 pir_error_output_like( <<'CODE', <<'OUTPUT', 'package-scoped closure 4 - autoclose' );
1016 # sub g () { print $x };
1024 .sub '&g' :outer('&f')
1030 .sub '&main' :main :anon
1038 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 5 - autoclose' );
1040 # sub g () { print "$x\n" };
1049 .sub '&g' :outer('&f')
1056 .sub '&main' :main :anon
1064 pir_output_is( <<'CODE', <<'OUTPUT', 'package-scoped closure 6 - autoclose' );
1066 # sub g () { print "$x\n" };
1076 .sub '&g' :outer('&f')
1083 .sub '&main' :main :anon
1092 pir_output_is( <<'CODE', <<'OUTPUT', 'find_lex: (Perl6 OUTER::)', todo => 'not yet implemented' );
1098 .sub 'get_outer' :outer('main')
1100 $P0 = find_lex '$x', 1
1107 pir_output_is( <<'CODE', <<'OUTPUT', 'nested scopes' );
1111 # The following PIR should be like:
1121 # create some closures, outer scope
1131 print "Sub $sub_num was called $not_shared times. Any sub was called $shared times.\n";
1139 foreach ( @closures ) {
1148 .sub test_closures :main
1150 .lex '@closures', $P0
1151 $P0 = new 'ResizablePMCArray'
1153 # create some closures, outer scope
1156 # and call them in turn.
1159 if $I0 >= 4 goto DONE_LOOP0
1162 if $I1 >= 3 goto DONE_LOOP1
1174 # Return n closures, each with lexical references to "$n" and "$sub_num".
1175 .sub 'outer_scope' :outer('test_closures')
1183 if $I3 > 3 goto DONE
1192 .sub 'inner_scope' :outer('outer_scope')
1195 .lex '$sub_num', $P0
1199 .lex '$not_shared', $P1
1203 find_lex $P2, '@closures'
1204 .const 'Sub' $P3 = 'anonymous'
1211 .sub 'anonymous' :outer('inner_scope')
1213 find_lex $P0, '$sub_num'
1214 find_lex $P1, '$not_shared'
1215 find_lex $P2, '$shared'
1219 print " was called "
1221 print " times. Any sub was called "
1233 Sub 1 was called 1 times. Any sub was called 1 times.
1234 Sub 2 was called 1 times. Any sub was called 2 times.
1235 Sub 3 was called 1 times. Any sub was called 3 times.
1236 Sub 1 was called 2 times. Any sub was called 4 times.
1237 Sub 2 was called 2 times. Any sub was called 5 times.
1238 Sub 3 was called 2 times. Any sub was called 6 times.
1239 Sub 1 was called 3 times. Any sub was called 7 times.
1240 Sub 2 was called 3 times. Any sub was called 8 times.
1241 Sub 3 was called 3 times. Any sub was called 9 times.
1242 Sub 1 was called 4 times. Any sub was called 10 times.
1243 Sub 2 was called 4 times. Any sub was called 11 times.
1244 Sub 3 was called 4 times. Any sub was called 12 times.
1247 pir_output_is( <<'CODE', <<'OUTPUT', 'Double-inner scope called from closure' );
1254 .sub 'foo' :outer('main')
1259 $P0 = get_global 'bar'
1260 bar = newclosure $P0
1264 .sub 'bar' :outer('foo')
1267 .const 'Sub' $P0 = 'bar_inner'
1276 .sub 'bar_inner' :outer('bar')
1288 pir_output_is( <<'CODE', <<'OUTPUT', "Patrick's request" );
1295 .sub 'foo' :subid('foo')
1303 .sub 'inner' :outer('foo')
1321 pir_output_is( <<'CODE', <<'OUTPUT', "Bob's recursion bug");
1327 .param int recursive_p
1328 unless recursive_p goto do_lex
1329 print "rpwi: recursive case\n"
1332 .lex "(SAVED *SHARP-EQUAL-ALIST*)", $P40
1333 $P40 = new 'Integer'
1335 .const 'Sub' $P80 = "(:INTERNAL rpwi 0)"
1336 newclosure $P81, $P80
1337 ## $P81 = clone $P80
1339 print "rpwi: lex case\n"
1344 .sub "(:INTERNAL rpwi 0)" :anon :outer('rpwi')
1345 print "[restoring *SHARP-EQUAL-ALIST*]\n"
1346 find_lex $P40, "(SAVED *SHARP-EQUAL-ALIST*)"
1353 rpwi: recursive case
1354 [restoring *SHARP-EQUAL-ALIST*]
1358 pir_output_is( <<'CODE', <<'OUTPUT', "Jonathan's recursive case" );
1360 $P0 = new 'ResizablePMCArray'
1362 $P1 = new 'ResizablePMCArray'
1363 $P2 = new 'ResizablePMCArray'
1367 $P3 = new 'ResizablePMCArray'
1374 'dump_thing'($P0, '# ')
1380 .lex '$thing', thing
1381 .lex '$prefix', prefix
1383 $P0 = get_hll_global 'anon_1'
1384 $P1 = newclosure $P0
1387 $P2 = find_lex '$thing'
1388 $I0 = isa $P2, 'ResizablePMCArray'
1389 unless $I0 goto not_ResizablePMCArray
1391 $P3 = find_lex '$prefix'
1394 $P4 = get_hll_global 'anon_2'
1395 $P5 = newclosure $P4
1396 $P6 = find_lex '$thing'
1398 $P7 = find_lex '$prefix'
1403 not_ResizablePMCArray:
1404 $P8 = find_lex '$prefix'
1406 $P9 = find_lex '$thing'
1412 .sub 'anon_1' :outer('dump_thing')
1414 .lex '$subthing', subthing
1415 $P0 = find_lex '$subthing'
1416 $P1 = find_lex '$prefix'
1418 $P2 = concat $P1, ' '
1419 'dump_thing'($P0, $P2)
1422 .sub 'anon_2' :outer('dump_thing')
1425 $P0 = find_lex '$recur'
1433 .local pmc result, it
1434 result = new 'ResizablePMCArray'
1437 unless it goto loop_end
1463 pir_output_is( <<'CODE', <<'OUTPUT', 'TT #536: lexical sub lookup' );
1465 .const 'Sub' $P0 = 'lexfoo'
1477 say ' - looking up lexical sub'
1484 say ' - looked up global sub, not lexical'
1487 ok 1 - looking up lexical sub
1488 ok 2 - looking up lexical sub
1491 pir_output_is( <<'CODE', <<'OUTPUT', 'find_dynamic_lex basic' );
1496 $P1 = find_dynamic_lex '$*VAR'
1497 if null $P1 goto p1_null
1504 $P1 = find_dynamic_lex '$*VAR'
1512 pir_output_is( <<'CODE', <<'OUTPUT', "find_dynamic_lex doesn't search outer" );
1525 .sub 'foo' :outer('main')
1526 $P1 = find_dynamic_lex '$*VAR'
1528 $P1 = find_lex '$*VAR'
1537 pir_output_is( <<'CODE', <<'OUTPUT', 'find_dynamic_lex two levels deep' );
1549 $P1 = find_dynamic_lex '$*VAR'
1556 pir_error_output_like( <<'CODE', <<'OUTPUT', '.lex should not accept $S#');
1562 /error.*Cannot use S register with \.lex/
1565 pir_error_output_like( <<'CODE', <<'OUTPUT', '.lex should not accept $I#');
1571 /error.*Cannot use I register with \.lex/
1574 pir_error_output_like( <<'CODE', <<'OUTPUT', '.lex should not accept $N#');
1580 /error.*Cannot use N register with \.lex/
1583 pir_error_output_like( <<'CODE', <<'OUTPUT', 'store_lex should not accept $S#');
1586 store_lex '$var', $S0
1592 pir_error_output_like( <<'CODE', <<'OUTPUT', 'store_lex should not accept $I#');
1595 store_lex '$var', $I0
1601 pir_error_output_like( <<'CODE', <<'OUTPUT', 'store_lex should not accept $N#');
1604 store_lex '$pi', $N0
1612 # cperl-indent-level: 4
1615 # vim: expandtab shiftwidth=4: