Author: jonathan
Date: Sat Aug 16 05:45:23 2008
New Revision: 30265

Modified:
   trunk/languages/perl6/src/pmc/perl6multisub.pmc
   trunk/languages/perl6/t/pmc/perl6multisub-dispatch-type.t

Log:
[rakudo] Implement topological sort based upon type narrowness of the 
candidates. This means that we are, with the ommission of various fallbacks/tie 
breaks (and much more testing ;-)) we now have an implementation of the Perl 6 
multi dispatch.

Modified: trunk/languages/perl6/src/pmc/perl6multisub.pmc
==============================================================================
--- trunk/languages/perl6/src/pmc/perl6multisub.pmc     (original)
+++ trunk/languages/perl6/src/pmc/perl6multisub.pmc     Sat Aug 16 05:45:23 2008
@@ -76,7 +76,8 @@
 typedef struct candidate_graph_node {
     candidate_info *info;
     struct candidate_graph_node **edges;
-    int edges_count;
+    INTVAL edges_in;
+    INTVAL edges_out;
 } candidate_graph_node;
 
 
@@ -213,8 +214,45 @@
 
 */
 static INTVAL is_narrower(PARROT_INTERP, candidate_info *a, candidate_info *b) 
{
-    /* XXX TODO */
-    return 0;
+    STRING *ACCEPTS = CONST_STRING(interp, "ACCEPTS");
+    INTVAL narrower = 0;
+    INTVAL tied = 0;
+    INTVAL i;
+
+    /* Check if they have the same number of effective parameters - if
+     * not, incomparable. */
+    if (a->num_types != b->num_types)
+        return 0;
+
+    /* Analyse each parameter in the two candidates. */
+    for (i = 0; i < a->num_types; i++) {
+        PMC *type_obj_a = a->types[i];
+        PMC *type_obj_b = b->types[i];
+        if (type_obj_a == type_obj_b) {
+            /* Same type, so tied. */
+            tied++;
+        }
+        else {
+            PMC *accepts_meth_a = VTABLE_find_method(interp, type_obj_b, 
ACCEPTS);
+            PMC *result_n = Parrot_run_meth_fromc_args(interp, accepts_meth_a, 
type_obj_b,
+                    ACCEPTS, "PP", type_obj_a);
+            if (VTABLE_get_integer(interp, result_n)) {
+                /* Narrower - note it and we're done. */
+                narrower++;
+            }
+            else {
+                /* Make sure it's tied, rather than the other way around. */
+                PMC *accepts_meth_b = VTABLE_find_method(interp, type_obj_a, 
ACCEPTS);
+                PMC *result_w = Parrot_run_meth_fromc_args(interp, 
accepts_meth_b, type_obj_a,
+                        ACCEPTS, "PP", type_obj_b);
+                if (!VTABLE_get_integer(interp, result_w)) {
+                    tied++;
+                }
+            }
+        }
+    }
+
+    return narrower > 1 && narrower + tied == a->num_types;
 }
 
 
@@ -227,7 +265,7 @@
 
 */
 static candidate_info** sort_candidiates(PARROT_INTERP, PMC *candidates) {
-    INTVAL i, j, sig_elems;
+    INTVAL i, j, sig_elems, candidates_to_sort, result_pos;
     PMC *signature, *params, *meth;
 
     /* Allocate results array (just allocate it for worst case, which
@@ -292,17 +330,39 @@
             if (i == j)
                 continue;
             if (is_narrower(interp, graph[i]->info, graph[j]->info)) {
-                graph[i]->edges[graph[i]->edges_count] = graph[j];
-                graph[i]->edges_count++;
+                graph[i]->edges[graph[i]->edges_out] = graph[j];
+                graph[i]->edges_out++;
+                graph[j]->edges_in++;
             }
         }
     }
 
-    /* XXX Here we do the topological sort. For now, just copy the values
-     * with the arity to the array, and nothing is narrower than anything
-     * else. */
-    for (i = 0; i < num_candidates; i++) {
-        result[i] = graph[i]->info;
+    /* Perform the topological sort. */
+    candidates_to_sort = num_candidates;
+    result_pos = 0;
+    while (candidates_to_sort > 0) {
+        INTVAL rem_start_point = result_pos;
+
+        /* Find any nodes that have no incoming edges and add them to results. 
*/
+        for (i = 0; i < num_candidates; i++) {
+            if (graph[i]->edges_in == 0) {
+                /* Add to results. */
+                result[result_pos] = graph[i]->info;
+                result_pos++;
+                candidates_to_sort--;
+                graph[i]->edges_in = -1;
+
+                /* Now we have added this node, remove its outgoing edges. */
+                for (j = 0; j < graph[i]->edges_out; j++)
+                    graph[i]->edges[j]->edges_in--;
+            }
+        }
+        if (rem_start_point == result_pos)
+            Parrot_ex_throw_from_c_args(interp, 0, 1,
+                    "Circularity detected in multi sub types.");
+
+        /* This is end of a tied group, so leave a gap. */
+        result_pos++;
     }
 
     return result;
@@ -332,7 +392,17 @@
 
     /* Iterate over the candidates and collect best ones; terminate
      * when we see two nulls (may break out earlier). */
-    while (*cur_candidate != NULL) {
+    while (cur_candidate[0] != NULL || cur_candidate[1] != NULL) {
+        if (*cur_candidate == NULL) {
+            /* If we're after just one candidate and we have found some, then
+             * we've hit the end of a tied group now, so stop looking if we are
+             * only after one. */
+            if (!many && possibles_count)
+                break;
+            cur_candidate++;
+            continue;
+        }
+        
         /* Check if it's admissable by arity. */
         if (num_args < (*cur_candidate)->min_arity || num_args > 
(*cur_candidate)->max_arity) {
             cur_candidate++;
@@ -362,17 +432,7 @@
         /* If we get here, it's an admissable candidate; add to list. */
         possibles[possibles_count] = *cur_candidate;
         possibles_count++;
-
-        /* Next candidate. */
         cur_candidate++;
-        if (*cur_candidate == NULL) {
-            /* If we're after just one candidate and we have found some, then
-             * we've hit the end of a tied group now, so stop looking if we are
-             * only after one. */
-            if (!many)
-                break;
-            cur_candidate++;
-        }
     }
 
     /* XXX Loooooads of other disambiguation logic comes here. */
@@ -488,6 +548,9 @@
 */
     VTABLE opcode_t *invoke(void *next) {
         PMC *found;
+        
+        /* Get arguments. */
+        PMC *args = get_args(interp);
 
         /* Need to make sure a wobload of globals don't get destroyed. */
         PMC *saved_ccont            = interp->current_cont;
@@ -512,7 +575,7 @@
 
         /* Now do the dispatch on the args we are being invoked with;
          * if it can't find anything, it will throw the required exception. */
-        found = do_dispatch(interp, candidates, get_args(interp), 0,
+        found = do_dispatch(interp, candidates, args, 0,
                 VTABLE_elements(interp, unsorted), next);
 
         /* Restore stuff that might have got overwriten by calls during the

Modified: trunk/languages/perl6/t/pmc/perl6multisub-dispatch-type.t
==============================================================================
--- trunk/languages/perl6/t/pmc/perl6multisub-dispatch-type.t   (original)
+++ trunk/languages/perl6/t/pmc/perl6multisub-dispatch-type.t   Sat Aug 16 
05:45:23 2008
@@ -1,6 +1,6 @@
 #! ../../parrot
 # Copyright (C) 2007-2008, The Perl Foundation.
-# $Id:$
+# $Id$
 
 =head1 NAME
 
@@ -22,11 +22,11 @@
     .include 'include/test_more.pir'
     load_bytecode "perl6.pbc"
 
-    plan(4)
+    plan(13)
 
     'basic_class'()
     'role'()
-    #'ordered_class'() # XXX Not passing until we do topological sort
+    'ordered_class'()
 .end
 
 
@@ -128,23 +128,23 @@
     stone = stone.'new'()
 
     $I0 = $P0(paper, paper)
-    is($I0, 0, 'basic class')
+    is($I0, 0, 'topological sorting')
     $I0 = $P0(paper, scissors)
-    is($I0, 0, 'basic class')
+    is($I0, 0, 'topological sorting')
     $I0 = $P0(paper, stone)
-    is($I0, 1, 'basic class')
+    is($I0, 1, 'topological sorting')
     $I0 = $P0(scissors, paper)
-    is($I0, 1, 'basic class')
+    is($I0, 1, 'topological sorting')
     $I0 = $P0(scissors, scissors)
-    is($I0, 0, 'basic class')
+    is($I0, 0, 'topological sorting')
     $I0 = $P0(scissors, stone)
-    is($I0, 0, 'basic class')
+    is($I0, 0, 'topological sorting')
     $I0 = $P0(stone, paper)
-    is($I0, 0, 'basic class')
+    is($I0, 0, 'topological sorting')
     $I0 = $P0(stone, scissors)
-    is($I0, 1, 'basic class')
+    is($I0, 1, 'topological sorting')
     $I0 = $P0(stone, stone)
-    is($I0, 0, 'basic class')
+    is($I0, 0, 'topological sorting')
 .end
 .sub 'ordered_class_1'
     .param pmc a

Reply via email to