Author: jonathan
Date: Fri Aug 15 04:28:17 2008
New Revision: 30248

Added:
   trunk/languages/perl6/t/pmc/perl6multisub-dispatch-type.t   (contents, props 
changed)
Modified:
   trunk/languages/perl6/src/classes/Role.pir
   trunk/languages/perl6/src/pmc/perl6multisub.pmc

Log:
[rakudo] Load types for parameters and use them to exclude candidates with 
incompatible types. Add some tests for this.

Modified: trunk/languages/perl6/src/classes/Role.pir
==============================================================================
--- trunk/languages/perl6/src/classes/Role.pir  (original)
+++ trunk/languages/perl6/src/classes/Role.pir  Fri Aug 15 04:28:17 2008
@@ -29,7 +29,8 @@
 .sub 'ACCEPTS' :method
     .param pmc topic
     $I0 = does topic, self
-    .return 'prefix:?'($I0)
+    $P0 = 'prefix:?'($I0)
+    .return ($P0)
 .end
 
 =back

Modified: trunk/languages/perl6/src/pmc/perl6multisub.pmc
==============================================================================
--- trunk/languages/perl6/src/pmc/perl6multisub.pmc     (original)
+++ trunk/languages/perl6/src/pmc/perl6multisub.pmc     Fri Aug 15 04:28:17 2008
@@ -60,6 +60,7 @@
     PMC **types;          /* Class or role type constraints for each 
parameter. */
     PMC **constraints;    /* Refinement type constraints for each parameter 
(if there
                            * are many, this will be a junction). */
+    INTVAL num_types;     /* Number of entries in the above two arrays. */
 } candidate_info;
 
 
@@ -276,6 +277,7 @@
             info->types[j] = type;
             info->constraints[j] = constraints;
         }
+        info->num_types = sig_elems;
 
         /* Add it to graph node, and initialize list of edges. */
         graph[i] = mem_allocate_zeroed_typed(candidate_graph_node);
@@ -320,10 +322,13 @@
 
 static PMC* do_dispatch(PARROT_INTERP, candidate_info** candidates, PMC *args, 
int many,
                         int num_candidates, opcode_t *next) {
+    INTVAL i, type_check_count;
     INTVAL num_args = VTABLE_elements(interp, args);
     candidate_info **cur_candidate = candidates;
     candidate_info **possibles = mem_allocate_n_typed(num_candidates, 
candidate_info*);
     INTVAL possibles_count = 0;
+    INTVAL type_mismatch;
+    STRING *ACCEPTS = CONST_STRING(interp, "ACCEPTS");
 
     /* Iterate over the candidates and collect best ones; terminate
      * when we see two nulls (may break out earlier). */
@@ -334,7 +339,25 @@
             continue;
         }
 
-        /* XXX Check if it's admissable by type. */
+        /* Check if it's admissable by type. */
+        type_check_count = (*cur_candidate)->num_types > num_args ?
+                num_args : (*cur_candidate)->num_types;
+        type_mismatch = 0;
+        for (i = 0; i < type_check_count; i++) {
+            PMC *param = VTABLE_get_pmc_keyed_int(interp, args, i);
+            PMC *type_obj = (*cur_candidate)->types[i];
+            PMC *accepts_meth = VTABLE_find_method(interp, type_obj, ACCEPTS);
+            PMC *result = Parrot_run_meth_fromc_args(interp, accepts_meth, 
type_obj,
+                    ACCEPTS, "PP", param);
+            if (!VTABLE_get_integer(interp, result)) {
+                type_mismatch = 1;
+                break;
+            }
+        }
+        if (type_mismatch) {
+            cur_candidate++;
+            continue;
+        }
 
         /* If we get here, it's an admissable candidate; add to list. */
         possibles[possibles_count] = *cur_candidate;
@@ -466,8 +489,14 @@
     VTABLE opcode_t *invoke(void *next) {
         PMC *found;
 
-        /* Need to make sure current continuation doesn't get destroyed. */
-        PMC *saved_ccont = interp->current_cont;
+        /* Need to make sure a wobload of globals don't get destroyed. */
+        PMC *saved_ccont            = interp->current_cont;
+        opcode_t *current_args      = interp->current_args;
+        opcode_t *current_params    = interp->current_params;
+        opcode_t *current_returns   = interp->current_returns;
+        PMC      *args_signature    = interp->args_signature;
+        PMC      *params_signature  = interp->params_signature;
+        PMC      *returns_signature = interp->returns_signature;
 
         /* Make sure that we have a candidate list built. */
         candidate_info **candidates = NULL;
@@ -486,8 +515,17 @@
         found = do_dispatch(interp, candidates, get_args(interp), 0,
                 VTABLE_elements(interp, unsorted), next);
 
-        /* Invoke what was found. */
+        /* Restore stuff that might have got overwriten by calls during the
+         * dispatch algorithm. */
         interp->current_cont = saved_ccont;
+        interp->current_args = current_args;
+        interp->current_params = current_params;
+        interp->current_returns = current_returns;
+        interp->args_signature = args_signature;
+        interp->params_signature = params_signature;
+        interp->returns_signature = returns_signature;
+
+        /* Invoke the winner. */
         return VTABLE_invoke(interp, found, next);
     }
 

Added: trunk/languages/perl6/t/pmc/perl6multisub-dispatch-type.t
==============================================================================
--- (empty file)
+++ trunk/languages/perl6/t/pmc/perl6multisub-dispatch-type.t   Fri Aug 15 
04:28:17 2008
@@ -0,0 +1,198 @@
+#! ../../parrot
+# Copyright (C) 2007-2008, The Perl Foundation.
+# $Id:$
+
+=head1 NAME
+
+t/pmc/perl6multisub-dispatch-type.t - Type based dispatch tests
+
+=head1 SYNOPSIS
+
+    % prove t/pmc/perl6multisub-dispatch-type.t
+
+=head1 DESCRIPTION
+
+Tests for type based dispatch using the Perl 6 MultiSub PMC.
+
+=cut
+
+.loadlib 'perl6_group'
+
+.sub main :main
+    .include 'include/test_more.pir'
+    load_bytecode "perl6.pbc"
+
+    plan(4)
+
+    'basic_class'()
+    'role'()
+    #'ordered_class'() # XXX Not passing until we do topological sort
+.end
+
+
+.sub 'basic_class'
+    $P0 = new "Perl6MultiSub"
+    $P1 = find_global 'basic_class_1'
+    'attach_sig'($P1, 'Int')
+    push $P0, $P1
+    $P1 = find_global 'basic_class_2'
+    'attach_sig'($P1, 'Junction')
+    push $P0, $P1
+
+    $P1 = new 'Int'
+    $P1 = 42
+    $I0 = $P0($P1)
+    is($I0, 1, 'dispatch on class')
+    $P1 = new 'Junction'
+    $I0 = $P0($P1)
+    is($I0, 2, 'dispatch on class')
+.end
+.sub 'basic_class_1'
+    .param pmc a
+    .return (1)
+.end
+.sub 'basic_class_2'
+    .param pmc a
+    .return (2)
+.end
+
+
+.sub 'role'
+    # Create a couple of roles.
+    .local pmc R1, R2
+    R1 = '!keyword_role'('R1')
+    R2 = '!keyword_role'('R2')
+
+    # Set up multis.
+    $P0 = new "Perl6MultiSub"
+    $P1 = find_global 'role_1'
+    'attach_sig'($P1, 'R1')
+    push $P0, $P1
+    $P1 = find_global 'role_2'
+    'attach_sig'($P1, 'R2')
+    push $P0, $P1
+
+    # Couple of classes that do the roles.
+    .local pmc C1, C2
+    C1 = new 'Class'
+    addrole C1, R1
+    C2 = new 'Class'
+    addrole C2, R2
+
+    # Tests
+    $P1 = new C1
+    $I0 = $P0($P1)
+    is($I0, 1, 'dispatch on a role')
+    $P1 = new C2
+    $I0 = $P0($P1)
+    is($I0, 2, 'dispatch on a role')
+.end
+.sub 'role_1'
+    .param pmc a
+    .return (1)
+.end
+.sub 'role_2'
+    .param pmc a
+    .return (2)
+.end
+
+
+.sub 'ordered_class'
+    # Create 3 classes.
+    .local pmc p6meta
+    p6meta = get_hll_global ['Perl6Object'], '$!P6META'
+    p6meta.'new_class'('Paper', 'parent'=>'Any')
+    p6meta.'new_class'('Scissors', 'parent'=>'Any')
+    p6meta.'new_class'('Stone', 'parent'=>'Any')
+
+    $P0 = new "Perl6MultiSub"
+    $P1 = find_global 'ordered_class_1'
+    'attach_sig'($P1, 'Any', 'Any')
+    push $P0, $P1
+    $P1 = find_global 'ordered_class_2'
+    'attach_sig'($P1, 'Paper', 'Stone')
+    push $P0, $P1
+    $P1 = find_global 'ordered_class_3'
+    'attach_sig'($P1, 'Stone', 'Scissors')
+    push $P0, $P1
+    $P1 = find_global 'ordered_class_4'
+    'attach_sig'($P1, 'Scissors', 'Paper')
+    push $P0, $P1
+
+    .local pmc paper, scissors, stone
+    paper = get_hll_global 'Paper'
+    paper = paper.'new'()
+    scissors = get_hll_global 'Scissors'
+    scissors = scissors.'new'()
+    stone = get_hll_global 'Stone'
+    stone = stone.'new'()
+
+    $I0 = $P0(paper, paper)
+    is($I0, 0, 'basic class')
+    $I0 = $P0(paper, scissors)
+    is($I0, 0, 'basic class')
+    $I0 = $P0(paper, stone)
+    is($I0, 1, 'basic class')
+    $I0 = $P0(scissors, paper)
+    is($I0, 1, 'basic class')
+    $I0 = $P0(scissors, scissors)
+    is($I0, 0, 'basic class')
+    $I0 = $P0(scissors, stone)
+    is($I0, 0, 'basic class')
+    $I0 = $P0(stone, paper)
+    is($I0, 0, 'basic class')
+    $I0 = $P0(stone, scissors)
+    is($I0, 1, 'basic class')
+    $I0 = $P0(stone, stone)
+    is($I0, 0, 'basic class')
+.end
+.sub 'ordered_class_1'
+    .param pmc a
+    .param pmc b
+    .return (0)
+.end
+.sub 'ordered_class_2'
+    .param pmc a
+    .param pmc b
+    .return (1)
+.end
+.sub 'ordered_class_3'
+    .param pmc a
+    .param pmc b
+    .return (1)
+.end
+.sub 'ordered_class_4'
+    .param pmc a
+    .param pmc b
+    .return (1)
+.end
+
+.sub 'attach_sig'
+    .param pmc sub
+    .param pmc types :slurpy
+    
+    # Make signature.
+    $P0 = new 'Signature'
+    $P1 = new 'Perl6Array'
+    setattribute $P0, "@!params", $P1
+    .local pmc it, type
+    it = iter types
+  param_loop:
+    unless it goto param_loop_end
+    $P3 = shift it
+    $S0 = $P3
+    type = get_hll_global $S0
+    $P2 = new 'Perl6Hash'
+    $P2["type"] = type
+    push $P1, $P2
+    goto param_loop
+  param_loop_end:
+
+    setprop sub, '$!signature', $P0
+.end
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Reply via email to