diff options
author | Andy Wingo <wingo@pobox.com> | 2017-02-28 20:42:45 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2017-02-28 21:01:33 +0100 |
commit | 89ececea95bb4180384e897c0259a5128ed2fc15 (patch) | |
tree | c71fd3da394883223e49b268f4d24fe81ebec951 /libguile/eval.c | |
parent | f428e93ee7a4be76341444b228585755807b282f (diff) | |
download | guile-89ececea95bb4180384e897c0259a5128ed2fc15.tar.gz |
Better errors for odd-length keyword args
* libguile/vm-i-system.c (bind-kwargs):
* libguile/vm.c (vm_error_kwargs_missing_value):
* libguile/eval.c (error_missing_value)
(prepare_boot_closure_env_for_apply): Adapt to mirror VM behavior.
* libguile/keywords.c (scm_c_bind_keyword_arguments): Likewise.
* module/ice-9/eval.scm (primitive-eval): Update to error on (foo #:kw)
with a "Keyword argument has no value" instead of the horrible "odd
argument list length". Also adapts to the expected args format for
the keyword-argument-error exception printer in all cases. Matches
1.8 optargs behavior also.
* test-suite/standalone/test-scm-c-bind-keyword-arguments.c (test_missing_value):
(missing_value_error_handler): Update test.
* test-suite/tests/optargs.test: Add tests.
Diffstat (limited to 'libguile/eval.c')
-rw-r--r-- | libguile/eval.c | 64 |
1 files changed, 41 insertions, 23 deletions
diff --git a/libguile/eval.c b/libguile/eval.c index 815f7c7a7..82dcbdd07 100644 --- a/libguile/eval.c +++ b/libguile/eval.c @@ -162,6 +162,13 @@ static void error_used_before_defined (void) "Variable used before given a value", SCM_EOL, SCM_BOOL_F); } +static void error_missing_value (SCM proc, SCM kw) +{ + scm_error_scm (scm_from_latin1_symbol ("keyword-argument-error"), proc, + scm_from_locale_string ("Keyword argument has no value"), SCM_EOL, + scm_list_1 (kw)); +} + static void error_invalid_keyword (SCM proc, SCM obj) { scm_error_scm (scm_from_latin1_symbol ("keyword-argument-error"), proc, @@ -867,38 +874,49 @@ prepare_boot_closure_env_for_apply (SCM proc, SCM args, { int imax = i - 1; int kw_start_idx = i; - SCM walk, k, v; + SCM walk, k; for (walk = kw; scm_is_pair (walk); walk = CDR (walk)) if (SCM_I_INUM (CDAR (walk)) > imax) imax = SCM_I_INUM (CDAR (walk)); for (; i <= imax; i++) env = scm_cons (SCM_UNDEFINED, env); - if (scm_is_pair (args) && scm_is_pair (CDR (args))) - for (; scm_is_pair (args) && scm_is_pair (CDR (args)); - args = CDR (args)) - { - k = CAR (args); v = CADR (args); - if (!scm_is_keyword (k)) + while (scm_is_pair (args)) + { + k = CAR (args); + args = CDR (args); + if (!scm_is_keyword (k)) + { + if (scm_is_true (rest)) + continue; + else + break; + } + for (walk = kw; scm_is_pair (walk); walk = CDR (walk)) + if (scm_is_eq (k, CAAR (walk))) { - if (scm_is_true (rest)) - continue; + /* Well... ok, list-set! isn't the nicest interface, but + hey. */ + int iset = imax - SCM_I_INUM (CDAR (walk)); + if (scm_is_pair (args)) + { + SCM v = CAR (args); + args = CDR (args); + scm_list_set_x (env, SCM_I_MAKINUM (iset), v); + break; + } else - break; + error_missing_value (proc, k); } - for (walk = kw; scm_is_pair (walk); walk = CDR (walk)) - if (scm_is_eq (k, CAAR (walk))) - { - /* Well... ok, list-set! isn't the nicest interface, but - hey. */ - int iset = imax - SCM_I_INUM (CDAR (walk)); - scm_list_set_x (env, SCM_I_MAKINUM (iset), v); - args = CDR (args); - break; - } - if (scm_is_null (walk) && scm_is_false (aok)) - error_unrecognized_keyword (proc, k); - } + if (scm_is_null (walk)) + { + if (scm_is_false (aok)) + error_unrecognized_keyword (proc, k); + /* Advance past argument of unknown keyword. */ + if (scm_is_pair (args)) + args = CDR (args); + } + } if (scm_is_pair (args) && scm_is_false (rest)) error_invalid_keyword (proc, CAR (args)); |