1
Fork 0
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:
Marius Vollmer 2000-08-16 19:30:07 +00:00
parent 83238bc162
commit dfb49627fc

View file

@ -48,9 +48,9 @@
;;; Summary of the lambda* extended parameter list syntax (brackets
;;; are used to indicate grouping only):
;;;
;;; ext-param-list ::= [identifier]* [#&optional [ext-var-decl]+]?
;;; [#&key [ext-var-decl]+ [#&allow-other-keys]?]?
;;; [[#&rest identifier]|[. identifier]]?
;;; ext-param-list ::= [identifier]* [#:optional [ext-var-decl]+]?
;;; [#:key [ext-var-decl]+ [#:allow-other-keys]?]?
;;; [[#:rest identifier]|[. identifier]]?
;;;
;;; ext-var-decl ::= identifier | ( identifier expression )
;;;
@ -195,44 +195,15 @@
accum
(loop (car rest) (cdr rest) accum)))))))
;; reader extensions for #&optional #&key #&allow-other-keys #&rest
;; 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))))))
;; This is a reader extension to support the (deprecated) use of
;; "#&optional" instead of "#:optional"
(read-hash-extend #\& (lambda (c port)
(case (read port)
((optional) the-optional-value)
((key) the-key-value)
((rest) the-rest-value)
((allow-other-keys) the-allow-other-keys-value)
((optional) #:optional)
((key) #:key)
((rest) #:rest)
((allow-other-keys) #:allow-other-keys-value)
(else (error "Bad #& value.")))))
@ -242,7 +213,7 @@
;; lambda* creates a procedure that takes optional arguments. These
;; are specified by putting them inside brackets at the end of the
;; 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
;; 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
@ -250,7 +221,7 @@
;;
;; lambda* can also take keyword arguments. For example, a procedure
;; defined like this:
;; (lambda* (#&key xyzzy larch) '())
;; (lambda* (#:key xyzzy larch) '())
;; can be called with any of the argument lists (#:xyzzy 11)
;; (#:larch 13) (#:larch 42 #:xyzzy 19) (). Whichever arguments
;; are given as keywords are bound to values.
@ -258,7 +229,7 @@
;; 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
;; 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
;; value 42, and baz is a keyword argument with default value 73.
;; 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
;; 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
;; previous behavior of ignoring unknown keywords. lambda* also now
;; guarantees that if the same keyword is passed more than once, the
;; 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)
;; would result in (99 47) being displayed.
;;
;; #&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
;; #: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
;; 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
;; Lisp dialects.
@ -345,27 +316,27 @@
(else (cont lst '() #f))))
(define (parse-opt-and-fixed arglist keys aok? rest cont)
(split-list-at
'#&optional arglist
#:optional arglist
(lambda (before after split?)
(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)))))
(define (parse-keys arglist rest cont)
(split-list-at
'#&allow-other-keys arglist
#:allow-other-keys arglist
(lambda (aok-before aok-after aok-split?)
(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
'#&key aok-before
#:key aok-before
(lambda (key-before key-after key-split?)
(cond
((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?
(cond
((null? key-after) (error "#&key specified but no keyword arguments declared."))
((memq '#&optional key-after) (error "#&optional arguments declared after #&key arguments."))
((null? key-after) (error "#:key specified but no keyword arguments declared."))
((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 arglist '() #f rest cont)))))))))
(define (parse-rest arglist cont)
@ -377,17 +348,17 @@
(lp (last-pair copy))
(ra (cdr lp)))
(set-cdr! lp '())
(if (memq '#&rest copy)
(error "Cannot specify both #&rest and dotted rest argument.")
(if (memq #:rest copy)
(error "Cannot specify both #:rest and dotted rest argument.")
(parse-keys copy ra cont))))
(else (split-list-at
'#&rest arglist
#:rest arglist
(lambda (before after split?)
(if split?
(case (length after)
((0) (error "#&rest not followed by argument."))
((0) (error "#:rest not followed by argument."))
((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-rest arglist cont))
@ -401,16 +372,16 @@
;; define* and define*-public support optional arguments with
;; a similar syntax to lambda*. They also support arbitrary-depth
;; 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
;; a, another optional argument z with default value 3, a keyword argument w,
;; 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,
;; when called with an optional argument bar, returns a procedure that
;; 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*.
(defmacro-public define* (ARGLIST . BODY)
@ -442,10 +413,10 @@
;; defmacro and defmacro-public extended for optional and keyword arguments
;;
;; These are just like defmacro and defmacro-public except that they
;; take lambda*-style extended paramter lists, where #&optional,
;; #&key, #&allow-other-keys and #&rest are allowed with the usual
;; take lambda*-style extended paramter lists, where #:optional,
;; #:key, #:allow-other-keys and #:rest are allowed with the usual
;; 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*-guts 'define NAME ARGLIST BODY))