2 # Copyright (C) 2001-2010, Parrot Foundation.
7 use lib qw( . lib ../lib ../../lib );
10 use Parrot::Test::Util 'create_tempfile';
12 use Parrot::Test tests => 70;
17 t/pmc/sub.t - Subroutine PMCs
25 Tests the creation and invocation of C<Sub>, C<Closure> and
32 pasm_output_is( <<'CODE', <<'OUTPUT', "PASM subs - invokecc" );
33 .const 'Sub' P0 = "func"
50 .include "interpinfo.pasm"
51 interpinfo P0, .INTERPINFO_CURRENT_SUB
53 invokecc P0 # recursive invoke
65 pasm_output_is( <<'CODE', <<'OUTPUT', "Continuation" );
69 new P1, ['Continuation']
79 print "going to cont\n"
97 pasm_output_is( <<'CODE', <<'OUTPUT', "definedness of Continuation" );
98 new P1, ['Continuation']
109 print "I'm a very boring continuation"
117 pasm_output_is( <<'CODE', <<'OUTPUT', "pcc sub" );
118 get_global P0, "_the_sub"
136 pasm_output_is( <<'CODE', <<'OUTPUT', "pcc sub, tail call" );
137 get_global P0, "_the_sub"
149 get_global P0, "_next_sub"
155 print "in next sub\n"
166 my ($TEMP, $temp_pasm) = create_tempfile( SUFFIX => '.pasm', UNLINK => 1 );
174 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode call sub" );
177 load_bytecode "$temp_pasm"
179 get_global P0, "_sub1"
195 ($TEMP, $temp_pasm) = create_tempfile( SUFFIX => '.pasm', UNLINK => 1 );
204 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode call sub, ret" );
207 load_bytecode "$temp_pasm"
209 get_global P0, "_sub1"
226 ($TEMP, $temp_pasm) = create_tempfile( SUFFIX => '.pasm', UNLINK => 1 );
238 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode call different subs, ret" );
241 load_bytecode "$temp_pasm"
243 get_global P0, "_sub1"
252 get_global P0, "_sub2"
277 my (undef, $temp_pbc) = create_tempfile( SUFFIX => '.pbc', UNLINK => 1 );
279 system(".$PConfig{slash}parrot$PConfig{exe}", '-o', $temp_pbc, $temp_pasm);
281 pir_output_is( <<"CODE", <<'OUTPUT', "load_bytecode Sx" );
295 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode PBC call different subs, ret" );
298 load_bytecode "$temp_pasm"
300 get_global P0, "_sub1"
309 get_global P0, "_sub2"
334 pasm_output_is( <<'CODE', <<'OUTPUT', "equality of closures" );
336 .const 'Sub' P3 = "f1"
343 .const 'Sub' P4 = "f2"
351 .pcc_sub :outer(main) f1:
355 .pcc_sub :outer(main) f2:
363 pasm_output_is( <<'CODE', <<'OUTPUT', "equality of subs" );
364 .const 'Sub' P0 = "f1"
370 .const 'Sub' P2 = "f2"
390 pasm_output_is( <<'CODE', <<'OUT', "MAIN pragma, syntax only" );
391 .pcc_sub :main _main:
398 ($TEMP, $temp_pasm) = create_tempfile( SUFFIX => '.pasm', UNLINK => 1 );
401 .pcc_sub :load _sub1:
407 pasm_output_is( <<"CODE", <<'OUTPUT', 'load_bytecode :load' );
410 load_bytecode "$temp_pasm"
419 ($TEMP, $temp_pasm) = create_tempfile( SUFFIX => '.pasm', UNLINK => 1 );
424 .pcc_sub :load _sub1:
430 pasm_output_is( <<"CODE", <<'OUTPUT', 'load_bytecode :load second sub' );
433 load_bytecode "$temp_pasm"
442 system(".$PConfig{slash}parrot$PConfig{exe}", '-o', $temp_pbc, $temp_pasm );
444 pasm_output_is( <<"CODE", <<'OUTPUT', 'load_bytecode :load in pbc' );
447 load_bytecode "$temp_pbc"
456 ($TEMP, $temp_pasm) = create_tempfile( SUFFIX => '.pasm', UNLINK => 1 );
459 .pcc_sub :load _sub1:
468 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode autorun first" );
471 load_bytecode "$temp_pasm"
473 get_global P0, "_sub2"
485 system(".$PConfig{slash}parrot$PConfig{exe}", '-o', $temp_pbc, $temp_pasm );
487 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode autorun first in pbc" );
490 load_bytecode "$temp_pbc"
492 get_global P0, "_sub2"
504 ($TEMP, $temp_pasm) = create_tempfile( SUFFIX => '.pasm', UNLINK => 1 );
510 .pcc_sub :load _sub2:
516 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode autorun second" );
519 load_bytecode "$temp_pasm"
521 get_global P0, "_sub1"
533 system(".$PConfig{slash}parrot$PConfig{exe}", '-o', $temp_pbc, $temp_pasm );
535 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode autorun second in pbc" );
538 load_bytecode "$temp_pbc"
540 get_global P0, "_sub1"
552 ($TEMP, $temp_pasm) = create_tempfile( SUFFIX => '.pasm', UNLINK => 1 );
555 .pcc_sub :load _sub1:
558 .pcc_sub :load _sub2:
564 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode autorun both" );
567 load_bytecode "$temp_pasm"
569 get_global P0, "_sub1"
582 system(".$PConfig{slash}parrot$PConfig{exe}", '-o', $temp_pbc, $temp_pasm );
584 pasm_output_is( <<"CODE", <<'OUTPUT', "load_bytecode autorun both in pbc" );
587 load_bytecode "$temp_pbc"
589 get_global P0, "_sub1"
602 pasm_output_is( <<'CODE', <<'OUTPUT', ':main pragma' );
606 .pcc_sub :main _main:
613 pasm_output_is( <<'CODE', <<'OUTPUT', 'two :main pragmas' );
617 .pcc_sub :main _main:
620 .pcc_sub :main _second:
627 pasm_output_is( <<'CODE', <<'OUTPUT', ':main pragma call subs' );
634 .pcc_sub :main _main:
636 get_global P0, "_first"
638 get_global P0, "_second"
647 pir_error_output_like( <<'CODE', <<'OUTPUT', "implicit :main with wrong # args." );
653 /too few positional arguments: 1 passed, 2 \(or more\) expected/
656 pir_error_output_like( <<'CODE', <<'OUTPUT', "explicit :main with wrong # args." );
662 /too few positional arguments: 1 passed, 2 \(or more\) expected/
665 ($TEMP, $temp_pasm) = create_tempfile(UNLINK => 1);
674 pasm_output_is( <<"CODE", <<'OUTPUT', 'load_bytecode :load first sub - pir' );
677 load_bytecode "$temp_pasm"
686 ($TEMP, $temp_pasm) = create_tempfile(UNLINK => 1);
692 # :load or other pragmas are only evaluated on the first
693 # instruction of a subroutine
701 pasm_output_is( <<"CODE", <<'OUTPUT', 'load_bytecode :load second sub - pir' );
704 load_bytecode "$temp_pasm"
713 ($TEMP, my $temp_pir) = create_tempfile( SUFFIX => '.pir', UNLINK => 1 );
726 pasm_output_is( <<"CODE", <<'OUTPUT', 'load_bytecode no :load - pir' );
729 load_bytecode "$temp_pir"
737 pir_output_like( <<'CODE', '/Stringifying an Undef PMC/', 'warn on in main' );
739 .include "warnings.pasm"
740 warningson .PARROT_WARNINGS_UNDEF_FLAG
749 pir_output_is( <<'CODE', <<'OUTPUT', "warn on in sub" );
751 .include "warnings.pasm"
758 warningson .PARROT_WARNINGS_UNDEF_FLAG
764 pir_output_like( <<'CODE', <<'OUTPUT', "warn on in sub, turn off in f2" );
766 .include "warnings.pasm"
774 warningson .PARROT_WARNINGS_UNDEF_FLAG
780 warningsoff .PARROT_WARNINGS_UNDEF_FLAG
783 /Stringifying an Undef PMC
789 pasm_output_is( <<'CODE', <<'OUTPUT', "sub names" );
791 .include "interpinfo.pasm"
792 interpinfo P20, .INTERPINFO_CURRENT_SUB
795 get_global P0, "the_sub"
797 interpinfo P20, .INTERPINFO_CURRENT_SUB
802 interpinfo P20, .INTERPINFO_CURRENT_SUB
805 interpinfo P1, .INTERPINFO_CURRENT_CONT
813 pasm_output_is( <<'CODE', <<'OUTPUT', "sub names w MAIN" );
818 .include "interpinfo.pasm"
819 interpinfo P20, .INTERPINFO_CURRENT_SUB
822 get_global P0, "the_sub"
824 interpinfo P20, .INTERPINFO_CURRENT_SUB
829 interpinfo P20, .INTERPINFO_CURRENT_SUB
832 interpinfo P1, .INTERPINFO_CURRENT_CONT
840 pir_output_is( <<'CODE', <<'OUTPUT', "caller introspection via interp" );
842 .include "interpinfo.pasm"
843 # this test will fail when run with -Oc
844 # as the call chain is cut down with tail calls
847 $P0 = get_hll_global ["Bar"], "foo"
853 $P0 = get_hll_global ["Bar"], "bar"
872 $P0 = $P1["sub"; $I0]
897 pir_output_is( <<'CODE', <<'OUT', ':immediate :postcomp' );
898 .sub optc :immediate :postcomp
910 pir_output_like( <<'CODE', <<'OUTPUT', ':anon' );
914 $P0 = get_global "new"
918 $P0 = get_global "foo"
919 unless null $P0 goto foo
940 ($TEMP, my $l1_pir) = create_tempfile( SUFFIX => '.pir', UNLINK => 1 );
941 (my $l1_pbc = $l1_pir) =~ s/\.pir/.pbc/;
954 ($TEMP, my $l2_pir) = create_tempfile( SUFFIX => '.pir', UNLINK => 1 );
955 (my $l2_pbc = $l2_pir) =~ s/\.pir/.pbc/;
968 system(".$PConfig{slash}parrot$PConfig{exe}", '-o', $l1_pbc, $l1_pir);
969 system(".$PConfig{slash}parrot$PConfig{exe}", '-o', $l2_pbc, $l2_pir);
971 pir_output_is( <<"CODE", <<'OUTPUT', 'multiple :load' );
974 load_bytecode "$l1_pir"
975 load_bytecode "$l2_pir"
977 load_bytecode "$l1_pbc" # these have to be ignored
978 load_bytecode "$l2_pbc"
991 unlink( $l1_pbc, $l2_pbc );
993 pir_output_is( <<'CODE', <<'OUTPUT', "immediate code as const" );
994 .sub make_phi :immediate :anon
1004 .const 'Sub' phi = "make_phi"
1012 pir_output_is( <<'CODE', <<'OUTPUT', "immediate code as const - obj" );
1013 .sub make_obj :immediate :anon
1016 addattribute cl, 'x'
1018 $P0 = new ['String']
1020 setattribute o, 'x', $P0
1025 .const 'Sub' o = "make_obj"
1026 $P0 = getattribute o, 'x'
1034 pir_output_is( <<'CODE', <<'OUTPUT', "__get_regs_used 1" );
1037 .include "interpinfo.pasm"
1038 m = interpinfo .INTERPINFO_CURRENT_SUB
1039 $I0 = m."__get_regs_used"('N')
1041 $I0 = m."__get_regs_used"('I')
1043 $I0 = m."__get_regs_used"('S')
1045 $I0 = m."__get_regs_used"('P')
1054 pir_output_is( <<'CODE', <<'OUTPUT', "__get_regs_used 2" );
1060 .include "interpinfo.pasm"
1061 m = interpinfo .INTERPINFO_CURRENT_SUB
1067 $I0 = m."__get_regs_used"('N')
1069 $I0 = m."__get_regs_used"('I')
1071 $I0 = m."__get_regs_used"('S')
1073 $I0 = m."__get_regs_used"('P')
1083 pir_output_like( <<"CODE", <<'OUTPUT', 'warn on in main' );
1085 .include "warnings.pasm"
1086 warningson .PARROT_WARNINGS_UNDEF_FLAG
1090 \$P0 = new ['Undef']
1094 /Stringifying an Undef PMC/
1097 pir_output_is( <<"CODE", <<'OUTPUT', 'warn on in sub' );
1099 .include "warnings.pasm"
1101 \$P0 = new ['Undef']
1106 warningson .PARROT_WARNINGS_UNDEF_FLAG
1112 pir_output_like( <<"CODE", <<'OUTPUT', 'warn on in sub, turn off in f2' );
1114 .include "warnings.pasm"
1116 \$P0 = new ['Undef']
1122 warningson .PARROT_WARNINGS_UNDEF_FLAG
1124 \$P0 = new ['Undef']
1128 warningsoff .PARROT_WARNINGS_UNDEF_FLAG
1131 /Stringifying an Undef PMC/
1134 pir_output_is( <<'CODE', <<'OUTPUT', ':postcomp' );
1159 pir_output_is( <<'CODE', <<'OUTPUT', 'unicode sub names, compilation' );
1160 .sub unicode:"\u7777"
1167 pir_output_is( <<'CODE', <<'OUTPUT', 'unicode sub names, invocation' );
1168 .sub unicode:"\u7777"
1179 pir_output_is( <<'CODE', <<'OUTPUT', 'unicode sub names, dynamic' );
1180 .sub unicode:"\u7777"
1185 $P1 = find_name unicode:"\u7777"
1192 pir_output_is( <<'CODE', <<'OUTPUT', 'unicode sub names' );
1193 .sub unicode:"\u7777"
1198 # unicode:"\u7777" ends up as a string nicode:"\u7777
1199 # (or it did, in r12860)
1200 $P1 = find_name 'nicode:"\u7777'
1201 unless null $P1 goto bad
1209 pir_output_is( <<'CODE', <<'OUTPUT', 'unicode sub constant' );
1211 .const 'Sub' s = unicode:"\u7777"
1215 .sub unicode:"\u7777"
1222 pir_output_is( <<'CODE', <<'OUTPUT', 'literal \u in sub name (not unicode)' );
1230 pir_error_output_like( <<'CODE', qr/Null PMC access in invoke()/, 'invoking null pmc' );
1237 pir_output_is( <<'CODE', <<'OUTPUT', ":init" );
1250 pir_output_is( <<'CODE', <<'OUTPUT', 'assign' );
1252 $P0 = get_global 'ok'
1267 pir_output_is( <<'CODE', <<'OUTPUT', 'assign w/:outer' );
1269 $P0 = get_global 'ok'
1277 .sub ok :outer('main')
1284 pir_output_is( <<'CODE', <<'OUTPUT', 'get_namespace()' );
1286 $P0 = get_global 'main'
1287 $P0 = $P0.'get_namespace'()
1288 $P0 = $P0.'get_name'()
1292 $P0 = get_global ['Foo'; 'Bar'], 'foo'
1293 $P0 = $P0.'get_namespace'()
1294 $P0 = $P0.'get_name'()
1299 .namespace ['Foo'; 'Bar']
1308 pir_output_is( <<'CODE', <<'OUTPUT', 'arity()' );
1310 $P0 = get_global 'none'
1314 $P0 = get_global 'one'
1318 $P0 = get_global 'four'
1322 $P0 = get_global 'all_slurpy'
1326 $P0 = get_global 'some_optional'
1330 $P0 = get_global 'some_named'
1334 $P0 = get_global 'allsorts'
1354 .param pmc s :slurpy
1359 .param int b :optional
1360 .param int bo :opt_flag
1366 .param int a :named('a')
1367 .param int c :named('c')
1372 .param int b :optional
1373 .param int bo :opt_flag
1374 .param pmc s :slurpy
1375 .param int a :named('a')
1387 pir_output_is( <<'CODE', <<'OUTPUT', 'set_outer' );
1389 $P0 = get_hll_global "example_outer"
1390 $P1 = get_hll_global "example_inner"
1391 $P1.'set_outer'($P0)
1398 $P0 = new ['String']
1399 $P0 = 'I can has outer?'
1403 $P0 = find_lex "Foo"
1410 pir_output_is( <<'CODE', <<'OUTPUT', 'set_outer and eval' );
1415 .sub 'example_outer'
1417 $P0 = new ['String']
1418 $P0 = 'I can has outer from eval?'
1422 $P0 = find_lex "Foo"
1429 $P3 = new 'ParrotInterpreter'
1432 $P2.'set_outer'($P3)
1437 I can has outer from eval?
1440 $ENV{TEST_PROG_ARGS} ||= '';
1441 @todo = $ENV{TEST_PROG_ARGS} =~ /--run-pbc/
1442 ? ( todo => 'lexicals not thawed properly from PBC, TT #1171' )
1444 pir_output_is( <<'CODE', <<'OUTPUT', ':outer with identical sub names', @todo );
1446 $P0 = get_hll_global ['ABC'], 'outer'
1449 $P0 = get_hll_global ['DEF'], 'outer'
1454 .sub 'outer' :subid('abc_outer')
1461 .sub 'inner' :outer('abc_outer')
1463 $P0 = find_lex '$abc'
1468 .sub 'outer' :subid('def_outer')
1475 .sub 'inner' :outer('def_outer')
1477 $P0 = find_lex '$def'
1489 pir_output_is( <<'CODE', <<'OUTPUT', ':subid and identical string constants' );
1501 .sub 'bar' :subid("abc")
1511 pir_output_is( <<'CODE', <<'OUTPUT', 'copy sub to self' );
1521 pir_output_is( <<'CODE', <<'OUTPUT', 'get_string null check' );
1531 pir_output_is( <<'CODE', <<'OUTPUT', 'use of :init sub pointed to by a :outer in compreg' );
1543 .sub 'foo' :outer('BEGIN')
1563 pir_output_is( <<'CODE', <<'OUTPUT', '.get_subid' );
1565 .const 'Sub' foo = 'foo'
1566 $S0 = foo.'get_subid'()
1569 $P0 = get_global 'bar'
1570 $S0 = $P0.'get_subid'()
1573 $P0 = get_global 'baz'
1574 $S0 = $P0.'get_subid'()
1578 .sub '' :subid('foo')
1586 .sub 'baz' :subid('bazsubid')
1595 pir_output_is( <<'CODE', <<'OUTPUT', 'Thaw PIR subclass', todo => 'See TT #132' );
1598 $P0 = get_class 'Sub'
1599 $P1 = subclass $P0, 'myProc'
1602 pirC = compreg 'PIR'
1613 compiled = pirC(code)
1614 compiled = compiled[0] # just want the first executable sub here.
1620 assign sub, compiled
1637 pir_output_is( <<'CODE', <<'OUTPUT', 'init_pmc' );
1639 .local pmc init, s, regs, arg_info
1642 init['start_offs'] = 42
1643 init['end_offs'] = 115200
1645 regs = new ['FixedIntegerArray']
1651 init['n_regs_used'] = regs
1653 arg_info = new ['Hash']
1654 arg_info['pos_required'] = 1
1655 arg_info['pos_optional'] = 1
1656 arg_info['pos_slurpy'] = 2
1657 arg_info['named_required'] = 3
1658 arg_info['named_optional'] = 5
1659 arg_info['named_slurpy'] = 8
1660 init['arg_info'] = arg_info
1662 s = new ['Sub'], init
1664 $I0 = s.'start_offs'()
1669 $I0 = s.'end_offs'()
1673 $I0 = s.'__get_regs_used'('I')
1677 $I0 = s.'__get_regs_used'('N')
1681 $I0 = s.'__get_regs_used'('S')
1685 $I0 = s.'__get_regs_used'('P')
1690 $P0 = inspect s, 'pos_required'
1691 print 'pos_required '
1694 $P0 = inspect s, 'pos_optional'
1695 print 'pos_optional '
1698 $P0 = inspect s, 'pos_slurpy'
1702 $P0 = inspect s, 'named_required'
1703 print 'named_required '
1706 $P0 = inspect s, 'named_optional'
1707 print 'named_optional '
1710 $P0 = inspect s, 'named_slurpy'
1711 print 'named_slurpy '
1714 # We need more tests for other fields. And more accessors obviously.
1731 pir_output_is( <<'CODE', <<'OUT', 'interface' );
1733 .const 'Sub' $P0 = "main"
1735 $I0 = does $P0, 'scalar'
1736 say $I0 # Sub does not scalar
1737 $I0 = does $P0, 'invokable'
1738 say $I0 # Sub does invokable
1739 $I0 = does $P0, 'no_interface'
1740 say $I0 # Sub does not no_interface
1751 # cperl-indent-level: 4
1754 # vim: expandtab shiftwidth=4: