From 8470b614669a3c57f11f329e07c86459ab588e45 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Tue, 10 Jul 2007 07:08:16 +0000 Subject: [PATCH] doc work: reference on syntax objects svn: r6882 --- collects/scribble/manual.ss | 21 +- collects/scribble/scheme.ss | 1 + collects/scribblings/reference/ellipses.ss | 15 + collects/scribblings/reference/macros.scrbl | 15 +- .../scribblings/reference/reference.scrbl | 1 + collects/scribblings/reference/stx-comp.scrbl | 138 +++++++ collects/scribblings/reference/stx-ops.scrbl | 206 ++++++++++ .../scribblings/reference/stx-patterns.scrbl | 375 ++++++++++++++++++ .../scribblings/reference/syntax-model.scrbl | 18 +- collects/scribblings/reference/syntax.scrbl | 32 +- 10 files changed, 805 insertions(+), 17 deletions(-) create mode 100644 collects/scribblings/reference/ellipses.ss create mode 100644 collects/scribblings/reference/stx-comp.scrbl create mode 100644 collects/scribblings/reference/stx-ops.scrbl create mode 100644 collects/scribblings/reference/stx-patterns.scrbl diff --git a/collects/scribble/manual.ss b/collects/scribble/manual.ss index 998ca24405..287d86d429 100644 --- a/collects/scribble/manual.ss +++ b/collects/scribble/manual.ss @@ -192,6 +192,7 @@ (provide defproc defproc* defstruct defthing defparam defboolparam defform defform* defform/subs defform*/subs defform/none + defidform specform specform/subs specsubform specsubform/subs specspecsubform specspecsubform/subs specsubform/inline schemegrammar schemegrammar* @@ -311,6 +312,15 @@ '(spec) (list (lambda (ignored) (schemeblock0 spec))) null null (lambda () (list desc ...)))])) + (define-syntax (defidform stx) + (syntax-case stx () + [(_ spec-id desc ...) + #'(*defforms (quote-syntax spec-id) null + '(spec-id) + (list (lambda (x) (make-paragraph (list x)))) + null + null + (lambda () (list desc ...)))])) (define-syntax specsubform (syntax-rules () [(_ #:literals (lit ...) spec desc ...) @@ -837,7 +847,11 @@ (apply append (map (lambda (form) - (let loop ([form (cons (if kw-id (cdr form) form) + (let loop ([form (cons (if kw-id + (if (pair? form) + (cdr form) + null) + form) subs)]) (cond [(symbol? form) (if (or (meta-symbol? form) @@ -869,7 +883,10 @@ (eq? form (car forms)) (make-target-element #f - (list (to-element (make-just-context (car form) kw-id))) + (list (to-element (make-just-context (if (pair? form) + (car form) + form) + kw-id))) (register-scheme-form-definition kw-id)))))))) forms form-procs) (if (null? sub-procs) diff --git a/collects/scribble/scheme.ss b/collects/scribble/scheme.ss index 74622b0a24..78e2744989 100644 --- a/collects/scribble/scheme.ss +++ b/collects/scribble/scheme.ss @@ -363,6 +363,7 @@ (let ([c (syntax-e c)]) (let ([s (format "~s" c)]) (if (and (symbol? c) + ((string-length s) . > . 1) (char=? (string-ref s 0) #\_)) (values (substring s 1) #t #f) (values s #f #f))))] diff --git a/collects/scribblings/reference/ellipses.ss b/collects/scribblings/reference/ellipses.ss new file mode 100644 index 0000000000..04f284f7d3 --- /dev/null +++ b/collects/scribblings/reference/ellipses.ss @@ -0,0 +1,15 @@ +(module ellipses (lib "lang.ss" "big") + (require (lib "manual.ss" "scribble")) + + (provide ellipses-defn + ellipses-id) + + (define-syntax ... #'no) + + (define-syntax ellipses-defn + (syntax-rules () + [(_ . body) + (defidform (... ...) . body)])) + + (define ellipses-id + (scheme ...))) diff --git a/collects/scribblings/reference/macros.scrbl b/collects/scribblings/reference/macros.scrbl index 7dc4c19a2b..670e1b48d1 100644 --- a/collects/scribblings/reference/macros.scrbl +++ b/collects/scribblings/reference/macros.scrbl @@ -1,4 +1,17 @@ #reader(lib "docreader.ss" "scribble") @require["mz.ss"] -@title{Macros} +@title[#:style 'toc]{Macros} + +See @secref["mz:syntax-model"] for general information on how programs +are parsed. In particular, the subsection @secref["mz:expand-steps"] +describes how parsing triggers macros, and +@secref["mz:transformer-model"] describes how macro transformers are +called. + +@local-table-of-contents[] + +@include-section["stx-patterns.scrbl"] +@include-section["stx-ops.scrbl"] +@include-section["stx-comp.scrbl"] + diff --git a/collects/scribblings/reference/reference.scrbl b/collects/scribblings/reference/reference.scrbl index f95b14bad1..f126d6165a 100644 --- a/collects/scribblings/reference/reference.scrbl +++ b/collects/scribblings/reference/reference.scrbl @@ -21,6 +21,7 @@ language. @include-section["struct.scrbl"] @include-section["control.scrbl"] @include-section["concurrency.scrbl"] +@include-section["macros.scrbl"] @include-section["security.scrbl"] @include-section["io.scrbl"] @include-section["os.scrbl"] diff --git a/collects/scribblings/reference/stx-comp.scrbl b/collects/scribblings/reference/stx-comp.scrbl new file mode 100644 index 0000000000..d2c35dcbaf --- /dev/null +++ b/collects/scribblings/reference/stx-comp.scrbl @@ -0,0 +1,138 @@ +#reader(lib "docreader.ss" "scribble") +@require["mz.ss"] + +@title[#:tag "mz:stxcmp"]{Syntax Object Bindings} + +@defproc[(bound-identifier=? [a-id syntax?][b-id syntax?]) boolean?]{ + +Returns @scheme[#t] if the identifier @scheme[a-id] would bind +@scheme[b-id] (or vice-versa) if the identifiers were substituted in a +suitable expression context, @scheme[#f] otherwise.} + + +@defproc[(free-identifier=? [a-id syntax?][b-id syntax?]) boolean?]{ + +Returns @scheme[#t] if @scheme[a-id] and @scheme[b-id] access the same +lexical, module, or top-level binding at @tech{phase level} 0. ``Same +module binding'' means that the identifiers refer to the same original +definition site, not necessarily the @scheme[require] or +@scheme[provide] site. Due to renaming in @scheme[require] and +@scheme[provide], the identifiers may return distinct results with +@scheme[syntax-e].} + + +@defproc[(free-transformer-identifier=? [a-id syntax?][b-id syntax?]) boolean?]{ + +Returns @scheme[#t] if @scheme[a-id] and @scheme[b-id] access the same +lexical, module, or top-level binding at @tech{phase level} 1 (see +@secref["mz:id-model"]).} + + +@defproc[(free-template-identifier=? [a-id syntax?][b-id syntax?]) boolean?]{ + +Returns @scheme[#t] if @scheme[a-id] and @scheme[b-id] access the same +lexical or module binding at @tech{phase level} -1 (see +@secref["mz:id-model"]).} + + +@defproc[(check-duplicate-identifier [ids (listof identifier?)]) + (or/c identifier? false/c)]{ + +Compares each identifier in @scheme[ids] with every other identifier +in the list with @scheme[bound-identifier=?]. If any comparison +returns @scheme[#t], one of the duplicate identifiers is returned (the +first one in @scheme[ids] that is a duplicate), otherwise the result +is @scheme[#f].} + + +@defproc[(identifier-binding [id-stx syntax?]) + (or/c (one-of 'lexical #f) + (listof (or/c module-path-index? symbol?) + symbol? + (or/c module-path-index? symbol?) + symbol? + boolean?))]{ + +Returns one of three kinds of values, depending on the binding of +@scheme[id-stx] at @tech{phase level} 0: + +@itemize{ + + @item{The result is @scheme['lexical] if @scheme[id-stx] has + a @tech{local binding}. + + @item{The result is a list of five items when @scheme[id-stx] + has a @tech{module binding}: @scheme[(list source-mod source-id + nominal-source-mod nominal-source-id et?)]. + + @itemize{ + + @item{@scheme[source-mod] is a module path index or symbol (see + @secref["mz:modpathidx"]) that indicates the defining module.} + + @item{@scheme[source-id] is a symbol for the identifier's name + at its definition site in the source module. This can be + different from the local name returned by + @scheme[syntax->datum] for several reasons: the identifier is + renamed on import, it is renamed on export, or it is + implicitly renamed because the identifier (or its import) was + generated by a macro invocation.} + + @item{@scheme[nominal-source-mod] is a module path index or + symbol (see @secref["mz:modpathidx"]) that indicates the + module @scheme[require]d into the context of @scheme[id-stx] + to provide its binding. It can be different from + @scheme[source-mod] due to a re-export in + @scheme[nominal-source-mod] of some imported identifier.} + + @item{@scheme[nominal-source-id] is a symbol for the + identifier's name as exported by + @scheme[nominal-source-mod]. It can be different from + @scheme[source-id] due to a renaming @scheme[provide], even if + @scheme[source-mod] and @scheme[nominal-source-mod] are the + same.} + + @item{@scheme[et?] is @scheme[#t] if the source definition is + for-syntax, @scheme[#f] otherwise.} + + }}} + + @item{The result is @scheme[#f] if @scheme[id-stx] + has a @tech{top-level binding}.} + + }} + +@defproc[(identifier-transformer-binding [id-stx syntax?]) + (or/c (one-of 'lexical #f) + (listof (or/c module-path-index? symbol?) + symbol? + (or/c module-path-index? symbol?) + symbol? + boolean?))]{ + +Like @scheme[identifier-binding], but that the reported information is +for the identifier's binding in @tech{phase level} 1 (see +@secref["mz:id-model"]). + +If the result is @scheme['lexical] for either of +@scheme[identifier-binding] or +@scheme[identifier-transformer-binding], then the result is always +@scheme['lexical] for both.} + + +@defproc[(identifier-template-binding [id-stx syntax?]) + (or/c (one-of 'lexical #f) + (listof (or/c module-path-index? symbol?) + symbol? + (or/c module-path-index? symbol?) + symbol? + boolean?))]{ + +Like @scheme[identifier-binding], but that the reported information is +for the identifier's binding in @tech{phase level} -1 (see +@secref["mz:id-model"]). + +If the result is @scheme['lexical] for either of +@scheme[identifier-binding] or +@scheme[identifier-template-binding], then the result is always +@scheme['lexical] for both.} diff --git a/collects/scribblings/reference/stx-ops.scrbl b/collects/scribblings/reference/stx-ops.scrbl new file mode 100644 index 0000000000..11f59b0c8a --- /dev/null +++ b/collects/scribblings/reference/stx-ops.scrbl @@ -0,0 +1,206 @@ +#reader(lib "docreader.ss" "scribble") +@require["mz.ss"] + +@title[#:tag "mz:stxops"]{Syntax Object Content} + +@defproc[(syntax? [v any/c]) boolean?]{ + +Returns @scheme[#t] if @scheme[v] is a @tech{syntax object}, @scheme[#f] +otherwise. See also @secref["mz:stxobj-model"].} + +@defproc[(syntax-source [stx syntax?]) any]{ + +Returns the source for the syntax object @scheme[stx], or @scheme[#f] +if none is known. The source is represented by an arbitrary value +(e.g., one passed to @scheme[read-syntax]), but it is typically a file +path string. See also @secref["mz:compilation"].} + + +@defproc[(syntax-line [stx syntax?]) + (or/c positive-exact-integer? + false/c)]{ + +Returns the line number (positive exact integer) for the start of the +syntax object in its source, or @scheme[#f] if the line number or +source is unknown. The result is @scheme[#f] if and only if +@scheme[(syntax-column stx)] produces @scheme[#f]. See also +@secref["mz:linecol"] and @secref["mz:compilation"].} + + +@defproc[(syntax-column [stx syntax?]) + (or/c nonnegative-exact-integer? + false/c)]{ + +Returns the column number (non-negative exact integer) for the start +of the syntax object in its source, or @scheme[#f] if the source +column is unknown. The result is @scheme[#f] if and only if +@scheme[(syntax-line stx)] produces @scheme[#f]. See also +@secref["mz:linecol"] and @secref["mz:compilation"].} + + +@defproc[(syntax-position [stx syntax?]) + (or/c positive-exact-integer? + false/c)]{ + +Returns the character position (positive exact integer) for the start +of the syntax object in its source, or @scheme[#f] if the source +position is unknown. See also @secref["mz:linecol"] and +@secref["mz:compilation"].} + + +@defproc[(syntax-span [stx syntax?]) + (or/c nonnegative-exact-integer? + false/c)]{ + +Returns the span (non-negative exact integer) in characters of the +syntax object in its source, or @scheme[#f] if the span is +unknown. See also @secref["mz:compilation"].} + + +@defproc[(syntax-original? [stx syntax?]) boolean?]{ + +Returns @scheme[#t] if @scheme[stx] has the property that +@scheme[read-syntax] and @scheme[read-honu-syntax] attach to the +syntax objects that they generate (see @secref["mz:stxprops"]), and if +@scheme[stx]'s lexical information does not indicate that the object +was introduced by a syntax transformer (see +@secref["mz:stxscope"]). The result is @scheme[#f] otherwise. This +predicate can be used to distinguish syntax objects in an expanded +expression that were directly present in the original expression, as +opposed to syntax objects inserted by macros.} + + +@defproc[(syntax-source-module [stx syntax?]) + (or/c module-path-index? symbol?)]{ + +Returns a module path index or symbol (see @secref["mz:modpathidx"]) +for the module whose source contains @scheme[stx], or @scheme[#f] if +@scheme[stx] has no source module.} + + +@defproc[(syntax-e [stx syntax?]) any]{ + +Unwraps the immediate datum structure from a syntax object, +leaving nested syntax structure (if any) in place. The result of +@scheme[(syntax-e @scheme[stx])] is one of the following: + + @itemize{ + + @item{a symbol} + + @item{a @tech{syntax pair} (described below)} + + @item{the empty list} + + @item{a vector containing syntax objects} + + @item{some other kind of datum---usually a number, boolean, or string} + + } + +A @deftech{syntax pair} is a pair containing a syntax object as its +first element, and either the empty list, a syntax pair, or a syntax +object as its second element. + +A syntax object that is the result of @scheme[read-syntax] reflects +the use of delimited @litchar{.} in the input by creating a syntax +object for every pair of parentheses in the source, and by creating a +pair-valued syntax object @italic{only} for parentheses in the +source. See @secref["mz:parse-pair"] for more information.} + + +@defproc[(syntax->list [stx syntax?]) + (or/c list? false/c)]{ + +Returns an immutable list of syntax objects or @scheme[#f]. The result +is a list of syntax objects when @scheme[(syntax->datum stx)] +would produce a list. In other words, @tech{syntax pairs} in +@scheme[(syntax-e @scheme[stx])] are flattened.} + + +@defproc[(syntax->datum [stx syntax?]) any]{ + +Returns a datum by stripping the lexical and source-location +information from @scheme[stx]. Graph structure is preserved by the +conversion.} + + +@defproc[(datum->syntax [ctxt (or/c syntax? false/c)] + [v any/c] + [srcloc (or/c syntax? false/c + (list/c any/c + (or/c positive-exact-integer? false/c) + (or/c nonnegative-exact-integer? false/c) + (or/c nonnegative-exact-integer? false/c) + (or/c positive-exact-integer? false/c)))] + [prop (or/c syntax? false/c) #f] + [cert (or/c syntax? false/c) #f]) + syntax?]{ + +Converts the @tech{datum} @scheme[v] to a @tech{syntax object}, using +syntax objects already in @scheme[v] in the result. Converted objects +in @scheme[v] are given the lexical context information of +@scheme[ctxt] and the source-location information of +@scheme[srcloc]. If @scheme[v] is not already a syntax object, then +the resulting immediate syntax object it is given the properties (see +@secref["mz:stxprops"]) of @scheme[prop] and the inactive certificates +(see @secref["mz:stxprotect"]) of @scheme[cert]. Any of +@scheme[ctxt], @scheme[srcloc], @scheme[prop], or @scheme[cert] can be +@scheme[#f], in which case the resulting syntax has no lexical +context, source information, new properties, and/or certificates. + +If @scheme[srcloc] is not @scheme[#f] +or a syntax object, it must be a list of five elements: + +@schemeblock[ + (list source-name line column position span) +] + +where @scheme[source-name-v] is an arbitrary value for the source +name; @scheme[line] is an integer for the source line, or @scheme[#f]; +@scheme[column] is an integer for the source column, or @scheme[#f]; +@scheme[position] is an integer for the source position, or +@scheme[#f]; and @scheme[span] is an integer for the source span, or +@scheme[#f]. The @scheme[line] and @scheme[column] values must both be +numbers or both be @scheme[#f], otherwise the +@exnraise[exn:fail:contract]. + +Graph structure is preserved by the conversion of @scheme[v] to a +syntax object, but graph structure that is distributed among distinct +syntax objects in @scheme[v] may be hidden from future applications of +@scheme[syntax->datum] and @scheme[syntax-graph?] to the new +syntax object.} + +@defproc[(syntax-graph? [stx syntax?]) boolean?]{ + +Returns @scheme[#t] if @scheme[stx] might be preservably shared within +a syntax object created by @scheme[read-syntax], +@scheme[read-honu-syntax], or @scheme[datum->syntax]. In general, +sharing detection is approximate---@scheme[datum->syntax] can +construct syntax objects with sharing that is hidden from +@scheme[syntax-graph?]---but @scheme[syntax-graph?] reliably returns +@scheme[#t] for at least one syntax object in a cyclic +structure. Meanwhile, deconstructing a syntax object with procedures +such as @scheme[syntax-e] and comparing the results with @scheme[eq?] +can also fail to detect sharing (even cycles), due to the way lexical +information is lazily propagated; only @scheme[syntax->datum] reliably +exposes sharing in a way that can be detected with @scheme[eq?].} + +@defproc[(identifier? [v any/c]) boolean?]{ + +Returns @scheme[#t] if @scheme[v] is a syntax object and +@scheme[(syntax-e stx)] produces a symbol.} + + +@defproc[(generate-temporaries [stx-pair (or syntax? list?)]) + (listof identifier?)]{ + +Returns a list of identifiers that are distinct from all other +identifiers. The list contains as many identifiers as +@scheme[stx-pair] contains elements. The @scheme[stx-pair] argument +must be a syntax pair that can be flattened into a list. The elements +of @scheme[stx-pair] can be anything, but string, symbol, and +identifier elements will be embedded in the corresponding generated +name (useful for debugging purposes). The generated identifiers are +built with interned symbols (not @scheme[gensym]s), so the limitations +described in @secref["mz:compilation"] do not apply.} diff --git a/collects/scribblings/reference/stx-patterns.scrbl b/collects/scribblings/reference/stx-patterns.scrbl new file mode 100644 index 0000000000..b9473cc69b --- /dev/null +++ b/collects/scribblings/reference/stx-patterns.scrbl @@ -0,0 +1,375 @@ +#reader(lib "docreader.ss" "scribble") +@require["mz.ss"] +@require["ellipses.ss"] + +@title{Pattern-Based Syntax Matching} + +@defform/subs[(syntax-case stx-expr (literal-id ...) + clause ...) + ([clause [pattern result-expr] + [pattern fender-expr result-expr]] + [pattern _ + id + (pattern ...) + (pattern ...+ . pattern) + (pattern ... pattern ellipses pattern ...) + (pattern ... pattern ellipses pattern ... . pattern) + (code:line #,(tt "#")(pattern ...)) + (code:line #,(tt "#")(pattern ... pattern ellipses pattern ...)) + (ellipses stat-pattern) + const] + [stat-pattern id + (stat-pattern ...) + (stat-pattern ...+ . stat-pattern) + (code:line #,(tt "#")(stat-pattern ...)) + const] + [ellipses #,ellipses-id])]{ + +Finds the first @scheme[pattern] that matches the syntax object +produced by @scheme[stx-expr], and for which the corresponding +@scheme[fender-expr] (if any) produces a true value; the result is from +the corresponding @scheme[result-expr], which is in tail position for +the @scheme[syntax-case] form. If no @scheme[clause] matches, then the +@exnraise[exn:fail:syntax]. + +A syntax object matches a @scheme[pattern] as follows: + + @specsubform[_]{ + + A @scheme[_] pattern (i.e., an identifier with the same binding as + @scheme[_]) matches any syntax object.} + + @specsubform[id]{ + + An @scheme[id] matches any syntax object when it is not bound to + @|ellipses-id| or @scheme[_] and does not have the same binding as + any @scheme[literal-id]. The @scheme[id] is further bound as + @deftech{pattern variable} for the corresponding @scheme[fender-expr] + (if any) and @scheme[result-expr]. A pattern-variable binding is a + transformer binding; the pattern variable can be reference only + through forms like @scheme[syntax]. The binding's value is the syntax + object that matched the pattern with a @deftech{depth marker} of + @math{0}. + + An @scheme[id] that has the same binding as a @scheme[literal-id] + matches a syntax object that is an identifier with the same binding + in the sense of @scheme[free-identifier=?]. The match does not + introduce any @tech{pattern variables}.} + + @specsubform[(pattern ...)]{ + + A @scheme[(pattern ...)] pattern matches a syntax object whose datum + form (i.e., without lexical information) is a list with as many + elements as sub-@scheme[pattern]s in the pattern, and where each + syntax object that corresponding to an element of the list matches + the corresponding sub-@scheme[pattern]. + + Any @tech{pattern variables} bound by the sub-@scheme[pattern]s are + bound by the complete pattern; the bindings must all be distinct.} + + @specsubform[(pattern ...+ . pattern)]{ + + The last @scheme[pattern] must not be a @scheme[(pattern ...)], + @scheme[(pattern ...+ . pattern)], @scheme[(pattern ... pattern + ellipses pattern ...)], or @scheme[(pattern ... pattern ellipses + pattern ... . pattern)] form. + + Like the previous kind of pattern, but matches syntax objects that + are not necessarily lists; for @math{n} sub-@scheme[pattern]s before + the last sub-@scheme[pattern], the syntax object's datum must be a + pair such that @math{n-1} @scheme[cdr]s produce pairs. The last + sub-@scheme[pattern] is matched against the syntax object + corresponding to the @math{n}th @scheme[cdr] (or the + @scheme[datum->syntax] coercion of the datum using the nearest + enclosing syntax object's lexical context and source location).} + + @specsubform[(pattern ... pattern ellipses pattern ...)]{ + + Like the @scheme[(pattern ...)] kind of pattern, but matching a + syntax object with any number (zero or more) elements that match the + sub-@scheme[pattern] followed by @scheme[ellipses] in the + corresponding position relative to other sub-@scheme[pattern]s. + + For each pattern variable bound by the sub-@scheme[pattern] followed + by @scheme[ellipses], the larger pattern binds the same pattern + variable to a list of values, one for each element of the syntax + object matched to the sub-@scheme[pattern], with an incremented + @tech{depth marker}. (The sub-@scheme[pattern] itself may contain + @scheme[ellipses], leading to a pattern variables bound to lists of + lists of syntax objects with a @tech{depth marker} of @math{2}, and + so on.)} + + @specsubform[(pattern ... pattern ellipses pattern ... . pattern)]{ + + Like the previous kind of pattern, but with a final + sub-@scheme[pattern] as for @scheme[(pattern ...+ . pattern)]. The + final @scheme[pattern] never matches a syntax object whose datum is a + list.} + + @specsubform[(code:line #,(tt "#")(pattern ...))]{ + + Like a @scheme[(pattern ...)] pattern, but matching a vector syntax object + whose elements match the corresponding sub-@scheme[pattern]s.} + + @specsubform[(code:line #,(tt "#")(pattern ... pattern ellipses pattern ...))]{ + + Like a @scheme[(pattern ... pattern ellipses pattern ...)] pattern, + but matching a vector syntax object whose elements match the + corresponding sub-@scheme[pattern]s.} + + @specsubform[(ellipses stat-pattern)]{ + + Matches the same as @scheme[stat-pattern], which is like a @scheme[pattern], + but identifiers with the binding @scheme[...] are treated the same as + other @scheme[id]s.} + + @specsubform[const]{ + + A @scheme[const] is any datum that does not match one of the + preceeding forms; a syntax object matches a @scheme[const] pattern + when its datum is @scheme[equal?] to the @scheme[quote]d + @scheme[const].} + +} + +@defform[(syntax-case* stx-expr (literal-id ...) id-compare-expr + clause ...)]{ + +Like @scheme[syntax-case], but @scheme[id-compare-expr] must produce a +procedure that accepts two arguments. A @scheme[literal-id] in a +@scheme[_pattern] matches an identifier for which the procedure +returns true when given the identifier to match (as the first argument) +and the identifier in the @scheme[_pattern] (as the second argument). + +In other words, @scheme[syntax-case] is like @scheme[syntax-case*] with +an @scheme[id-compare-expr] that produces @scheme[free-identifier=?].} + + +@defform[(with-syntax ([pattern stx-expr] ...) + body ...+)]{ + +Similar to @scheme[syntax-case], in that it matches a @scheme[pattern] +to a syntax object. Unlike @scheme[syntax-case], all @scheme[pattern]s +are matched, each to the result of a corresponding @scheme[stx-expr], +and the pattern variables from all matches (which must be distinct) +are bound with a single @scheme[body] sequence. The result of the +@scheme[with-syntax] form is the result of the last @scheme[body], +which is in tail position with respect to the @scheme[with-syntax] +form. + +If any @scheme[pattern] fails to match the corresponding +@scheme[stx-expr], the @exnraise[exn:fail:syntax]. + +A @scheme[with-syntax] form is roughly equivalent to the following +@scheme[syntax-case] form: + +@schemeblock[ +(syntax-case (list stx-expr ...) () + [(pattern ...) (let () body ...+)]) +] + +However, if any individual @scheme[stx-expr] produces a +non-@tech{syntax object}, then it is converted to one using +@scheme[datum->syntax] and the lexical context and source location of +the individual @scheme[stx-expr].} + + +@defform/subs[(syntax template) + ([template id + (template-elem ...) + (template-elem ...+ . template) + (code:line #,(tt "#")(template-elem ...)) + (ellipses stat-template) + const] + [template-elem (code:line template ellipses ...)] + [stat-template id + (stat-template ...) + (stat-template ... . stat-template) + (code:line #,(tt "#")(stat-template ...)) + const] + [ellipses #,ellipses-id])]{ + +Constructs a syntax object based on a @scheme[template],which can +inlude @tech{pattern variables} bound by @scheme[syntax-case] or +@scheme[with-syntax]. + +Template forms produce a syntax object as follows: + + @specsubform[id]{ + + If @scheme[id] is bound as a @tech{pattern variable}, then + @scheme[id] as a template produces the @tech{pattern variable}'s + match result. Unless the @scheme[id] is a sub-@scheme[template] that is + replicated by @scheme[ellipses] in a larger @scheme[template], the + @tech{pattern variable}'s value must be a syntax object with a + @tech{depth marker} of @math{0} (as opposed to a list of + matches). + + More generally, if the @tech{pattern variable}'s value has a depth + marker @math{n}, then it can only appear within a template where it + is replicated by at least @math{n} @scheme[ellipses]es. In that case, + the template will be replicated enough times to use each match result + at least once. + + If @scheme[id] is not bound as a pattern variable, then @scheme[id] + as a template produces @scheme[(quote-syntax id)].} + + @specsubform[(template-elem ...)]{ + + Produces a syntax object whose datum is a list, and where the + elements of the list correspond to syntax objects producesd by the + @scheme[template-elem]s. + + A @scheme[template-elem] is a sub-@scheme[template] replicated by any + number of @scheme[ellipses]es: + + @itemize{ + + @item{If the sub-@scheme[template] is replicated by no + @scheme[ellipses]es, then it generates a single syntax object to + incorporate into the result syntax object.} + + @item{If the sub-@scheme[template] is replicated by one + @scheme[ellipses], then it generates a sequence of syntax objects + that is ``inlined'' into the resulting syntax object. + + The number of generated elements depends the values of + @tech{pattern variables} referenced within the + sub-@scheme[template]. There must be at least one @tech{pattern + variable} whose value is has a @tech{depth marker} less than the + number of @scheme[ellipses]es after the pattern variable within the + sub-@scheme[template]. + + If a @tech{pattern variable} is replicated by more + @scheme[ellipses]es in a @scheme[template] than the @tech{depth + marker} of its binding, then the @tech{pattern variable}'s result + is determined normally for inner @scheme[ellipses]es (up to the + binding's @tech{depth marker}), and then the result is replicated + as necessary to satisfy outer @scheme[ellipses]es.} + + @item{For each @scheme[ellipses] after the first one, the preceding + element (with earlier replicating @scheme[ellipses]s) is + conceptually wrapped with parentheses for generating output, and + then the wrapping parentheses are removed in the resulting syntax + object.}}} + + @specsubform[(template-elem ... . template)]{ + + Like the previous form, but the result is not necessarily a list; + instead, the place of the empty list in resulting syntax object's + datum is taken by the syntax object produced by @scheme[template].} + + @specsubform[(code:line #,(tt "#")(template-elem ...))]{ + + Like the @scheme[(template-elem ...)] form, but producing a syntax + object whose datum is a vector instead of a list.} + + @specsubform[(ellipses stat-template)]{ + + Produces the same result as @scheme[stat-template], which is like a + @scheme[template], but @|ellipses-id| is treated like a @scheme[id] + (with no pattern binding).} + + @specsubform[const]{ + + A @scheme[const] template is any form that does not match the + preceding cases, and it produces the result @scheme[(quote-syntac + const)].} + +A @scheme[(#,(schemekeywordfont "syntax") template)] form is normally +abbreviated as @scheme[#'template]; see also +@secref["mz:parse-quote"]. If @scheme[template] contains no pattern +variables, then @scheme[#'template] is equivalent to +@scheme[(quote-syntax template)].} + + +@defform[(quasisyntax template)]{ + +Like @scheme[syntax], but @scheme[(#,(schemekeywordfont "unsyntax") +_expr)] and @scheme[(#,(schemekeywordfont "unsyntax-splicing") _expr)] +escape to an expression within the @scheme[template]. + +The @scheme[_expr] must produce a syntax object (or syntax list) to be +substituted in place of the @scheme[unsyntax] or +@scheme[unsyntax-splicing] form within the quasiquoting template, just +like @scheme[unquote] and @scheme[unquote-splicing] within +@scheme[quasiquote]. (If the escaped expression does not generate a +syntax object, it is converted to one in the same was as for the +right-hand sides of @scheme[with-syntax].) Nested +@scheme[quasisyntax]es introduce quasiquoting layers in the same way +as nested @scheme[quasiquote]s. + +Also analogous @scheme[quasiquote], the reader converts @litchar{#`} +to @scheme[quasisyntax], @litchar{#,} to @scheme[unsyntax], and +@litchar["#,@"] to @scheme[unsyntax-splicing]. See also +@secref["mz:parse-quote"].} + + + +@defform[(unsyntax expr)]{ + +Illegal as an expression form. The @scheme[unsyntax] form is for use +only with a @scheme[quasisyntax] template.} + + +@defform[(unsyntax-splicing expr)]{ + +Illegal as an expression form. The @scheme[unsyntax-splicing] form is +for use only with a @scheme[quasisyntax] template.} + + +@defform[(syntax/loc stx-expr template)]{ + +Like @scheme[syntax], except that the immediate resulting syntax +object takes its source-location information from the result of +@scheme[stx-expr] (which must produce a syntax object), unless the +@scheme[template] is just a pattern variable.} + + +@defform[(quasisyntax/loc stx-expr template)]{ + +Like @scheme[quasisyntax], but with source-location assignment like +@scheme[syntax/loc].} + + +@defform[(syntax-rules (literal-id ...) + [(id . pattern) template] ...)]{ + +Equivalent to + +@schemeblock[ +(lambda (stx) + (syntax-case stx (literal-id ...) + [(_generated-id . pattern) (syntax template)] ...)) +] + +where each @scheme[_generated-id] binds no identifier in the +corresponding @scheme[template].} + + +@defform[(syntax-id-rules (literal-id ...) + [pattern template] ...)]{ + +Equivalent to + +@schemeblock[ +(lambda (stx) + (make-set!-transformer + (syntax-case stx (literal-id ...) + [pattern (syntax template)] ...))) +]} + + +@ellipses-defn{ + +The @|ellipses-id| transformer binding prohibits @|ellipses-id| from being +used as an expression. This binding useful only in syntax patterns and +templates, where it indicates repetitions of a pattern or +template. See @scheme[syntax-case] and @scheme[syntax].} + +@defidform[_]{ + +The @scheme[_] transformer binding prohibits @scheme[_] from being +used as an expression. This binding useful only in syntax patterns, +where it indicates a pattern that matches any syntax object. See +@scheme[syntax-case].} diff --git a/collects/scribblings/reference/syntax-model.scrbl b/collects/scribblings/reference/syntax-model.scrbl index cb41d8ba14..f8ff72cb4f 100644 --- a/collects/scribblings/reference/syntax-model.scrbl +++ b/collects/scribblings/reference/syntax-model.scrbl @@ -4,7 +4,7 @@ @require["mz.ss"] @;------------------------------------------------------------------------ -@title{Syntax Model} +@title[#:tag "mz:syntax-model"]{Syntax Model} The syntax of a Scheme program is defined by @@ -30,7 +30,7 @@ process, and when the @tech{expansion} process encounters a new binding information. @;------------------------------------------------------------------------ -@section{Identifiers and Binding} +@section[#:tag "mz:id-model"]{Identifiers and Binding} @guideintro["guide:binding"]{binding} @@ -85,7 +85,7 @@ identifier has a @tech{top-level binding} or @tech{module binding}, then it can have different such bindings in different phase levels. @;------------------------------------------------------------------------ -@section{Syntax Objects} +@section[#:tag "mz:stxobj-model"]{Syntax Objects} A @deftech{syntax object} combines a simpler Scheme value, such as a symbol or pair, with @deftech{lexical information} about bindings and @@ -147,7 +147,7 @@ information that @scheme[_datum] had when it was parsed as part of the @section[#:tag "mz:expansion"]{Expansion@aux-elem{ (Parsing)}} @deftech{Expansion} recursively processes a @tech{syntax object} in a -particular phase level, starting with phase level 0. @tech{Bindings} +particular phase level, starting with @tech{phase level} 0. @tech{Bindings} from the @tech{syntax object}'s @tech{lexical information} drive the expansion process, and cause new bindings to be introduced for the lexical information of sub-expressions. In some cases, a @@ -219,7 +219,7 @@ one whose binding is @scheme[define-values]). In all cases, identifiers above typeset as syntactic-form names refer to the bindings defined in @secref["mz:syntax"]. -Only phase levels 0 and 1 are relevant for following the parse of a +Only @tech{phase levels} 0 and 1 are relevant for following the parse of a program (though the @scheme[_datum] in a @scheme[quote-syntax] form preserves its information for all phase levels). In particular, the relevant phase level is 0, except for the @scheme[_expr]s in a @@ -425,7 +425,7 @@ binding @scheme[x] and the body @scheme[y] are not @scheme[bound-identifier=?]. @;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@subsection{Transformer Bindings} +@subsection[#:tag "mz:transformer-model"]{Transformer Bindings} In a @tech{top-level context} or @tech{module context}, when the expander encounters a @scheme[define-syntaxes] form, the binding that @@ -487,6 +487,12 @@ is the one left with a mark, and the reference @scheme[x] has no mark, so the binding @scheme[x] is not @scheme[bound-identifier=?] to the body @scheme[x]. +The @scheme[set!] form and the @scheme[make-set!-transformer] +procedure work together to support @deftech{assignment transformers} +that transformer @scheme[set!] expression. @tech{Assignment +transformers} are applied by @scheme[set!] in the same way as a normal +transformer by the macro expander. + The expander's handling of @scheme[letrec-values+syntaxes] is similar to its handling of @scheme[define-syntaxes]. A @scheme[letrec-values+syntaxes] mist be expanded in an arbitrary phase diff --git a/collects/scribblings/reference/syntax.scrbl b/collects/scribblings/reference/syntax.scrbl index fadd0566db..a04ca089f9 100644 --- a/collects/scribblings/reference/syntax.scrbl +++ b/collects/scribblings/reference/syntax.scrbl @@ -745,12 +745,17 @@ Equivalent to @scheme[(when (not test-expr) expr ...)]. @defform[(set! id expr)]{ -Evaluates @scheme[expr] and installs the result into the location for -@scheme[id], which must be bound as a local variable or defined as a -@tech{top-level variable} or @tech{module-level variable}. If -@scheme[id] refers to an imported binding, a syntax error is reported. -If @scheme[id] refers to a @tech{top-level variable} that has not been -defined, the @exnraise[exn:fail:contract]. +If @scheme[id] is bound as syntax to an @tech{assignment transformer}, +as produced by @scheme[make-set!-transformer], then this form is +expanded by calling the assignment transformer with the full +expressions. + +Otherwise, evaluates @scheme[expr] and installs the result into the +location for @scheme[id], which must be bound as a local variable or +defined as a @tech{top-level variable} or @tech{module-level +variable}. If @scheme[id] refers to an imported binding, a syntax +error is reported. If @scheme[id] refers to a @tech{top-level +variable} that has not been defined, the @exnraise[exn:fail:contract]. @defexamples[ (define x 12) @@ -764,7 +769,8 @@ x @defform[(set!-values (id ...) expr)]{ -Evaluates @scheme[expr], which must produce as many values as supplied +Assuming that all @scheme[id]s refer to variables, this form evaluates +@scheme[expr], which must produce as many values as supplied @scheme[id]s. The location of each @scheme[id] is filled wih to the corresponding value from @scheme[expr] in the same way as for @scheme[set!]. @@ -774,7 +780,17 @@ corresponding value from @scheme[expr] in the same way as for [b 2]) (set!-values (a b) (values b a)) (list a b)) -]} +] + +More generally, the @scheme[set!-values] form is expanded to + +@schemeblock[ +(let-values ([(_tmp-id ...) expr]) + (set! id _tmp-id) ...) +] + +which triggers further expansion if any @scheme[id] has a transformer +binding to an @tech{assignment transformer}.} @;------------------------------------------------------------------------ @include-section["for.scrbl"]