Polyvalent identifiers with multi-id
(require multi-id) | package: multi-id |
This library is implemented using literate programming. The implementation details are presented in the Implementation of the multi-id library document.
This package helps defining identifiers with many different meanings in different contexts. An identifier can be given a meaning:
As a type expander (: foo (Listof (ident arg …))) (see type-expander)
As a match expander
As a macro (i.e. when it appears in the first position of a form)
As a simple identifier (i.e. used as a variable, via an identifier macro)
As a set! subform
syntax
(define-multi-id name maybe-type-expander maybe-match-expander maybe-maybe-set!+call+id fallback-clause ...)
maybe-type-expander =
| #:type-expander proc maybe-match-expander =
| #:match-expander proc maybe-set!+call+id =
| #:set!-transformer proc | else | maybe-set! maybe-call maybe-id maybe-set! = #:set! proc maybe-call = #:call proc | #:call-id identifier maybe-id = #:id proc | #:id-id identifier else = #:else-id identifier | #:mutable-else-id identifier | #:else identifier-expression | #:mutable-else identifier-expression fallback-clause = #:??? expression ??? = "any struct-type-property?, without the prop:"
In the syntax described above, each proc should be a transformer procedure accepting a single syntax? argument and returning a syntax? value, i.e. the signature of each proc should be (-> syntax? syntax?). Each identifier should be an identifier, and each identifier-expression should be a compile-time expression producing an identifier.
#:??? expression
??? = "any struct-type-property?, without the prop:" The identifier name is a struct with the prop:??? struct type property, using the given expression
In the syntax above, #:??? is only a placeholder; any keyword can be used, so long as prefixing the keyword’s name with prop: gives an identifier which is a struct-type-property?.
#:type-expander proc The identifier name acts as a type expander, using the given proc which should return the syntax for a type.
#:match-expander proc The identifier name acts as a match expander, using the given proc which should return the syntax for a match pattern.
#:set!-transformer proc The identifier name acts as a set! transformer, using the given proc which should return a syntax? value. The proc is used both when name is used in a set! form, and when it is used as a macro or identifier macro.
#:set! proc The identifier name acts as a set! transformer when it is used in a set! form, using the given proc which should return a syntax? value.
The proc is used only when name is used in a set! form, but not when it is used as a macro or identifier macro. In these cases, #:call and #:id, respectively, are used instead.
If #:id is not specified, but name is used as an identifier macro, the exn:fail:syntax exception is raised. If #:call is not specified, but name is used as a regular macro, the exn:fail:syntax exception is raised.
#:call proc The identifier name acts as a macro when it appears in the first position of a form, using the given proc which should return a syntax? value.
The proc is used only when name is used as a regular macro, but not when it is used as an identifier macro or when it is used in a set! form. In these cases, #:id and #:set!, respectively, are used instead.
If #:set! is not specified, but name is used in a set! form, the exn:fail:syntax exception is raised. If #:id is not specified, but name is used as an identifier macro, the exn:fail:syntax exception is raised.
#:call-id identifier The identifier name acts as a macro when it appears in the first position of a form. The occurrence of name is replaced by the given identifier, which should either be a function or a macro.
When name is used as a macro, i.e. in a form like (name . args), the whole form is replaced by (identifier . args). If the identifier is itself a regular macro, then the whole (identifier . args) form is expanded.
The identifier is used only when name is used as a regular macro, not when it is used as an identifier macro or as a set! transformer. In these cases, #:id and #:set!, respectively, are used instead.
If #:set! is not specified, but name is used in a set! form, the exn:fail:syntax exception is raised. If #:id is not specified, but name is used as an identifier macro, the exn:fail:syntax exception is raised.
#:id proc The identifier name acts as an identifier macro, using the given proc which should return a syntax? value.
The proc is used only when name is used as an identifier macro, but not when it appears in the first position of a form, nor when it is used in a set! form. In these cases, #:call and #:set!, respectively, are used instead.
If #:set! is not specified, but name is used in a set! form, the exn:fail:syntax exception is raised. If #:call is not specified, but name is used as a regular macro, the exn:fail:syntax exception is raised.
#:id-id proc The identifier name acts as an identifier macro. The occurrence of name is replaced by the given identifier. If the identifier is itself an identifier macro, it is expanded again.
The identifier is used only when name is used as an identifier macro, but not when it appears in the first position of a form, nor when it is used in a set! form. In these cases, #:call and #:set!, respectively, are used instead.
If #:set! is not specified, but name is used in a set! form, the exn:fail:syntax exception is raised. If #:call is not specified, but name is used as a regular macro, the exn:fail:syntax exception is raised.
#:else-id identifier The identifier name acts as a regular macro and as an identifier macro. The occurrence of name is replaced by the given identifier, which should either be a function, or be both a macro and an identifier macro at the same time.
When name is used as an identifier macro, it is replaced by identifier. If the identifier is itself an identifier macro, then it is expanded.
When name is used as a macro, i.e. in a form like (name . args), the whole form is replaced by (identifier . args). If the identifier is itself a regular macro, then the whole (identifier . args) form is expanded.
The identifier is not used when name is used in a set! form, instead the exn:fail:syntax exception is raised.
#:mutable-else-id identifier The identifier name acts as a regular macro, as an identifier macro and as a set! transformer. In all three cases, the occurrence of name is replaced by the given identifier, which should either be a function, or be a macro and an identifier macro and a set! transformer at the same time.
This option works like #:else-id, except that name can also be used in a set! form.
When name is used in a set! form like (set!. (name . vals)), the whole form is replaced by (set!. (identifier . vals)). If the identifier is itself a set! transformer, then the whole (set!. (identifier . vals)) form is expanded.
#:else identifier-expression The identifier name acts as a regular macro and as an identifier macro. The occurrence of name is replaced by the result of the compile-time expression identifier-expression, which should either produce the syntax for a function, or the syntax for an identifier which is both a macro and an identifier macro at the same time.
It is equivalent to #:else-id, except that the identifier is not constant, but is instead produced by identifier-expression. Note that identifier-expression is not a transformer function (it will not be able to access the original syntax). In other words, the compile-time contract for identifier-expression is syntax?, not (-> syntax? syntax?).
The identifier-expression is not used when name is used in a set! form, instead the exn:fail:syntax exception is raised.
#:mutable-else identifier-expression The identifier name acts as a regular macro, as an identifier macro and as a set! transformer. In all three cases, the occurrence of name is replaced by the result of the compile-time expression identifier-expression, which should either produce the syntax for a mutable identifier containing a function, or the syntax for an identifier which is a macro and an identifier macro and a set! transformer at the same time.
It is equivalent to #:mutable-else-id, except that the identifier is not constant, but is instead produced by identifier-expression. Note that identifier-expression is not a transformer function (it will not be able to access the original syntax). In other words, the compile-time contract for identifier-expression is syntax?, not (-> syntax? syntax?).