2 # Copyright (C) 2001-2008, Parrot Foundation.
7 use lib qw( . lib ../lib ../../lib );
10 use Parrot::Test::Util 'create_tempfile';
12 use Parrot::Test tests => 48;
16 t/pmc/mmd.t - Multi-Method Dispatch
24 Tests the multi-method dispatch.
28 pir_output_is( <<'CODE', <<'OUTPUT', 'Integer_divide_Integer 10 / 3 = 1003', todo => 'TT #452' );
32 divide = get_global "Integer_divide_Integer"
33 add_multi "divide", "Integer,Integer,Integer", divide
45 .sub Integer_divide_Integer
51 $I2 = $I0/$I1 # don't call divide Integer/Integer here
53 lhs += 1000 # prove that this function has been called
60 pir_output_is( <<'CODE', <<'OUTPUT', "1+1=3", todo => 'TT #452' );
64 add = get_global "add"
65 add_multi "add", "Integer,Integer,Integer", add
92 pir_output_is( <<'CODE', <<'OUTPUT', "PASM divide - override builtin 10 / 3 = 42", todo => 'TT #452' );
96 divide = get_global "Integer_divide_Integer"
97 add_multi "divide", "Integer,Integer,Integer", divide
100 $P1 = new ['Integer']
101 $P2 = new ['Integer']
109 .sub Integer_divide_Integer
120 pir_output_is( <<'CODE', <<'OUTPUT', "INTVAL return numeq", todo => 'TT #452' );
124 comp = get_global "Float_cmp_Integer"
125 add_multi "cmp", "Float,Integer", comp
128 $P2 = new ['Integer']
131 $I0 = cmp $P1, $P2 # XXX cmp calls cmp_num
136 .sub Float_cmp_Integer
147 pir_output_is( <<'CODE', <<'OUTPUT', "find_multi" );
151 comp = get_global "Float_cmp_Integer"
152 add_multi "cmp_num", "Float,Integer", comp
153 $P0 = find_multi "cmp_num", "Float,Integer"
156 ne_addr $P0, comp, nok
163 .sub Float_cmp_Integer
175 pir_output_is( <<'CODE', <<'OUTPUT', "find_multi - invoke it" );
179 comp = get_global "Float_cmp_Integer"
180 add_multi "cmp_num", "Float,Integer", comp
181 $P0 = find_multi "cmp_num", "Float,Integer"
184 ne_addr $P0, comp, nok
187 $P2 = new ['Integer']
197 .sub Float_cmp_Integer
210 my ($TEMP, $temp_pir) = create_tempfile( SUFFIX => '.pir', UNLINK => 1 );
213 .sub Integer_divide_Integer
223 pir_output_is( <<"CODE", <<'OUTPUT', "PASM MMD divide - loaded sub", todo => 'TT #452' );
226 load_bytecode "$temp_pir"
227 divide = get_global "Integer_divide_Integer"
228 add_multi "divide", "Integer,Integer,Integer", divide
230 \$P0 = new ['Integer']
231 \$P1 = new ['Integer']
232 \$P2 = new ['Integer']
242 pasm_output_is( <<'CODE', <<'OUTPUT', "PASM INTVAL - new result", todo => 'TT #452' );
243 .include "datatypes.pasm"
244 get_global P10, "Integer_bxor_Intval"
245 add_multi "bitwise_xor_int", "Integer,INTVAL,PMC", P10
253 .pcc_sub Integer_bxor_Intval:
254 get_params "0,0,0", P5, I5, P6
267 pasm_output_is( <<'CODE', <<'OUTPUT', "PASM INTVAL - existing result", todo => 'TT #452' );
268 .include "datatypes.pasm"
269 get_global P10, "Integer_bxor_Intval"
270 add_multi "bitwise_xor_int", "Integer,INTVAL,PMC", P10
279 .pcc_sub Integer_bxor_Intval:
280 get_params "0,0,0", P5, I5, P6
292 pasm_output_is( <<'CODE', <<'OUTPUT', "PASM INTVAL - mixed", todo => 'TT #452' );
293 .include "datatypes.pasm"
294 get_global P10, "Integer_bxor_Intval"
295 add_multi "bitwise_xor_int", "Integer,INTVAL,PMC", P10
307 .pcc_sub Integer_bxor_Intval:
308 get_params "0,0,0", P5, I5, P6
324 pir_output_is( <<'CODE', <<'OUT', "first dynamic MMD call" );
327 .local pmc F, B, f, b, m, s
332 # create a multi the hard way
334 ## s = get_global "Foo", "foo"
336 ## s = get_global "Bar", "foo"
338 ## set_global "foo", m
339 print "calling foo(f, b)\n"
341 print "calling foo(b, f)\n"
345 .sub foo :multi(Foo, Bar)
351 .sub foo :multi(Bar, Foo)
363 pir_output_is( <<'CODE', <<'OUT', "MMD second arg int/float dispatch" );
364 .sub foo :multi(_, Integer)
367 print "(_, Int) method: "
373 .sub foo :multi(_, Float)
376 print "(_, Float) method: "
386 $P1 = new ['Integer']
391 (_, Float) method: 1, 9.5
392 (_, Int) method: 1, 3
395 pir_error_output_like( <<'CODE', <<'OUT', "MMD single method, dispatch failure" );
396 ## Compare this to the previous example.
397 .sub foo :multi(_, Float)
400 print "(_, Float) method: "
410 $P1 = new ['Integer']
415 /\A\(_, Float\) method: 1, 9\.5
416 No applicable methods/
419 pir_output_is( <<'CODE', <<'OUT', "MMD on argument count" );
422 p("-twice", "ok 2\n")
425 .sub p :multi(string)
430 .sub p :multi(string, string)
433 if opt != '-twice' goto no_twice
446 pir_output_is( <<'CODE', <<'OUT', "MMD on native types" );
452 .sub p :multi(string)
467 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types' );
474 pstring = subclass 'String', 'PString'
475 $P1 = new ['PString']
479 $P0 = subclass 'PString', "Xstring"
480 $P0 = new ['Xstring']
482 $P1 = subclass 'String', "Ystring"
483 $P1 = new ['Ystring']
489 .sub p :multi(PString)
495 .sub p :multi(String)
507 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types quoted' );
514 pstring = subclass 'String', 'PString'
515 $P1 = new ['PString']
519 $P0 = subclass "PString", "Xstring"
520 $P0 = new ['Xstring']
522 $P1 = subclass "String", "Ystring"
523 $P1 = new ['Ystring']
529 .sub p :multi("String")
535 .sub p :multi("PString")
547 pir_error_output_like( <<'CODE', <<'OUT', 'MMD on PMC types, invalid' );
554 pstring = subclass 'String', 'PString'
555 $P1 = new ['PString']
558 $P0 = subclass "PString", "Xstring"
559 $P0 = new ['Xstring']
561 $P1 = subclass "String", "Ystring"
562 $P1 = new ['Ystring']
566 $P0 = new ['Integer']
570 .sub p :multi(String)
576 .sub p :multi(PString)
586 No applicable methods/
589 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types 3' );
596 pstring = subclass 'String', 'PString'
597 $P1 = new ['PString']
601 $P0 = subclass "PString", "Xstring"
602 $P0 = new ['Xstring']
604 $P1 = subclass "String", "Ystring"
605 $P1 = new ['Ystring']
611 pint = subclass 'Integer', 'PInt'
617 .sub p :multi(String)
623 .sub p :multi(PString)
629 .sub p :multi(Integer)
644 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types, global namespace' );
651 pstring = subclass 'String', 'PString'
652 $P1 = new ['PString']
656 $P0 = subclass "PString", "Xstring"
657 $P0 = new ['Xstring']
659 $P1 = subclass "String", "Ystring"
660 $P1 = new ['Ystring']
666 .sub p :multi(String)
672 .sub p :multi(PString)
684 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types, package namespace' );
693 pstring = subclass 'String', 'PString'
694 $P1 = new ['PString']
698 $P0 = subclass "PString", "Xstring"
699 $P0 = new ['Xstring']
701 $P1 = subclass "String", "Ystring"
702 $P1 = new ['Ystring']
708 .sub p :multi(String)
714 .sub p :multi(PString)
726 pir_output_is( <<'CODE', <<'OUT', "MMD on PMC types - Any", todo => 'RT #41374' );
731 $P1 = new ['PerlInt']
735 $P0 = new ['PerlInt']
738 $P0 = new ['PerlInt']
745 .sub p :multi(String)
751 .sub p :multi(PString)
778 pir_output_is( <<'CODE', <<'OUTPUT', "add as function - Int, Float" );
780 .local pmc d, l, r, a
786 a = get_root_global ["MULTI"], "add"
796 pir_output_is( <<'CODE', <<'OUTPUT', "add as method" );
812 pir_output_is( <<'CODE', <<'OUTPUT', "add as method - inherited", todo => 'RT #41374' );
816 pint = subclass 'Integer', 'PInt'
829 pir_output_is( <<'CODE', <<'OUTPUT', "add as method - Int, Float" );
845 pir_output_is( <<'CODE', <<'OUTPUT', "bound add method" );
847 .local pmc d, l, r, m
853 m = get_global ['scalar'], "add"
859 m = get_global ['Integer'], "add"
870 pir_output_is( <<'CODE', <<'OUTPUT', "Integer subclasses" );
872 .local pmc d, l, r, cl
873 cl = subclass "Integer", "AInt"
883 # dispatches to Parrot_Integer_add_Integer
899 pir_output_is( <<'CODE', <<'OUTPUT', "Integer subclasses, add" );
901 $P0 = subclass "Integer", "AInt"
903 $P1 = new ['Integer']
912 .sub add :multi(AInt, Integer, PMC)
928 ($TEMP, $temp_pir) = create_tempfile( SUFFIX => '.pir', UNLINK => 1 );
932 .sub add :multi(AInt, Integer, PMC)
946 pir_output_is( <<"CODE", <<'OUTPUT', "override builtin add" );
948 load_bytecode "$temp_pir"
949 \$P0 = subclass "Integer", "AInt"
951 \$P1 = new ['Integer']
955 \$P2 = add \$P0, \$P1
963 pir_output_is( <<'CODE', <<'OUTPUT', "mmd bug reported by Jeff" );
966 .sub bar :method :multi(Foo, string)
971 .sub bar :method :multi(Foo, pmc)
976 .sub bar :method :multi(Foo)
1001 pir_output_is( <<'CODE', <<'OUTPUT', "use a core func for an object", todo => 'RT #59628' );
1003 .local pmc d, l, r, cl
1004 cl = newclass "AInt"
1005 addattribute cl, ".i"
1011 func = find_multi "add", "Float,Float,PMC"
1017 add_multi "add", typ, func
1029 .sub init :vtable :method
1030 $P0 = new ['Integer']
1031 setattribute self, ".i", $P0
1033 .sub set_integer_native :vtable :method
1035 $P0 = getattribute self, ".i"
1038 .sub set_number_native :vtable :method
1040 $P0 = getattribute self, ".i"
1043 .sub get_string :vtable :method
1044 $P0 = getattribute self, ".i"
1048 .sub get_number :vtable :method
1049 $P0 = getattribute self, ".i"
1059 pir_output_is( <<'CODE', <<'OUTPUT', "multisub vs find_name" );
1061 $P0 = find_name "foo"
1066 .sub foo :method :multi(string)
1070 .sub foo :method :multi(pmc)
1078 pir_output_is( <<'CODE', <<'OUTPUT', "multisub w void" );
1084 .sub foo :multi(string)
1086 print "foo string\n"
1097 pir_output_is( <<'CODE', <<'OUTPUT', "multisub w/o .HLL" );
1099 $P0 = new ['Integer']
1103 $P0 = new ['ResizablePMCArray']
1105 $P1 = new ['String']
1107 $P9 = 'foo'($P0, $P1)
1110 .sub 'foo' :multi(Integer)
1111 print "foo(Integer)\n"
1115 .sub 'foo' :multi(ResizablePMCArray, _)
1116 print "foo(ResizablePMCArray,_)\n"
1121 foo(ResizablePMCArray,_)
1124 pir_output_is( <<'CODE', <<'OUTPUT', "multisub w/ .HLL, rt #39161" );
1127 $P0 = new ['Integer']
1131 $P0 = new ['ResizablePMCArray']
1133 $P1 = new ['String']
1135 $P9 = 'foo'($P0, $P1)
1138 .sub 'foo' :multi(Integer)
1139 print "foo(Integer)\n"
1143 .sub 'foo' :multi(ResizablePMCArray, _)
1144 print "foo(ResizablePMCArray,_)\n"
1149 foo(ResizablePMCArray,_)
1152 pir_output_is( <<'CODE', <<'OUTPUT', "multisub w/ flatten" );
1153 # see also 'rt #39173
1156 int_pmc = new ['Integer']
1160 args = new ['ResizablePMCArray']
1164 .local pmc string_pmc
1165 string_pmc = new ['String']
1166 string_pmc = 'hello'
1168 args = new ['ResizablePMCArray']
1169 push args, string_pmc
1174 .sub 'foo' :multi(Integer)
1175 print "foo(Integer)\n"
1178 .sub 'foo' :multi(String)
1179 print "foo(String)\n"
1186 pir_output_is( <<'CODE', <<'OUTPUT', "keyed class name and multi" );
1189 newclass class, [ 'Some'; 'Class' ]
1192 instance = new [ 'Some'; 'Class' ]
1195 name = typeof instance
1206 pir_output_is( <<'CODE', <<'OUTPUT', "keyed class name and multi" );
1209 newclass class, [ 'Some'; 'Class' ]
1212 instance = new [ 'Some'; 'Class' ]
1218 .sub 'foo' :multi( [ 'Some'; 'Class' ])
1219 print "Called multi for class\n"
1222 .sub 'foo' :multi(_)
1223 print "Called wrong multi\n"
1226 Called multi for class
1229 pir_output_is( <<'CODE', <<'OUTPUT', "unicode sub names and multi (RT #39254)" );
1230 .sub unicode:"\u7777" :multi(string)
1235 .sub unicode:"\u7777" :multi(int)
1242 unicode:"\u7777"('what')
1243 unicode:"\u7777"(23)
1250 pir_output_is( <<'CODE', <<'OUTPUT', "autoboxing on multis" );
1251 .sub box_me_up :multi(string)
1255 .local string promoted_type
1256 promoted_type = typeof second
1257 print "BMU autobox type: "
1262 .sub box_me_up :multi()
1263 print "BMU no autobox, so sad\n"
1266 .sub box_me_up :multi(int, int)
1267 print "BMU inty, so bad\n"
1271 box_me_up( 'foo', 'bar' )
1274 BMU autobox type: String
1277 pir_output_is( <<'CODE', <<'OUTPUT', '_ matches native types' );
1280 asub = get_global 'main'
1282 foo('world', asub) # should call :multi(_, Sub)
1285 .sub foo :multi(_, Sub)
1290 say ":multi(_, Sub)"
1293 .sub foo :multi(Integer, Sub)
1298 say ":multi(int, Sub)"
1301 world :multi(_, Sub)
1304 pir_output_is( <<'CODE', <<'OUTPUT', 'type mix with _' );
1306 $P0 = new ['Integer']
1311 $P0 = new ['String']
1318 .sub 'foo' :multi(Integer)
1320 print "foo(Integer)\n"
1323 .sub 'foo' :multi(_)
1328 .sub 'foo' :multi(int)
1333 .sub 'foo' :multi(String)
1335 print "foo(String)\n"
1338 .sub 'foo' :multi(string)
1340 print "foo(string)\n"
1350 pir_output_is( <<'CODE', <<'OUTPUT', ':multi with :outer' );
1359 $P99 = "foo"($P0, $P1)
1363 $P99 = "bar"($P0, $P1)
1367 .sub "foo" :multi(_)
1374 .sub "foo" :multi(_,_)
1384 .sub "bar" :outer("main") :multi(_)
1391 .sub "bar" :outer("main") :multi(_,_)
1407 pir_output_is( <<'CODE', <<'OUTPUT', "multi-dispatch on PMCNULL" );
1413 .sub foo :multi(String)
1423 pir_output_is( <<'CODE', <<'OUTPUT', "multi-dispatch with :optional" );
1432 .sub foo :multi(string)
1434 .param int i :optional
1435 .param int have_i :opt_flag
1438 unless have_i goto done
1443 .sub foo :multi(int)
1445 .param int i :optional
1446 .param int have_i :opt_flag
1449 unless have_i goto done
1462 pir_output_is( <<'CODE', <<'OUTPUT', '.autoboxed MMD with :optional' );
1473 .sub foo :multi(String)
1475 .param pmc i :optional
1476 .param int have_i :opt_flag
1479 unless have_i goto done
1484 .sub foo :multi(Integer)
1486 .param pmc i :optional
1487 .param int have_i :opt_flag
1490 unless have_i goto done
1495 .sub foo :multi(Float)
1497 .param pmc i :optional
1498 .param int have_i :opt_flag
1501 unless have_i goto done
1517 pir_output_is( <<'CODE', <<'OUTPUT', 'more .autoboxed MMD with :optional' );
1521 foo('Goodbye', 'Ta ta', 2)
1525 foo(77.7, 88.8, 99.9)
1528 .sub foo :multi(String, String)
1531 .param pmc i :optional
1532 .param int have_i :opt_flag
1536 unless have_i goto done
1542 .sub foo :multi(Integer, Integer)
1545 .param pmc i :optional
1546 .param int have_i :opt_flag
1550 unless have_i goto done
1556 .sub foo :multi(Float, Float)
1559 .param pmc i :optional
1560 .param int have_i :opt_flag
1564 unless have_i goto done
1580 # cperl-indent-level: 4
1583 # vim: expandtab shiftwidth=4: