mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-02 13:00:26 +02:00
* optargs.scm: Replaced `#&' reader syntax with keywords.
This commit is contained in:
parent
83238bc162
commit
dfb49627fc
1 changed files with 35 additions and 64 deletions
|
@ -48,9 +48,9 @@
|
||||||
;;; Summary of the lambda* extended parameter list syntax (brackets
|
;;; Summary of the lambda* extended parameter list syntax (brackets
|
||||||
;;; are used to indicate grouping only):
|
;;; are used to indicate grouping only):
|
||||||
;;;
|
;;;
|
||||||
;;; ext-param-list ::= [identifier]* [#&optional [ext-var-decl]+]?
|
;;; ext-param-list ::= [identifier]* [#:optional [ext-var-decl]+]?
|
||||||
;;; [#&key [ext-var-decl]+ [#&allow-other-keys]?]?
|
;;; [#:key [ext-var-decl]+ [#:allow-other-keys]?]?
|
||||||
;;; [[#&rest identifier]|[. identifier]]?
|
;;; [[#:rest identifier]|[. identifier]]?
|
||||||
;;;
|
;;;
|
||||||
;;; ext-var-decl ::= identifier | ( identifier expression )
|
;;; ext-var-decl ::= identifier | ( identifier expression )
|
||||||
;;;
|
;;;
|
||||||
|
@ -195,44 +195,15 @@
|
||||||
accum
|
accum
|
||||||
(loop (car rest) (cdr rest) accum)))))))
|
(loop (car rest) (cdr rest) accum)))))))
|
||||||
|
|
||||||
|
;; This is a reader extension to support the (deprecated) use of
|
||||||
;; reader extensions for #&optional #&key #&allow-other-keys #&rest
|
;; "#&optional" instead of "#:optional"
|
||||||
;; These need to be quoted in normal code, but need not be in
|
|
||||||
;; an extended lambda-list provided by lambda*, define*, or
|
|
||||||
;; define*-public (see below). In other words, they act sort of like
|
|
||||||
;; symbols, except they aren't. They're being temporarily used until
|
|
||||||
;; #!optional and #!key and such are available. #&rest is provided for
|
|
||||||
;; the convenience of confused Common Lisp users, even though `.' will
|
|
||||||
;; do just as well.
|
|
||||||
|
|
||||||
(define the-optional-value
|
|
||||||
((record-constructor (make-record-type
|
|
||||||
'optional '() (lambda (o p)
|
|
||||||
(display "#&optional"))))))
|
|
||||||
|
|
||||||
(define the-key-value
|
|
||||||
((record-constructor (make-record-type
|
|
||||||
'key '() (lambda (o p)
|
|
||||||
(display "#&key"))))))
|
|
||||||
|
|
||||||
|
|
||||||
(define the-rest-value
|
|
||||||
((record-constructor (make-record-type
|
|
||||||
'rest '() (lambda (o p)
|
|
||||||
(display "#&rest" p))))))
|
|
||||||
|
|
||||||
(define the-allow-other-keys-value
|
|
||||||
((record-constructor (make-record-type
|
|
||||||
'allow-other-keys '() (lambda (o p)
|
|
||||||
(display "#&allow-other-keys" p))))))
|
|
||||||
|
|
||||||
|
|
||||||
(read-hash-extend #\& (lambda (c port)
|
(read-hash-extend #\& (lambda (c port)
|
||||||
(case (read port)
|
(case (read port)
|
||||||
((optional) the-optional-value)
|
((optional) #:optional)
|
||||||
((key) the-key-value)
|
((key) #:key)
|
||||||
((rest) the-rest-value)
|
((rest) #:rest)
|
||||||
((allow-other-keys) the-allow-other-keys-value)
|
((allow-other-keys) #:allow-other-keys-value)
|
||||||
(else (error "Bad #& value.")))))
|
(else (error "Bad #& value.")))))
|
||||||
|
|
||||||
|
|
||||||
|
@ -242,7 +213,7 @@
|
||||||
;; lambda* creates a procedure that takes optional arguments. These
|
;; lambda* creates a procedure that takes optional arguments. These
|
||||||
;; are specified by putting them inside brackets at the end of the
|
;; are specified by putting them inside brackets at the end of the
|
||||||
;; paramater list, but before any dotted rest argument. For example,
|
;; paramater list, but before any dotted rest argument. For example,
|
||||||
;; (lambda* (a b #&optional c d . e) '())
|
;; (lambda* (a b #:optional c d . e) '())
|
||||||
;; creates a procedure with fixed arguments a and b, optional arguments c
|
;; creates a procedure with fixed arguments a and b, optional arguments c
|
||||||
;; and d, and rest argument e. If the optional arguments are omitted
|
;; and d, and rest argument e. If the optional arguments are omitted
|
||||||
;; in a call, the variables for them are unbound in the procedure. This
|
;; in a call, the variables for them are unbound in the procedure. This
|
||||||
|
@ -250,7 +221,7 @@
|
||||||
;;
|
;;
|
||||||
;; lambda* can also take keyword arguments. For example, a procedure
|
;; lambda* can also take keyword arguments. For example, a procedure
|
||||||
;; defined like this:
|
;; defined like this:
|
||||||
;; (lambda* (#&key xyzzy larch) '())
|
;; (lambda* (#:key xyzzy larch) '())
|
||||||
;; can be called with any of the argument lists (#:xyzzy 11)
|
;; can be called with any of the argument lists (#:xyzzy 11)
|
||||||
;; (#:larch 13) (#:larch 42 #:xyzzy 19) (). Whichever arguments
|
;; (#:larch 13) (#:larch 42 #:xyzzy 19) (). Whichever arguments
|
||||||
;; are given as keywords are bound to values.
|
;; are given as keywords are bound to values.
|
||||||
|
@ -258,7 +229,7 @@
|
||||||
;; Optional and keyword arguments can also be given default values
|
;; Optional and keyword arguments can also be given default values
|
||||||
;; which they take on when they are not present in a call, by giving a
|
;; which they take on when they are not present in a call, by giving a
|
||||||
;; two-item list in place of an optional argument, for example in:
|
;; two-item list in place of an optional argument, for example in:
|
||||||
;; (lambda* (foo #&optional (bar 42) #&key (baz 73)) (list foo bar baz))
|
;; (lambda* (foo #:optional (bar 42) #:key (baz 73)) (list foo bar baz))
|
||||||
;; foo is a fixed argument, bar is an optional argument with default
|
;; foo is a fixed argument, bar is an optional argument with default
|
||||||
;; value 42, and baz is a keyword argument with default value 73.
|
;; value 42, and baz is a keyword argument with default value 73.
|
||||||
;; Default value expressions are not evaluated unless they are needed
|
;; Default value expressions are not evaluated unless they are needed
|
||||||
|
@ -268,17 +239,17 @@
|
||||||
;;
|
;;
|
||||||
;; lambda*-defined procedures now throw an error by default if a
|
;; lambda*-defined procedures now throw an error by default if a
|
||||||
;; keyword other than one of those specified is found in the actual
|
;; keyword other than one of those specified is found in the actual
|
||||||
;; passed arguments. However, specifying #&allow-other-keys
|
;; passed arguments. However, specifying #:allow-other-keys
|
||||||
;; immediately after the kyword argument declarations restores the
|
;; immediately after the kyword argument declarations restores the
|
||||||
;; previous behavior of ignoring unknown keywords. lambda* also now
|
;; previous behavior of ignoring unknown keywords. lambda* also now
|
||||||
;; guarantees that if the same keyword is passed more than once, the
|
;; guarantees that if the same keyword is passed more than once, the
|
||||||
;; last one passed is the one that takes effect. For example,
|
;; last one passed is the one that takes effect. For example,
|
||||||
;; ((lambda* (#&key (heads 0) (tails 0)) (display (list heads tails)))
|
;; ((lambda* (#:key (heads 0) (tails 0)) (display (list heads tails)))
|
||||||
;; #:heads 37 #:tails 42 #:heads 99)
|
;; #:heads 37 #:tails 42 #:heads 99)
|
||||||
;; would result in (99 47) being displayed.
|
;; would result in (99 47) being displayed.
|
||||||
;;
|
;;
|
||||||
;; #&rest is also now provided as a synonym for the dotted syntax rest
|
;; #:rest is also now provided as a synonym for the dotted syntax rest
|
||||||
;; argument. The argument lists (a . b) and (a #&rest b) are equivalent in
|
;; argument. The argument lists (a . b) and (a #:rest b) are equivalent in
|
||||||
;; all respects to lambda*. This is provided for more similarity to DSSSL,
|
;; all respects to lambda*. This is provided for more similarity to DSSSL,
|
||||||
;; MIT-Scheme and Kawa among others, as well as for refugees from other
|
;; MIT-Scheme and Kawa among others, as well as for refugees from other
|
||||||
;; Lisp dialects.
|
;; Lisp dialects.
|
||||||
|
@ -345,27 +316,27 @@
|
||||||
(else (cont lst '() #f))))
|
(else (cont lst '() #f))))
|
||||||
(define (parse-opt-and-fixed arglist keys aok? rest cont)
|
(define (parse-opt-and-fixed arglist keys aok? rest cont)
|
||||||
(split-list-at
|
(split-list-at
|
||||||
'#&optional arglist
|
#:optional arglist
|
||||||
(lambda (before after split?)
|
(lambda (before after split?)
|
||||||
(if (and split? (null? after))
|
(if (and split? (null? after))
|
||||||
(error "#&optional specified but no optional arguments declared.")
|
(error "#:optional specified but no optional arguments declared.")
|
||||||
(cont before after keys aok? rest)))))
|
(cont before after keys aok? rest)))))
|
||||||
(define (parse-keys arglist rest cont)
|
(define (parse-keys arglist rest cont)
|
||||||
(split-list-at
|
(split-list-at
|
||||||
'#&allow-other-keys arglist
|
#:allow-other-keys arglist
|
||||||
(lambda (aok-before aok-after aok-split?)
|
(lambda (aok-before aok-after aok-split?)
|
||||||
(if (and aok-split? (not (null? aok-after)))
|
(if (and aok-split? (not (null? aok-after)))
|
||||||
(error "#&allow-other-keys not at end of keyword argument declarations.")
|
(error "#:allow-other-keys not at end of keyword argument declarations.")
|
||||||
(split-list-at
|
(split-list-at
|
||||||
'#&key aok-before
|
#:key aok-before
|
||||||
(lambda (key-before key-after key-split?)
|
(lambda (key-before key-after key-split?)
|
||||||
(cond
|
(cond
|
||||||
((and aok-split? (not key-split?))
|
((and aok-split? (not key-split?))
|
||||||
(error "#&allow-other-keys specified but no keyword arguments declared."))
|
(error "#:allow-other-keys specified but no keyword arguments declared."))
|
||||||
(key-split?
|
(key-split?
|
||||||
(cond
|
(cond
|
||||||
((null? key-after) (error "#&key specified but no keyword arguments declared."))
|
((null? key-after) (error "#:key specified but no keyword arguments declared."))
|
||||||
((memq '#&optional key-after) (error "#&optional arguments declared after #&key arguments."))
|
((memq #:optional key-after) (error "#:optional arguments declared after #:key arguments."))
|
||||||
(else (parse-opt-and-fixed key-before key-after aok-split? rest cont))))
|
(else (parse-opt-and-fixed key-before key-after aok-split? rest cont))))
|
||||||
(else (parse-opt-and-fixed arglist '() #f rest cont)))))))))
|
(else (parse-opt-and-fixed arglist '() #f rest cont)))))))))
|
||||||
(define (parse-rest arglist cont)
|
(define (parse-rest arglist cont)
|
||||||
|
@ -377,17 +348,17 @@
|
||||||
(lp (last-pair copy))
|
(lp (last-pair copy))
|
||||||
(ra (cdr lp)))
|
(ra (cdr lp)))
|
||||||
(set-cdr! lp '())
|
(set-cdr! lp '())
|
||||||
(if (memq '#&rest copy)
|
(if (memq #:rest copy)
|
||||||
(error "Cannot specify both #&rest and dotted rest argument.")
|
(error "Cannot specify both #:rest and dotted rest argument.")
|
||||||
(parse-keys copy ra cont))))
|
(parse-keys copy ra cont))))
|
||||||
(else (split-list-at
|
(else (split-list-at
|
||||||
'#&rest arglist
|
#:rest arglist
|
||||||
(lambda (before after split?)
|
(lambda (before after split?)
|
||||||
(if split?
|
(if split?
|
||||||
(case (length after)
|
(case (length after)
|
||||||
((0) (error "#&rest not followed by argument."))
|
((0) (error "#:rest not followed by argument."))
|
||||||
((1) (parse-keys before (car after) cont))
|
((1) (parse-keys before (car after) cont))
|
||||||
(else (error "#&rest argument must be declared last.")))
|
(else (error "#:rest argument must be declared last.")))
|
||||||
(parse-keys before #f cont)))))))
|
(parse-keys before #f cont)))))))
|
||||||
|
|
||||||
(parse-rest arglist cont))
|
(parse-rest arglist cont))
|
||||||
|
@ -401,16 +372,16 @@
|
||||||
;; define* and define*-public support optional arguments with
|
;; define* and define*-public support optional arguments with
|
||||||
;; a similar syntax to lambda*. They also support arbitrary-depth
|
;; a similar syntax to lambda*. They also support arbitrary-depth
|
||||||
;; currying, just like Guile's define. Some examples:
|
;; currying, just like Guile's define. Some examples:
|
||||||
;; (define* (x y #&optional a (z 3) #&key w . u) (display (list y z u)))
|
;; (define* (x y #:optional a (z 3) #:key w . u) (display (list y z u)))
|
||||||
;; defines a procedure x with a fixed argument y, an optional agument
|
;; defines a procedure x with a fixed argument y, an optional agument
|
||||||
;; a, another optional argument z with default value 3, a keyword argument w,
|
;; a, another optional argument z with default value 3, a keyword argument w,
|
||||||
;; and a rest argument u.
|
;; and a rest argument u.
|
||||||
;; (define-public* ((foo #&optional bar) #&optional baz) '())
|
;; (define-public* ((foo #:optional bar) #:optional baz) '())
|
||||||
;; This illustrates currying. A procedure foo is defined, which,
|
;; This illustrates currying. A procedure foo is defined, which,
|
||||||
;; when called with an optional argument bar, returns a procedure that
|
;; when called with an optional argument bar, returns a procedure that
|
||||||
;; takes an optional argument baz.
|
;; takes an optional argument baz.
|
||||||
;;
|
;;
|
||||||
;; Of course, define*[-public] also supports #&rest and #&allow-other-keys
|
;; Of course, define*[-public] also supports #:rest and #:allow-other-keys
|
||||||
;; in the same way as lambda*.
|
;; in the same way as lambda*.
|
||||||
|
|
||||||
(defmacro-public define* (ARGLIST . BODY)
|
(defmacro-public define* (ARGLIST . BODY)
|
||||||
|
@ -442,10 +413,10 @@
|
||||||
;; defmacro and defmacro-public extended for optional and keyword arguments
|
;; defmacro and defmacro-public extended for optional and keyword arguments
|
||||||
;;
|
;;
|
||||||
;; These are just like defmacro and defmacro-public except that they
|
;; These are just like defmacro and defmacro-public except that they
|
||||||
;; take lambda*-style extended paramter lists, where #&optional,
|
;; take lambda*-style extended paramter lists, where #:optional,
|
||||||
;; #&key, #&allow-other-keys and #&rest are allowed with the usual
|
;; #:key, #:allow-other-keys and #:rest are allowed with the usual
|
||||||
;; semantics. Here is an example of a macro with an optional argument:
|
;; semantics. Here is an example of a macro with an optional argument:
|
||||||
;; (defmacro* transmorgify (a #&optional b)
|
;; (defmacro* transmorgify (a #:optional b)
|
||||||
|
|
||||||
(defmacro-public defmacro* (NAME ARGLIST . BODY)
|
(defmacro-public defmacro* (NAME ARGLIST . BODY)
|
||||||
(defmacro*-guts 'define NAME ARGLIST BODY))
|
(defmacro*-guts 'define NAME ARGLIST BODY))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue