Author: jonathan
Date: Thu Aug 14 02:51:37 2008
New Revision: 30221

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

Log:
[rakudo] Get Perl 6 MultiSub implementation far along enough to do multi 
dispatch based on arity. Includes a couple of initial, passing tests.

Modified: trunk/languages/perl6/src/pmc/perl6multisub.pmc
==============================================================================
--- trunk/languages/perl6/src/pmc/perl6multisub.pmc     (original)
+++ trunk/languages/perl6/src/pmc/perl6multisub.pmc     Thu Aug 14 02:51:37 2008
@@ -55,11 +55,28 @@
 
 typedef struct candidate_info {
     PMC *sub;               /* The sub that is the candidate. */
-    INTVAL arity;           /* The number of required arguments. */
+    INTVAL min_arity;       /* The number of required positonal arguments. */
+    INTVAL max_arity;       /* The number of required and optional positional 
arguments. */
     PMC *type_cons;         /* Any class or role type constraints. */
     PMC *refinement_cons;   /* Any refinement type constraints (C<subset>). */
 } candidate_info;
 
+
+/*
+
+=item candidate_graph_node
+
+Represents the produced information about a candidate as well as the graph
+edges originating from it. The edges array contains pointers to the edges
+in the graph that we have arrows to.
+
+*/
+typedef struct candidate_graph_node {
+    candidate_info *info;
+    struct candidate_graph_node **edges;
+} candidate_graph_node;
+
+
 /*
 
 =back
@@ -192,7 +209,40 @@
 
 */
 static candidate_info** sort_candidiates(PARROT_INTERP, PMC *candidates) {
-    candidate_info** result = mem_allocate_n_zeroed_typed(2, candidate_info*);
+    INTVAL i;
+
+    /* Allocate results array (just allocate it for worst case, which
+     * is no ties ever, so a null between all of them, and then space
+     * for the terminating null. */
+    INTVAL num_candidates = VTABLE_elements(interp, candidates);
+    candidate_info** result = mem_allocate_n_zeroed_typed(
+            2 * num_candidates + 1, candidate_info*);
+
+    /* Create a node for each candidate in the graph. */
+    candidate_graph_node** graph = mem_allocate_n_zeroed_typed(
+            num_candidates, candidate_graph_node*);
+    for (i = 0; i < num_candidates; i++) {
+        /* Get information about this candidate. */
+        candidate_info *info = mem_allocate_zeroed_typed(candidate_info);
+        PMC *candidate = VTABLE_get_pmc_keyed_int(interp, candidates, i);
+        info->sub = candidate;
+        info->min_arity = VTABLE_get_integer(interp,
+                VTABLE_inspect_str(interp, candidate, CONST_STRING(interp, 
"pos_required")));
+        info->max_arity = info->min_arity + VTABLE_get_integer(interp,
+                VTABLE_inspect_str(interp, candidate, CONST_STRING(interp, 
"pos_optional")));
+/* XXX handle slurpy */
+        /* Add it to graph node. */
+        graph[i] = mem_allocate_typed(candidate_graph_node);
+        graph[i]->info = info;
+    }
+
+    /* 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;
+    }
+
     return result;
 }
 
@@ -202,15 +252,62 @@
 
 Runs the Perl 6 MMD algorithm. If many is set to a true value, returns a
 ResizablePMCArray of all possible candidates, which may be empty. If many
-is set to a false value, then returns either the one winning unambiguous
-candidate or throws an error saying that the dispatch failed if there were
-no candidates or that it was ambiguous if there were tied candidates.
+is false, then returns either the one winning unambiguous candidate
+or throws an error saying that the dispatch failed if there were no
+candidates or that it was ambiguous if there were tied candidates.
 
 */
 
-static PMC* do_dispatch(PARROT_INTERP, candidate_info** candidates, int many) {
-    Parrot_ex_throw_from_c_args(interp, NULL, 1, "Unimplemented.");
-    return PMCNULL;
+static PMC* do_dispatch(PARROT_INTERP, candidate_info** candidates, PMC *args, 
int many,
+                        int num_candidates, opcode_t *next) {
+    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;
+
+    /* Iterate over the candidates and collect best ones; terminate
+     * when we see two nulls (may break out earlier). */
+    while (*cur_candidate != NULL) {
+        /* Check if it's admissable by arity. */
+        if (num_args < (*cur_candidate)->min_arity || num_args > 
(*cur_candidate)->max_arity) {
+            cur_candidate++;
+            continue;
+        }
+
+        /* XXX Check if it's admissable by type. */
+
+        /* 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. */
+
+    if (!many) {
+        /* Need a unique candidate. */
+        if (possibles_count == 1) {
+            return possibles[0]->sub;
+        }
+        else if (possibles_count == 0) {
+            Parrot_ex_throw_from_c_args(interp, next, 1,
+                    "No applicable candidates found to dispatch to.");
+        }
+        else {
+            Parrot_ex_throw_from_c_args(interp, next, 1,
+                    "Ambiguous dispatch.");
+        }
+    }
 }
 
 /*
@@ -259,7 +356,7 @@
 
 pmclass Perl6MultiSub extends MultiSub need_ext dynpmc group perl6_group {
     ATTR PMC  *candidates;
-    ATTR struct candidate_info *candidates_sorted;
+    ATTR void *candidates_sorted;
 
 /*
 
@@ -306,24 +403,25 @@
 =cut
 
 */
-    VTABLE opcode_t* invoke(void* next) {
+    VTABLE opcode_t *invoke(void *next) {
         PMC *found;
 
         /* Make sure that we have a candidate list built. */
         candidate_info **candidates = NULL;
+        PMC *unsorted;
         GETATTR_Perl6MultiSub_candidates_sorted(interp, SELF, candidates);
+        GETATTR_Perl6MultiSub_candidates(interp, SELF, unsorted);
         if (!candidates) {
-            PMC *unsorted;
-            GETATTR_Perl6MultiSub_candidates(interp, SELF, unsorted);
             candidates = sort_candidiates(interp, unsorted);
             SETATTR_Perl6MultiSub_candidates_sorted(interp, SELF, candidates);
         }
         if (!candidates)
             Parrot_ex_throw_from_c_args(interp, next, 1, "Failed to build 
candidate list");
 
-        /* Now do the dispatch - if it can't find anything, it will throw the 
required
-         * exceptions. */
-        found = do_dispatch(interp, candidates, 0);
+        /* 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,
+                VTABLE_elements(interp, unsorted), next);
 
         /* Invoke what was found. */
         return VTABLE_invoke(interp, found, next);

Added: trunk/languages/perl6/t/pmc/perl6multisub-dispatch-arity.t
==============================================================================
--- (empty file)
+++ trunk/languages/perl6/t/pmc/perl6multisub-dispatch-arity.t  Thu Aug 14 
02:51:37 2008
@@ -0,0 +1,73 @@
+#! ../../parrot
+# Copyright (C) 2007-2008, The Perl Foundation.
+# $Id$
+
+=head1 NAME
+
+t/pmc/perl6multisub-dispatch-arity.t - Arity based dispatch tests
+
+=head1 SYNOPSIS
+
+    % prove t/pmc/perl6multisub-dispatch-arity.t
+
+=head1 DESCRIPTION
+
+Tests for arity 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)
+
+    'simple'()
+.end    
+
+
+.sub 'simple'
+    $P0 = new "Perl6MultiSub"
+    $P1 = find_global 'simple_1'
+    push $P0, $P1
+    $P1 = find_global 'simple_2'
+    push $P0, $P1
+    $P1 = find_global 'simple_3'
+    push $P0, $P1
+
+    $I0 = $P0()
+    is($I0, 0, 'simple call with 0 args')
+    $I0 = $P0(1)
+    is($I0, 1, 'simple call with 1 arg')
+    $I0 = $P0(1, 2, 3)
+    is($I0, 3, 'simple call with 3 args')
+    $I0 = 0
+    push_eh fails
+    $P0(1, 2)
+  fails:
+    $I0 = 1
+  ok:
+    is($I0, 1, 'call with no arity match fails')
+.end
+.sub 'simple_1'
+    .return (0)
+.end
+.sub 'simple_2'
+    .param int i
+    .return (1)
+.end
+.sub 'simple_3'
+    .param int i
+    .param int j
+    .param int k
+    .return (3)
+.end
+
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Reply via email to