[svn:parrot] r41698 - in branches/pcc_reapply/src: call pmc

allison at svn.parrot.org allison at svn.parrot.org
Sun Oct 4 16:58:18 UTC 2009


Author: allison
Date: Sun Oct  4 16:58:18 2009
New Revision: 41698
URL: https://trac.parrot.org/parrot/changeset/41698

Log:
[pcc] Reworking fill_params as an iterator over arguments rather than
parameters.

Modified:
   branches/pcc_reapply/src/call/args.c
   branches/pcc_reapply/src/pmc/callsignature.pmc

Modified: branches/pcc_reapply/src/call/args.c
==============================================================================
--- branches/pcc_reapply/src/call/args.c	Sun Oct  4 16:25:45 2009	(r41697)
+++ branches/pcc_reapply/src/call/args.c	Sun Oct  4 16:58:18 2009	(r41698)
@@ -53,6 +53,15 @@
 /* HEADERIZER BEGIN: static */
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 
+static void assign_default_param_value(PARROT_INTERP,
+    INTVAL param_index,
+    INTVAL param_flags,
+    ARGIN(void *arg_info),
+    ARGIN(struct pcc_set_funcs *accessor))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(4)
+        __attribute__nonnull__(5);
+
 static void dissect_aggregate_arg(PARROT_INTERP,
     ARGMOD(PMC *call_object),
     ARGIN(PMC *aggregate))
@@ -177,6 +186,10 @@
     SHIM(INTVAL param_index))
         __attribute__nonnull__(1);
 
+#define ASSERT_ARGS_assign_default_param_value __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(arg_info) \
+    , PARROT_ASSERT_ARG(accessor))
 #define ASSERT_ARGS_dissect_aggregate_arg __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(call_object) \
@@ -712,16 +725,14 @@
 {
     ASSERT_ARGS(fill_params)
     PMC    *ctx = CURRENT_CONTEXT(interp);
-    INTVAL  param_count      = VTABLE_elements(interp, raw_sig);
-    INTVAL  positional_elements;
-    STRING *param_name       = NULL;
-    INTVAL  param_index      = 0;
-    INTVAL  positional_index = 0;
-    INTVAL  named_count      = 0;
-    INTVAL  slurpy_count     = 0;
-    INTVAL  optional_count   = 0;
-    INTVAL  err_check        = 0;
-    INTVAL  got_optional     = -1;
+    PMC    *named_arg_list;
+    PMC    *named_used_list = PMCNULL;
+    INTVAL  param_count     = VTABLE_elements(interp, raw_sig);
+    INTVAL  positional_args;
+    INTVAL  param_index     = 0;
+    INTVAL  arg_index       = 0;
+    INTVAL  named_count     = 0;
+    INTVAL  err_check       = 0;
 
     /* Check if we should be throwing errors. This is configured separately
      * for parameters and return values. */
@@ -739,78 +750,229 @@
         return;
     }
 
-    positional_elements = VTABLE_elements(interp, call_object);
+    positional_args = VTABLE_elements(interp, call_object);
+
+    /* First iterate over positional args and positional parameters. */
+    arg_index = 0;
+    param_index = 0;
+    while (1) {
+        INTVAL optional_param = 0;
+        INTVAL param_flags;
+
+        /* Check if we've used up all the parameters. */
+        if (param_index >= param_count) {
+            if (arg_index >= positional_args) {
+                /* We've used up all the arguments and parameters, we're done. */
+                break;
+            }
+            else if (err_check) {
+                /* We've used up all the parameters, but have extra positional
+                 * args left over. */
+                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+                        "too many positional arguments: %d passed, %d expected",
+                        positional_args, param_index);
+            }
+            return;
+        }
 
-    for (param_index = 0; param_index < param_count; param_index++) {
-        INTVAL param_flags = VTABLE_get_integer_keyed_int(interp,
-                    raw_sig, param_index);
+        param_flags = VTABLE_get_integer_keyed_int(interp, raw_sig, param_index);
 
-        /* If it's also optional, set that info */
+        /* If the parameter is optional, set a flag for error checking */
         if (param_flags & PARROT_ARG_OPTIONAL) {
-            got_optional = 1;
-            optional_count++;
+            optional_param = 1;
         }
 
-        /* opt_flag parameter */
-        if (param_flags & PARROT_ARG_OPT_FLAG) {
-            if (optional_count <= 0)
-                Parrot_ex_throw_from_c_args(interp, NULL,
-                        EXCEPTION_INVALID_OPERATION,
-                        "optional flag with no optional parameter");
-            if (got_optional < 0 || got_optional > 1)
+        /* If the parameter is slurpy, collect all remaining positional
+         * arguments into an array.*/
+        if (param_flags & PARROT_ARG_SLURPY_ARRAY) {
+            PMC *collect_positional;
+
+            /* Can't handle named slurpy here, go on to named argument handling. */
+            if (param_flags & PARROT_ARG_NAME)
+                break;
+
+            if (named_count > 0)
                 Parrot_ex_throw_from_c_args(interp, NULL,
                         EXCEPTION_INVALID_OPERATION,
-                        "unable to determine if optional argument was passed");
+                        "named parameters must follow all positional parameters");
 
-            *accessor->intval(interp, arg_info, param_index) = got_optional;
-            got_optional = -1;
-            continue; /* on to next parameter */
-        }
-        /* Collected ("slurpy") parameter */
-        else if (param_flags & PARROT_ARG_SLURPY_ARRAY) {
-            /* Collect named arguments into hash */
-            if (param_flags & PARROT_ARG_NAME) {
-                PMC * const collect_named = pmc_new(interp,
-                        Parrot_get_ctx_HLL_type(interp, enum_class_Hash));
+            collect_positional = pmc_new(interp,
+                    Parrot_get_ctx_HLL_type(interp, enum_class_ResizablePMCArray));
+            for (; arg_index < positional_args; arg_index++) {
+                VTABLE_push_pmc(interp, collect_positional,
+                        VTABLE_get_pmc_keyed_int(interp, call_object, arg_index));
+            }
+            *accessor->pmc(interp, arg_info, param_index) = collect_positional;
+            param_index++;
+            break; /* Terminate the positional arg loop. */
+        }
+
+        /* We have a positional argument, fill the parameter with it. */
+        if (arg_index < positional_args) {
 
-                *accessor->pmc(interp, arg_info, param_index) = collect_named;
-                named_count += VTABLE_elements(interp, collect_named);
+            /* Fill a named parameter with a positional argument. */
+            if (param_flags & PARROT_ARG_NAME) {
+                STRING *param_name = PARROT_ARG_CONSTANT_ISSET(param_flags)
+                                   ? accessor->string_constant(interp, arg_info, param_index)
+                                   : *accessor->string(interp, arg_info, param_index);
+                named_count++;
+                param_index++;
+                if (param_index >= param_count)
+                    continue;
+                param_flags = VTABLE_get_integer_keyed_int(interp,
+                            raw_sig, param_index);
+
+                /* Mark the name as used, cannot be filled again. */
+                if (err_check) {
+                    if (PMC_IS_NULL(named_used_list)) /* Only created if needed. */
+                        named_used_list = pmc_new(interp, enum_class_Hash);
+                    VTABLE_set_integer_keyed_str(interp, named_used_list, param_name, 1);
+                }
             }
-            /* Collect positional arguments into array */
-            else {
-                PMC *collect_positional;
-                if (named_count > 0)
+            else if (named_count > 0) {
+                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+                        "named parameters must follow all positional parameters");
+            }
+
+            /* Check for :lookahead parameter goes here. */
+
+            /* Go ahead and fill the parameter with a positional argument. */
+            switch (PARROT_ARG_TYPE_MASK_MASK(param_flags)) {
+                case PARROT_ARG_INTVAL:
+                    *accessor->intval(interp, arg_info, param_index) =
+                            VTABLE_get_integer_keyed_int(interp, call_object, arg_index);
+                    break;
+                case PARROT_ARG_FLOATVAL:
+                    *accessor->numval(interp, arg_info, param_index) =
+                            VTABLE_get_number_keyed_int(interp, call_object, arg_index);
+                    break;
+                case PARROT_ARG_STRING:
+                    *accessor->string(interp, arg_info, param_index) =
+                            VTABLE_get_string_keyed_int(interp, call_object, arg_index);
+                    break;
+                case PARROT_ARG_PMC:
+                    *accessor->pmc(interp, arg_info, param_index) =
+                            VTABLE_get_pmc_keyed_int(interp, call_object, arg_index);
+                    break;
+                default:
                     Parrot_ex_throw_from_c_args(interp, NULL,
-                            EXCEPTION_INVALID_OPERATION,
-                            "named parameters must follow all positional parameters");
-                collect_positional = pmc_new(interp,
-                        Parrot_get_ctx_HLL_type(interp, enum_class_ResizablePMCArray));
-                for (; positional_index < positional_elements; positional_index++) {
-                    VTABLE_push_pmc(interp, collect_positional,
-                            VTABLE_get_pmc_keyed_int(interp, call_object, positional_index));
+                            EXCEPTION_INVALID_OPERATION, "invalid parameter type");
+                    break;
+            }
+
+            /* Mark the option flag for the filled parameter. */
+            if (optional_param) {
+                INTVAL next_param_flags;
+
+                if (param_index + 1 < param_count) {
+                    next_param_flags = VTABLE_get_integer_keyed_int(interp,
+                            raw_sig, param_index + 1);
+                    if (next_param_flags & PARROT_ARG_OPT_FLAG) {
+                        param_index++;
+                        *accessor->intval(interp, arg_info, param_index) = 1;
+                    }
                 }
-                *accessor->pmc(interp, arg_info, param_index) = collect_positional;
             }
+        }
+        /* We have no more positional arguments, fill the optional parameter
+         * with a default value. */
+        else if (optional_param) {
+            INTVAL next_param_flags;
+
+            /* We don't handle optional named params here, handle them in the
+             * next loop. */
+            if (param_flags & PARROT_ARG_NAME)
+                break;
+
+            assign_default_param_value(interp, param_index, param_flags,
+                    arg_info, accessor);
+
+            /* Mark the option flag for the parameter to FALSE, it was filled
+             * with a default value. */
+            if (param_index + 1 < param_count) {
+                next_param_flags = VTABLE_get_integer_keyed_int(interp,
+                        raw_sig, param_index + 1);
+                if (next_param_flags & PARROT_ARG_OPT_FLAG) {
+                    param_index++;
+                    *accessor->intval(interp, arg_info, param_index) = 0;
+                }
+            }
+        }
+        /* We don't have an argument for the parameter, and it's not optional,
+         * so it's an error. */
+        else {
+            /* We don't handle named params here, go to the next loop. */
+            if (param_flags & PARROT_ARG_NAME)
+                break;
+
+            if (err_check)
+                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+                        "too few positional arguments: %d passed, %d (or more) expected",
+                        positional_args, param_index + 1);
+        }
+
+        /* Go on to next argument and parameter. */
+        arg_index++;
+        param_index++;
+    }
 
-            continue; /* on to next parameter */
+    /* Now iterate over the named arguments and parameters. */
+    while (1) {
+        INTVAL optional_param = 0;
+        STRING *param_name    = NULL;
+        INTVAL param_flags;
+
+        /* Check if we've used up all the parameters. We'll check for leftover
+         * named args after the loop. */
+        if (param_index >= param_count)
+            break; 
+
+        param_flags = VTABLE_get_integer_keyed_int(interp, raw_sig, param_index);
+
+        /* All remaining parameters must be named. */
+        if (!(param_flags & PARROT_ARG_NAME)) {
+            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+                    "named parameters must follow all positional parameters");
         }
-        /* Named non-collected */
-        else if (param_flags & PARROT_ARG_NAME) {
-            /* Just store the name for now (this parameter is only the
-             * name). The next parameter is the actual value. */
-            param_name = PARROT_ARG_CONSTANT_ISSET(param_flags)
+
+        /* If the parameter is optional, set a flag for error checking */
+        if (param_flags & PARROT_ARG_OPTIONAL) {
+            optional_param = 1;
+        }
+
+        /* Collected ("slurpy") named parameter */
+        if (param_flags & PARROT_ARG_SLURPY_ARRAY) {
+            PMC * const collect_named = pmc_new(interp,
+                    Parrot_get_ctx_HLL_type(interp, enum_class_Hash));
+
+            *accessor->pmc(interp, arg_info, param_index) = collect_named;
+            named_count += VTABLE_elements(interp, collect_named);
+            break; /* End of named parameters. */
+        }
+
+        /* Store the name. */
+        param_name = PARROT_ARG_CONSTANT_ISSET(param_flags)
                                ? accessor->string_constant(interp, arg_info, param_index)
                                : *accessor->string(interp, arg_info, param_index);
 
-            continue;
-        }
-        else if (!STRING_IS_NULL(param_name)) {
-            /* The previous parameter was a parameter name. Now set the
-             * value of the named parameter.*/
+        if (!STRING_IS_NULL(param_name)) {
+            /* The next parameter is the actual value. */
+            param_index++;
+            if (param_index >= param_count)
+                continue;
+            param_flags = VTABLE_get_integer_keyed_int(interp, raw_sig, param_index);
 
             if (VTABLE_exists_keyed_str(interp, call_object, param_name)) {
+
+                /* Mark the name as used, cannot be filled again. */
+                if (err_check) {
+                    if (PMC_IS_NULL(named_used_list)) /* Only created if needed. */
+                        named_used_list = pmc_new(interp, enum_class_Hash);
+                    VTABLE_set_integer_keyed_str(interp, named_used_list, param_name, 1);
+                }
                 named_count++;
 
+                /* Fill the named parameter. */
                 switch (PARROT_ARG_TYPE_MASK_MASK(param_flags)) {
                     case PARROT_ARG_INTVAL:
                         *accessor->intval(interp, arg_info, param_index) =
@@ -833,95 +995,107 @@
                                 EXCEPTION_INVALID_OPERATION, "invalid parameter type");
                         break;
                 }
-                param_name = NULL;
-                continue; /* on to next parameter */
-            }
-
-            /* If the named parameter doesn't have a corresponding named
-             * argument, fall through to positional argument handling. */
-            param_name = NULL;
-        }
-        else {
-            /* Positional non-collected */
-            if (named_count > 0)
-                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
-                        "named parameters must follow all positional parameters");
-        }
 
-        if (slurpy_count > 0)
-            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
-                    "slurpy parameters must follow ordinary positional parameters");
+                /* Mark the option flag for the filled parameter. */
+                if (optional_param) {
+                    INTVAL next_param_flags;
+
+                    if (param_index + 1 < param_count) {
+                        next_param_flags = VTABLE_get_integer_keyed_int(interp,
+                                raw_sig, param_index + 1);
+                        if (next_param_flags & PARROT_ARG_OPT_FLAG) {
+                            param_index++;
+                            *accessor->intval(interp, arg_info, param_index) = 1;
+                        }
+                    }
+                }
+            }
+            else if (optional_param) {
+                INTVAL next_param_flags;
 
-        /* No more positional arguments available to assign */
-        if (positional_index >= positional_elements) {
-            if (!(param_flags & PARROT_ARG_OPTIONAL))
-                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
-                        "too few positional arguments: %d passed, %d (or more) expected",
-                        positional_elements, param_index + 1);
+                assign_default_param_value(interp, param_index, param_flags,
+                        arg_info, accessor);
 
-            got_optional = 0;
-            optional_count++;
-            switch (PARROT_ARG_TYPE_MASK_MASK(param_flags)) {
-                case PARROT_ARG_INTVAL:
-                    *accessor->intval(interp, arg_info, param_index) = 0;
-                    break;
-                case PARROT_ARG_FLOATVAL:
-                    *accessor->numval(interp, arg_info, param_index) = 0.0;
-                    break;
-                case PARROT_ARG_STRING:
-                    *accessor->string(interp, arg_info, param_index) = NULL;
-                    break;
-                case PARROT_ARG_PMC:
-                    *accessor->pmc(interp, arg_info, param_index) = PMCNULL;
-                    break;
-                default:
-                    Parrot_ex_throw_from_c_args(interp, NULL,
-                            EXCEPTION_INVALID_OPERATION, "invalid parameter type");
-                    break;
+                /* Mark the option flag for the parameter to FALSE, it was filled
+                 * with a default value. */
+                if (param_index + 1 < param_count) {
+                    next_param_flags = VTABLE_get_integer_keyed_int(interp,
+                            raw_sig, param_index + 1);
+                    if (next_param_flags & PARROT_ARG_OPT_FLAG) {
+                        param_index++;
+                        *accessor->intval(interp, arg_info, param_index) = 0;
+                    }
+                }
+            }
+            /* We don't have an argument for the parameter, and it's not optional,
+             * so it's an error. */
+            else {
+                if (err_check)
+                    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+                            "too few named arguments: no argument for required parameter '%S'",
+                            param_name);
             }
-
-            continue; /* on to next parameter */
         }
 
-        /* If last argument was an optional, but this arg isn't the
-           corresponding opt_flag, reset the flag. */
-        if (got_optional && !param_flags & PARROT_ARG_OPTIONAL)
-            got_optional = -1;
+        param_index++;
+    }
 
-        /* It's a (possibly optional) positional. Fill it. */
-        switch (PARROT_ARG_TYPE_MASK_MASK(param_flags)) {
-            case PARROT_ARG_INTVAL:
-                *accessor->intval(interp, arg_info, param_index) =
-                        VTABLE_get_integer_keyed_int(interp, call_object, positional_index);
-                positional_index++;
-                break;
-            case PARROT_ARG_FLOATVAL:
-                *accessor->numval(interp, arg_info, param_index) =
-                        VTABLE_get_number_keyed_int(interp, call_object, positional_index);
-                positional_index++;
-                break;
-            case PARROT_ARG_STRING:
-                *accessor->string(interp, arg_info, param_index) =
-                        VTABLE_get_string_keyed_int(interp, call_object, positional_index);
-                positional_index++;
-                break;
-            case PARROT_ARG_PMC:
-                *accessor->pmc(interp, arg_info, param_index) =
-                        VTABLE_get_pmc_keyed_int(interp, call_object, positional_index);
-                positional_index++;
-                break;
-            default:
-                Parrot_ex_throw_from_c_args(interp, NULL,
-                        EXCEPTION_INVALID_OPERATION, "invalid parameter type");
-                break;
+    /* Double check that all named arguments were assigned to parameters. */
+    if (err_check) {
+        named_arg_list = VTABLE_get_attr_str(interp, call_object, CONST_STRING(interp, "named"));
+        if (!PMC_IS_NULL(named_arg_list)) {
+            INTVAL named_arg_count = VTABLE_elements(interp, named_arg_list);
+            if (named_arg_count > named_count) {
+                /* At this point we know we have named arguments that weren't
+                 * assigned to parameters. We're going to throw an exception
+                 * anyway, so spend a little extra effort to tell the user *which*
+                 * named argument is extra. */
+                INTVAL named_arg_index;
+                PMC *named_key = pmc_new(interp, enum_class_Key);
+                VTABLE_set_integer_native(interp, named_key, 0);
+                SETATTR_Key_next_key(interp, named_key, (PMC *)INITBucketIndex);
+
+                /* Low-level hash iteration. */
+                for (named_arg_index = 0; named_arg_index < named_arg_count; named_arg_index++) {
+                    if (!PMC_IS_NULL(named_key)) {
+                        STRING *name = (STRING *)parrot_hash_get_idx(interp,
+                                        (Hash *)VTABLE_get_pointer(interp, named_arg_list), named_key);
+                        PARROT_ASSERT(name);
+                        if (!VTABLE_exists_keyed_str(interp, named_used_list, name)) {
+                            Parrot_ex_throw_from_c_args(interp, NULL,
+                                    EXCEPTION_INVALID_OPERATION,
+                                    "too many named arguments: '%S' not used",
+                                    name);
+                        }
+                    }
+                }
+            }
         }
     }
+}
 
-    if (err_check && (positional_elements > positional_index))
-        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
-                "too many positional arguments: %d passed, %d expected",
-                positional_elements, param_count);
-
+static void
+assign_default_param_value(PARROT_INTERP, INTVAL param_index, INTVAL param_flags,
+        ARGIN(void *arg_info), ARGIN(struct pcc_set_funcs *accessor))
+{
+    switch (PARROT_ARG_TYPE_MASK_MASK(param_flags)) {
+        case PARROT_ARG_INTVAL:
+            *accessor->intval(interp, arg_info, param_index) = 0;
+            break;
+        case PARROT_ARG_FLOATVAL:
+            *accessor->numval(interp, arg_info, param_index) = 0.0;
+            break;
+        case PARROT_ARG_STRING:
+            *accessor->string(interp, arg_info, param_index) = NULL;
+            break;
+        case PARROT_ARG_PMC:
+            *accessor->pmc(interp, arg_info, param_index) = PMCNULL;
+            break;
+        default:
+            Parrot_ex_throw_from_c_args(interp, NULL,
+                    EXCEPTION_INVALID_OPERATION, "invalid parameter type");
+            break;
+    }
 }
 
 /*

Modified: branches/pcc_reapply/src/pmc/callsignature.pmc
==============================================================================
--- branches/pcc_reapply/src/pmc/callsignature.pmc	Sun Oct  4 16:25:45 2009	(r41697)
+++ branches/pcc_reapply/src/pmc/callsignature.pmc	Sun Oct  4 16:58:18 2009	(r41698)
@@ -190,6 +190,10 @@
 Retrieves the flags for the call signature return arguments, an array of
 integers.
 
+=item named
+
+Retrieves the hash of named arguments.
+
 =back
 
 =cut
@@ -208,6 +212,9 @@
         else if (Parrot_str_equal(INTERP, key, CONST_STRING(INTERP, "return_flags"))) {
             GET_ATTR_return_flags(interp, SELF, value);
         }
+        else if (Parrot_str_equal(INTERP, key, CONST_STRING(INTERP, "named"))) {
+            GET_ATTR_hash(interp, SELF, value);
+        }
         else {
             /* If unknown attribute name, throw an exception. */
             Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_ATTRIB_NOT_FOUND,


More information about the parrot-commits mailing list