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 => 47;
16 t/pmc/mmd.t - Multi-Method Dispatch
20 % prove t/pmc/multidispatch.t
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 pir_output_is( <<'CODE', <<'OUT', "first dynamic MMD call" );
245 .local pmc F, B, f, b, m, s
250 # create a multi the hard way
252 ## s = get_global "Foo", "foo"
254 ## s = get_global "Bar", "foo"
256 ## set_global "foo", m
257 print "calling foo(f, b)\n"
259 print "calling foo(b, f)\n"
263 .sub foo :multi(Foo, Bar)
269 .sub foo :multi(Bar, Foo)
281 pir_output_is( <<'CODE', <<'OUT', "MMD second arg int/float dispatch" );
282 .sub foo :multi(_, Integer)
285 print "(_, Int) method: "
291 .sub foo :multi(_, Float)
294 print "(_, Float) method: "
304 $P1 = new ['Integer']
309 (_, Float) method: 1, 9.5
310 (_, Int) method: 1, 3
313 pir_error_output_like( <<'CODE', <<'OUT', "MMD single method, dispatch failure" );
314 ## Compare this to the previous example.
315 .sub foo :multi(_, Float)
318 print "(_, Float) method: "
328 $P1 = new ['Integer']
333 /\A\(_, Float\) method: 1, 9\.5
334 No applicable candidates/
337 pir_output_is( <<'CODE', <<'OUT', "MMD on argument count" );
340 p("-twice", "ok 2\n")
343 .sub p :multi(string)
348 .sub p :multi(string, string)
351 if opt != '-twice' goto no_twice
364 pir_output_is( <<'CODE', <<'OUT', "MMD on native types" );
370 .sub p :multi(string)
385 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types' );
392 pstring = subclass 'String', 'PString'
393 $P1 = new ['PString']
397 $P0 = subclass 'PString', "Xstring"
398 $P0 = new ['Xstring']
400 $P1 = subclass 'String', "Ystring"
401 $P1 = new ['Ystring']
407 .sub p :multi(PString)
413 .sub p :multi(String)
425 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types quoted' );
432 pstring = subclass 'String', 'PString'
433 $P1 = new ['PString']
437 $P0 = subclass "PString", "Xstring"
438 $P0 = new ['Xstring']
440 $P1 = subclass "String", "Ystring"
441 $P1 = new ['Ystring']
447 .sub p :multi("String")
453 .sub p :multi("PString")
465 pir_error_output_like( <<'CODE', <<'OUT', 'MMD on PMC types, invalid' );
472 pstring = subclass 'String', 'PString'
473 $P1 = new ['PString']
476 $P0 = subclass "PString", "Xstring"
477 $P0 = new ['Xstring']
479 $P1 = subclass "String", "Ystring"
480 $P1 = new ['Ystring']
484 $P0 = new ['Integer']
488 .sub p :multi(String)
494 .sub p :multi(PString)
504 No applicable candidates/
507 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types 3' );
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 pint = subclass 'Integer', 'PInt'
535 .sub p :multi(String)
541 .sub p :multi(PString)
547 .sub p :multi(Integer)
562 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types, global namespace' );
569 pstring = subclass 'String', 'PString'
570 $P1 = new ['PString']
574 $P0 = subclass "PString", "Xstring"
575 $P0 = new ['Xstring']
577 $P1 = subclass "String", "Ystring"
578 $P1 = new ['Ystring']
584 .sub p :multi(String)
590 .sub p :multi(PString)
602 pir_output_is( <<'CODE', <<'OUT', 'MMD on PMC types, package namespace' );
611 pstring = subclass 'String', 'PString'
612 $P1 = new ['PString']
616 $P0 = subclass "PString", "Xstring"
617 $P0 = new ['Xstring']
619 $P1 = subclass "String", "Ystring"
620 $P1 = new ['Ystring']
626 .sub p :multi(String)
632 .sub p :multi(PString)
644 pir_output_is( <<'CODE', <<'OUT', "MMD on PMC types - Any", todo => 'TT #1320' );
649 $P1 = new ['PerlInt']
653 $P0 = new ['PerlInt']
656 $P0 = new ['PerlInt']
663 .sub p :multi(String)
669 .sub p :multi(PString)
696 pir_output_is( <<'CODE', <<'OUTPUT', "add as function - Int, Float" );
698 .local pmc d, l, r, a
704 a = get_root_global ["MULTI"], "add"
714 pir_output_is( <<'CODE', <<'OUTPUT', "add as method" );
730 pir_output_is( <<'CODE', <<'OUTPUT', "add as method - inherited", todo => 'TT #1320' );
734 pint = subclass 'Integer', 'PInt'
747 pir_output_is( <<'CODE', <<'OUTPUT', "add as method - Int, Float" );
763 pir_output_is( <<'CODE', <<'OUTPUT', "bound add method" );
765 .local pmc d, l, r, m
771 m = get_global ['scalar'], "add"
777 m = get_global ['Integer'], "add"
788 pir_output_is( <<'CODE', <<'OUTPUT', "Integer subclasses" );
790 .local pmc d, l, r, cl
791 cl = subclass "Integer", "AInt"
801 # dispatches to Parrot_Integer_add_Integer
817 pir_output_is( <<'CODE', <<'OUTPUT', "Integer subclasses, add" );
819 $P0 = subclass "Integer", "AInt"
821 $P1 = new ['Integer']
830 .sub add :multi(AInt, Integer, PMC)
846 ($TEMP, $temp_pir) = create_tempfile( SUFFIX => '.pir', UNLINK => 1 );
850 .sub add :multi(AInt, Integer, PMC)
864 pir_output_is( <<"CODE", <<'OUTPUT', "override builtin add" );
866 load_bytecode "$temp_pir"
867 \$P0 = subclass "Integer", "AInt"
869 \$P1 = new ['Integer']
873 \$P2 = add \$P0, \$P1
881 pir_output_is( <<'CODE', <<'OUTPUT', "mmd bug reported by Jeff" );
884 .sub bar :method :multi(Foo, string)
889 .sub bar :method :multi(Foo, pmc)
894 .sub bar :method :multi(Foo)
919 pir_output_is( <<'CODE', <<'OUTPUT', "use a core func for an object");
921 .local pmc d, l, r, cl
923 addattribute cl, ".i"
929 func = find_multi "add", "Float,Float,PMC"
935 add_multi "add", typ, func
947 .sub init :vtable :method
948 $P0 = new ['Integer']
949 setattribute self, ".i", $P0
951 .sub set_integer_native :vtable :method
953 $P0 = getattribute self, ".i"
956 .sub set_number_native :vtable :method
958 $P0 = getattribute self, ".i"
961 .sub get_string :vtable :method
962 $P0 = getattribute self, ".i"
966 .sub get_number :vtable :method
967 $P0 = getattribute self, ".i"
977 pir_output_is( <<'CODE', <<'OUTPUT', "multisub vs find_name" );
979 $P0 = find_name "foo"
984 .sub foo :method :multi(string)
988 .sub foo :method :multi(pmc)
996 pir_output_is( <<'CODE', <<'OUTPUT', "multisub w void" );
1002 .sub foo :multi(string)
1004 print "foo string\n"
1015 pir_output_is( <<'CODE', <<'OUTPUT', "multisub w/o .HLL" );
1017 $P0 = new ['Integer']
1021 $P0 = new ['ResizablePMCArray']
1023 $P1 = new ['String']
1025 $P9 = 'foo'($P0, $P1)
1028 .sub 'foo' :multi(Integer)
1029 print "foo(Integer)\n"
1033 .sub 'foo' :multi(ResizablePMCArray, _)
1034 print "foo(ResizablePMCArray,_)\n"
1039 foo(ResizablePMCArray,_)
1042 pir_output_is( <<'CODE', <<'OUTPUT', "multisub w/ .HLL, rt #39161" );
1045 $P0 = new ['Integer']
1049 $P0 = new ['ResizablePMCArray']
1051 $P1 = new ['String']
1053 $P9 = 'foo'($P0, $P1)
1056 .sub 'foo' :multi(Integer)
1057 print "foo(Integer)\n"
1061 .sub 'foo' :multi(ResizablePMCArray, _)
1062 print "foo(ResizablePMCArray,_)\n"
1067 foo(ResizablePMCArray,_)
1070 pir_output_is( <<'CODE', <<'OUTPUT', "multisub w/ flatten" );
1071 # see also 'rt #39173
1074 int_pmc = new ['Integer']
1078 args = new ['ResizablePMCArray']
1082 .local pmc string_pmc
1083 string_pmc = new ['String']
1084 string_pmc = 'hello'
1086 args = new ['ResizablePMCArray']
1087 push args, string_pmc
1092 .sub 'foo' :multi(Integer)
1093 print "foo(Integer)\n"
1096 .sub 'foo' :multi(String)
1097 print "foo(String)\n"
1104 pir_output_is( <<'CODE', <<'OUTPUT', "keyed class name and multi" );
1107 newclass class, [ 'Some'; 'Class' ]
1110 instance = new [ 'Some'; 'Class' ]
1113 name = typeof instance
1124 pir_output_is( <<'CODE', <<'OUTPUT', "keyed class name and multi" );
1127 newclass class, [ 'Some'; 'Class' ]
1130 instance = new [ 'Some'; 'Class' ]
1136 .sub 'foo' :multi( [ 'Some'; 'Class' ])
1137 print "Called multi for class\n"
1140 .sub 'foo' :multi(_)
1141 print "Called wrong multi\n"
1144 Called multi for class
1147 pir_output_is( <<'CODE', <<'OUTPUT', "unicode sub names and multi" );
1148 .sub unicode:"\u7777" :multi(string)
1153 .sub unicode:"\u7777" :multi(int)
1160 unicode:"\u7777"('what')
1161 unicode:"\u7777"(23)
1168 pir_output_is( <<'CODE', <<'OUTPUT', "autoboxing on multis" );
1169 .sub box_me_up :multi(string)
1173 .local string promoted_type
1174 promoted_type = typeof second
1175 print "BMU autobox type: "
1180 .sub box_me_up :multi()
1181 print "BMU no autobox, so sad\n"
1184 .sub box_me_up :multi(int, int)
1185 print "BMU inty, so bad\n"
1189 box_me_up( 'foo', 'bar' )
1192 BMU autobox type: String
1195 pir_output_is( <<'CODE', <<'OUTPUT', '_ matches native types' );
1198 asub = get_global 'main'
1200 foo('world', asub) # should call :multi(_, Sub)
1203 .sub foo :multi(_, Sub)
1208 say ":multi(_, Sub)"
1211 .sub foo :multi(Integer, Sub)
1216 say ":multi(int, Sub)"
1219 world :multi(_, Sub)
1222 pir_output_is( <<'CODE', <<'OUTPUT', 'type mix with _' );
1224 $P0 = new ['Integer']
1229 $P0 = new ['String']
1236 .sub 'foo' :multi(Integer)
1238 print "foo(Integer)\n"
1241 .sub 'foo' :multi(_)
1246 .sub 'foo' :multi(int)
1251 .sub 'foo' :multi(String)
1253 print "foo(String)\n"
1256 .sub 'foo' :multi(string)
1258 print "foo(string)\n"
1268 pir_output_is( <<'CODE', <<'OUTPUT', ':multi with :outer' );
1277 $P99 = "foo"($P0, $P1)
1281 $P99 = "bar"($P0, $P1)
1285 .sub "foo" :multi(_)
1292 .sub "foo" :multi(_,_)
1302 .sub "bar" :outer("main") :multi(_)
1309 .sub "bar" :outer("main") :multi(_,_)
1325 pir_output_is( <<'CODE', <<'OUTPUT', "multi-dispatch on PMCNULL" );
1331 .sub foo :multi(String)
1341 pir_output_is( <<'CODE', <<'OUTPUT', "multi-dispatch with :optional" );
1350 .sub foo :multi(string)
1352 .param int i :optional
1353 .param int have_i :opt_flag
1356 unless have_i goto done
1361 .sub foo :multi(int)
1363 .param int i :optional
1364 .param int have_i :opt_flag
1367 unless have_i goto done
1380 pir_output_is( <<'CODE', <<'OUTPUT', '.autoboxed MMD with :optional' );
1391 .sub foo :multi(String)
1393 .param pmc i :optional
1394 .param int have_i :opt_flag
1397 unless have_i goto done
1402 .sub foo :multi(Integer)
1404 .param pmc i :optional
1405 .param int have_i :opt_flag
1408 unless have_i goto done
1413 .sub foo :multi(Float)
1415 .param pmc i :optional
1416 .param int have_i :opt_flag
1419 unless have_i goto done
1435 pir_output_is( <<'CODE', <<'OUTPUT', 'more .autoboxed MMD with :optional' );
1439 foo('Goodbye', 'Ta ta', 2)
1443 foo(77.7, 88.8, 99.9)
1446 .sub foo :multi(String, String)
1449 .param pmc i :optional
1450 .param int have_i :opt_flag
1454 unless have_i goto done
1460 .sub foo :multi(Integer, Integer)
1463 .param pmc i :optional
1464 .param int have_i :opt_flag
1468 unless have_i goto done
1474 .sub foo :multi(Float, Float)
1477 .param pmc i :optional
1478 .param int have_i :opt_flag
1482 unless have_i goto done
1496 pir_output_is( <<'CODE', <<'OUTPUT', 'Integer subclass and MMD - TT #784' );
1499 int_c = get_class "Integer"
1502 sub_c = subclass int_c, "MyInt"
1519 pir_output_is( <<'CODE', <<'OUTPUT', 'int autoboxes to scalar - TT #1133' );
1520 .sub 'foo' :multi(['scalar'])
1527 $I0 = isa x, 'scalar'
1545 # cperl-indent-level: 4
1548 # vim: expandtab shiftwidth=4: