mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-22 03:30:22 +02:00
case-lambda* clauses fail to match if too many positionals
* doc/ref/api-procedures.texi (Case-lambda): Expand case-lambda* documentation. * module/ice-9/eval.scm (primitive-eval): * libguile/eval.c (prepare_boot_closure_env_for_apply): Dispatch to the next case-lambda clause if there are too many positionals. * doc/ref/vm.texi (Function Prologue Instructions): * libguile/vm-i-system.c (bind-optionals/shuffle-or-br): New instruction, like bind-optionals/shuffle but can dispatch to the next clause if there are too many positionals. * module/language/assembly/disassemble.scm (code-annotation): * module/language/assembly/decompile-bytecode.scm (decode-load-program): * module/language/assembly/compile-bytecode.scm (compile-bytecode): Add case for bind-optionals/shuffle-or-br. * module/language/glil/compile-assembly.scm (glil->assembly): If there is an alternate, use bind-optionals/shuffle-or-br instead of bind-optionals/shuffle. * test-suite/tests/optargs.test ("case-lambda*"): Add tests.
This commit is contained in:
parent
18c5bffe96
commit
581f410fbd
10 changed files with 308 additions and 80 deletions
|
@ -599,12 +599,61 @@ A @code{case-lambda*} clause matches if the arguments fill the
|
|||
required arguments, but are not too many for the optional and/or rest
|
||||
arguments.
|
||||
|
||||
Keyword arguments are possible with @code{case-lambda*}, but they do
|
||||
not contribute to the ``matching'' behavior. That is to say,
|
||||
@code{case-lambda*} matches only on required, optional, and rest
|
||||
arguments, and on the predicate; keyword arguments may be present but
|
||||
do not contribute to the ``success'' of a match. In fact a bad keyword
|
||||
argument list may cause an error to be raised.
|
||||
Keyword arguments are possible with @code{case-lambda*} as well, but
|
||||
they do not contribute to the ``matching'' behavior, and their
|
||||
interactions with required, optional, and rest arguments can be
|
||||
surprising.
|
||||
|
||||
For the purposes of @code{case-lambda*} (and of @code{case-lambda}, as a
|
||||
special case), a clause @dfn{matches} if it has enough required
|
||||
arguments, and not too many positional arguments. The required
|
||||
arguments are any arguments before the @code{#:optional}, @code{#:key},
|
||||
and @code{#:rest} arguments. @dfn{Positional} arguments are the
|
||||
required arguments, together with the optional arguments.
|
||||
|
||||
In the absence of @code{#:key} or @code{#:rest} arguments, it's easy to
|
||||
see how there could be too many positional arguments: you pass 5
|
||||
arguments to a function that only takes 4 arguments, including optional
|
||||
arguments. If there is a @code{#:rest} argument, there can never be too
|
||||
many positional arguments: any application with enough required
|
||||
arguments for a clause will match that clause, even if there are also
|
||||
@code{#:key} arguments.
|
||||
|
||||
Otherwise, for applications to a clause with @code{#:key} arguments (and
|
||||
without a @code{#:rest} argument), a clause will match there only if
|
||||
there are enough required arguments and if the next argument after
|
||||
binding required and optional arguments, if any, is a keyword. For
|
||||
efficiency reasons, Guile is currently unable to include keyword
|
||||
arguments in the matching algorithm. Clauses match on positional
|
||||
arguments only, not by comparing a given keyword to the available set of
|
||||
keyword arguments that a function has.
|
||||
|
||||
Some examples follow.
|
||||
|
||||
@example
|
||||
(define f
|
||||
(case-lambda*
|
||||
((a #:optional b) 'clause-1)
|
||||
((a #:optional b #:key c) 'clause-2)
|
||||
((a #:key d) 'clause-3)
|
||||
((#:key e #:rest f) 'clause-4)))
|
||||
|
||||
(f) @result{} clause-4
|
||||
(f 1) @result{} clause-1
|
||||
(f) @result{} clause-4
|
||||
(f #:e 10) clause-1
|
||||
(f 1 #:foo) clause-1
|
||||
(f 1 #:c 2) clause-2
|
||||
(f #:a #:b #:c #:d #:e) clause-4
|
||||
|
||||
;; clause-2 will match anything that clause-3 would match.
|
||||
(f 1 #:d 2) @result{} error: bad keyword args in clause 2
|
||||
@end example
|
||||
|
||||
Don't forget that the clauses are matched in order, and the first
|
||||
matching clause will be taken. This can result in a keyword being bound
|
||||
to a required argument, as in the case of @code{f #:e 10}.
|
||||
|
||||
|
||||
@node Higher-Order Functions
|
||||
@subsection Higher-Order Functions
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@c -*-texinfo-*-
|
||||
@c This is part of the GNU Guile Reference Manual.
|
||||
@c Copyright (C) 2008,2009,2010
|
||||
@c Copyright (C) 2008,2009,2010,2013
|
||||
@c Free Software Foundation, Inc.
|
||||
@c See the file guile.texi for copying conditions.
|
||||
|
||||
|
@ -772,6 +772,7 @@ list. The list is then assigned to the @var{idx}th local variable.
|
|||
@end deffn
|
||||
|
||||
@deffn Instruction bind-optionals/shuffle nreq nreq-and-opt ntotal
|
||||
@deffnx Instruction bind-optionals/shuffle-or-br nreq nreq-and-opt ntotal offset
|
||||
Shuffle keyword arguments to the top of the stack, filling in the holes
|
||||
with @code{SCM_UNDEFINED}. Each argument is encoded over two bytes.
|
||||
|
||||
|
@ -783,6 +784,11 @@ the @var{nreq}th argument up to the @var{nreq-and-opt}th, and start
|
|||
shuffling when it sees the first keyword argument or runs out of
|
||||
positional arguments.
|
||||
|
||||
@code{bind-optionals/shuffle-or-br} does the same, except that it checks
|
||||
if there are too many positional arguments before shuffling. If this is
|
||||
the case, it jumps to @var{offset}, encoded using the normal three-byte
|
||||
encoding.
|
||||
|
||||
Shuffling simply moves the keyword arguments past the total number of
|
||||
arguments, @var{ntotal}, which includes keyword and rest arguments. The
|
||||
free slots created by the shuffle are filled in with
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue