2 Syntax Object Helpers
2.1 Deconstructing Syntax Objects
Returns
#t if
v is either a pair or a syntax object
representing a pair (see
syntax pair).
Returns
#t if
v is a list, or if it is a sequence of
pairs leading to a syntax object such that
syntax->list would
produce a list.
Produces a list by flatting out a trailing syntax object using
syntax->list.
Examples: |
> (stx->list #'(a b c d)) | '(#<syntax:14:0 a> #<syntax:14:0 b> #<syntax:14:0 c> #<syntax:14:0 d>) | > (stx->list #'((a b) (c d))) | '(#<syntax:15:0 (a b)> #<syntax:15:0 (c d)>) | > (stx->list #'(a b (c d))) | '(#<syntax:16:0 a> #<syntax:16:0 b> #<syntax:16:0 (c d)>) | > (stx->list (list #'a #'b)) | '(#<syntax:17:0 a> #<syntax:17:0 b>) | > (stx->list #'a) | #f |
|
Returns
#t if
a-id and
b-id are
free-identifier=?, or if
a-id and
b-id have
the same name (as extracted by
syntax-e) and
a-id
has no binding other than at the top level.
This procedure is useful in conjunction with syntax-case* to
match procedure names that are normally bound by Racket. For
example, the include macro uses this procedure to recognize
build-path; using free-identifier=? would not work
well outside of module, since the top-level
build-path is a distinct variable from the racket/base export
(though it’s bound to the same procedure, initially).
2.2 Matching Fully-Expanded Expressions
The trans?-expr boolean expression replaces the comparison
procedure, and instead selects simply between normal-phase comparisons
or transformer-phase comparisons. The clauses are the same as in
syntax-case*.
The primitive syntactic forms must have their normal bindings in the
context of the kernel-syntax-case expression. Beware that
kernel-syntax-case does not work in a module whose language
is mzscheme, since the binding of if from
mzscheme is different than the primitive if.
A syntactic form like
kernel-syntax-case, except that it
takes an additional list of extra literals that are in addition to the
primitive Racket forms.
Generalizes
kernel-syntax-case to work at an arbitrary phase
level, as indicated by
phase-expr.
Generalizes
kernel-syntax-case* to work at an arbitrary phase
level, as indicated by
phase-expr.
Returns a list of identifiers that are bound normally,
for-syntax, and
for-template to the primitive
Racket forms for expressions, internal-definition positions, and
module-level and top-level positions. This function is useful for
generating a list of stopping points to provide to
local-expand.
In addition to the identifiers listed in Fully Expanded Programs, the list
includes letrec-syntaxes+values, which is the core form for
local expand-time binding and can appear in the result of
local-expand.
2.3 Dictionaries with Identifier Keys
This module provides two implementations of identifier tables:
dictionaries with identifier keys that use identifier-specific
comparisons instead of eq? or equal?. Identifier
tables implement the racket/dict interface, and they
are available in both mutable and immutable variants.
A free-identifier table is a dictionary whose keys are compared using
free-identifier=?. Free-identifier tables implement the
dictionary interface of racket/dict, so all of the
appropriate generic functions (dict-ref, dict-map,
etc) can be used on free-identifier tables.
Produces a mutable free-identifier table or immutable free-identifier
table, respectively. The dictionary uses
free-identifier=?
to compare keys, but also uses a hash table based on symbol equality
to make the dictionary efficient in the common case.
The identifiers are compared at phase level phase. The
default phase, (syntax-local-phase-level), is generally
appropriate for identifier tables used by macros, but code that
analyzes fully-expanded programs may need to create separate
identifier tables for each phase of the module.
The optional init-dict argument provides the initial
mappings. It must be a dictionary, and its keys must all be
identifiers. If the init-dict dictionary has multiple
distinct entries whose keys are free-identifier=?, only one
of the entries appears in the new id-table, and it is not specified
which entry is picked.
Like
hash-ref. In particular, if
id is not found,
the
failure argument is applied if it is a procedure, or
simply returned otherwise.
Returns #t if v represents a position in an
identifier table (free or bound, mutable or immutable), #f
otherwise.
Like
hash/c, but for free-identifier tables. If
immutable? is
#t, the contract accepts only
immutable identifier tables; if
immutable? is
#f,
the contract accepts only mutable identifier tables.
A bound-identifier table is a dictionary whose keys are compared using
bound-identifier=?. Bound-identifier tables implement the
dictionary interface of racket/dict, so all of the
appropriate generic functions (dict-ref, dict-map,
etc) can be used on bound-identifier tables.
This library is for backwards-compatibility. Do not use it for new
libraries; use syntax/id-table instead.
2.5 Rendering Syntax Objects with Formatting
Builds a string with newlines and indenting according to the source
locations in stx-list; the outer pair of parens are not
rendered from stx-list.
2.6 Computing the Free Variables of an Expression
Returns a list of free
lambda- and
let-bound
identifiers in
expr-stx in the order in which each
identifier first appears within
expr-stx. The expression must be fully
expanded (see
Fully Expanded Programs and
expand).
The inspector insp is used to disarm expr-stx and
sub-expressions before extracting identifiers. The default
insp is the declaration-time inspector of the
syntax/free-vars module.
2.7 Replacing Lexical Context
Removes all lexical context from stx, preserving
source-location information and properties.
Uses the lexical context of ctx-stx to replace the lexical
context of all parts of stx, preserving source-location
information and properties of stx.
2.8 Helpers for Processing Keyword Syntax
The syntax/keyword module contains procedures for
parsing keyword options in macros.
keyword-table | | = | | (dict-of keyword (listof check-procedure)) |
A keyword-table is a dictionary (dict?) mapping keywords to
lists of check-procedures. (Note that an association list is a
suitable dictionary.) The keyword’s arity is the length of the list of
procedures.
check-procedure | | = | | (syntax syntax -> any) |
A check procedure consumes the syntax to check and a context syntax
object for error reporting and either raises an error to reject the
syntax or returns a value as its parsed representation.
options | | = | | (listof (list keyword syntax-keyword any ...)) |
Parsed options are represented as an list of option entries. Each
entry contains the keyword, the syntax of the keyword (for error
reporting), and the list of parsed values returned by the keyword’s
list of check procedures. The list contains the parsed options in the
order they appeared in the input, and a keyword that occurs multiple
times in the input occurs multiple times in the options list.
Parses the keyword options in the syntax stx (stx
may be an improper syntax list). The keyword options are described in
the table association list. Each entry in table
should be a list whose first element is a keyword and whose subsequent
elements are procedures for checking the arguments following the
keyword. The keyword’s arity (number of arguments) is determined by
the number of procedures in the entry. Only fixed-arity keywords are
supported.
Parsing stops normally when the syntax list does not have a keyword at
its head (it may be empty, start with a non-keyword term, or it may be
a non-list syntax object). Two values are returned: the parsed
options and the rest of the syntax (generally either a
syntax object or a list of syntax objects).
A variety of errors and exceptional conditions can occur during the
parsing process. The following keyword arguments determine the
behavior in those situations.
The #:context ctx argument is used to report all errors in
parsing syntax. In addition, ctx is passed as the final
argument to all provided handler procedures. Macros using
parse-keyword-options should generally pass the syntax object
for the whole macro use as ctx.
If no-duplicates? is a non-false value, then duplicate
keyword options are not allowed. If a duplicate is seen, the keyword’s
associated check procedures are not called and an incompatibility is
reported.
The incompatible argument is a list of incompatibility
entries, where each entry is a list of at least two
keywords. If any keyword in the entry occurs after any other keyword
in the entry, an incompatibility is reported.
Note that including a keyword in an incompatibility entry does not
prevent it from occurring multiple times. To disallow duplicates of
some keywords (as opposed to all keywords), include those keywords in
the incompatible list as being incompatible with
themselves. That is, include them twice:
; Disallow duplicates of only the #:foo keyword |
(parse-keyword-options .... #:incompatible '((#:foo #:foo))) |
When an incompatibility occurs, the
incompatible-handler is tail-called with the two keywords
causing the incompatibility (in the order that they occurred in the
syntax list, so the keyword triggering the incompatibility occurs
second), the syntax list starting with the occurrence of the second
keyword, and the context (ctx). If the incompatibility is due
to a duplicate, the two keywords are the same.
When a keyword is not followed by enough arguments according to its
arity in table, the too-short-handler is tail-called
with the keyword, the options parsed thus far, the syntax list
starting with the occurrence of the keyword, and ctx.
When a keyword occurs in the syntax list that is not in
table, the not-in-table-handler is tail-called with
the keyword, the options parsed thus far, the syntax list
starting with the occurrence of the keyword, and ctx.
Handlers typically escape—all of the default handlers raise
errors—but if they return, they should return two values: the parsed
options and a syntax object; these are returned as the results
of parse-keyword-options.
Examples: |
| '((#:transparent #<syntax:4:0 #:transparent>) | (#:property | #<syntax:4:0 #:property> | #<syntax:4:0 p> | #<syntax:4:0 (lambda (x) (f x))>)) | '() |
| | define-struct: #:inspector option not allowed after | #:transparent option |
|
Like
parse-keyword-options, but checks that there are no
terms left over after parsing all of the keyword options. If there
are,
not-eol-handler is tail-called with the
options
parsed thus far, the leftover syntax, and
ctx.
Selects the values associated with one keyword from the parsed
options. The resulting list has as many items as there were
occurrences of the keyword, and each element is a list whose length is
the arity of the keyword.
Like
options-select, except that the given keyword must occur
either zero or one times in
options. If the keyword occurs,
the associated list of parsed argument values is returned. Otherwise,
the
default list is returned.
Like
options-select, except that the given keyword must occur
either zero or one times in
options. If the keyword occurs,
the associated list of parsed argument values must have exactly one
element, and that element is returned. If the keyword does not occur
in
options, the
default value is returned.
A
check-procedure that accepts any non-keyword term. It does
not actually check that the term is a valid expression.
Lifts a
check-procedure to accept syntax lists of whatever the
original procedure accepted.