Next: , Up: lang   [Index]


1.1 More facilities for keyword objects

Keywords are disjoint objects which can be read by Vicare’s reader in #!vicare mode, (vicare-scheme)iklib reader stx. The core bindings and keyword objects handling is embedded in Vicare’s boot image, but additional facilities are required to make use of keywords.

The following bindings are exported by the library (vicare language-extensions keywords). Additionally the following bindings are reexported from (vicare):

symbol->keyword         keyword->symbol
keyword?                keyword=?
keyword-hash
Syntax: let-keywords ?input ?args ?allow ?options-spec ?form0 ?form ...
Syntax: let*-keywords ?input ?args ?allow ?options-spec ?form0 ?form ...
Syntax: letrec-keywords ?input ?args ?allow ?options-spec ?form0 ?form ...
Syntax: letrec*-keywords ?input ?args ?allow ?options-spec ?form0 ?form ...
Auxiliary Syntax: with-argument ?name ?default ?keyword
Auxiliary Syntax: without-argument ?name ?default ?keyword ?when-given

Expand into a let like form whose bindings are configured from a list of arguments and options.

let-keywords expands into a let syntax, let*-keywords expands into a let* syntax, letrec-keywords expands into a letrec syntax, letrec*-keywords expands into a letrec* syntax.

?input must be an expression evaluating to a list of values and keywords; keywords must be compliant to the specification in ?options-spec. The same keyword can be present multiple times in ?input.

?args must be an identifier which will be bound to a list of values from ?input not matching any of the options specified in ?options-spec.

?allow must be an expression meant to evaluate to #f or true; when #f: keyword values in ?input not matched by specifications in ?options-spec will cause an assertion violation; when true: keyword values in ?input not matched by specifications in ?options-spec will be collected in ?args.

?options-spec must be null or a list of lists, each with the following formats:

(with-argument ?name ?default ?keyword)
(without-argument ?name ?default ?keyword ?when-given)

such specifications are interpreted as follows:

We can imagine the following macro use:

(let-keywords ?input args #f
    ((with-argument a 1 #:a)
     (with-argument b 2 #:b))
  (alpha)
  (beta))

to expand to something like:

(let ((a 1)
      (b 2))
  (let ((args ?options-parser))
    (alpha)
    (beta)))

where ?options-parser is a form which takes care of parsing the ?input.

Examples:

#!vicare
(import (vicare)
  (vicare language-extensions keywords))

;; options with arguments
(let-keywords '(#:a 1 #:b 2 #:d 4) args #f
    ((with-argument a #\a #:a)
     (with-argument b #\b #:b)
     (with-argument c #\c #:c)
     (with-argument d #\d #:d))
  (list a b c d args))
⇒ (1 2 #\c 4 ())

;; options without arguments
(let-keywords '(#:a #:b #:d 4) args #f
    ((without-argument a #\a #:a #\A)
     (without-argument b #\b #:b #\B)
     (without-argument c #\c #:c #\C)
     (with-argument d #\d #:d))
  (list a b c d args))
⇒ (#\A #\B #\c 4 ())

;; options with arguments, leftover arguments
(let-keywords '(#:a 1 ciao #:b 2 hello #:d 4) args #f
    ((with-argument a #\a #:a)
     (with-argument b #\b #:b)
     (with-argument c #\c #:c)
     (with-argument d #\d #:d))
  (list a b c d args))
⇒ (1 2 #\c 4 (ciao hello))

;; no options, allow unknown
(let-keywords '(#:a 1 #:b 2 #:d 4) args #t
    ()
  args)
⇒ (#:a 1 #:b 2 #:d 4)

(let-keywords '(#:a) args #f
    ()
  args)
error→ unknown option #:a

(let-keywords '(#:a #:b 123) args #t
    ((with-argument a 1 #:a)
     (with-argument b 2 #:b))
  args)
error→ option value for #:a cannot be a keyword

(let-keywords '(#:a) args #t
    ((with-argument a 1 #:a)
     (with-argument b 2 #:b))
  args)
error→ option #:a requires argument

;; keywords used multiple times
(let-keywords '(#:verbose #:verbose #:verbose) args #f
  ((without-argument verbosity 0 #:verbose (+ 1 verbosity)))
  verbosity)
⇒ 3

Next: , Up: lang   [Index]