From 954e850e209771e2516456e7e563c5d0f3c08f77 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Thu, 1 Oct 2009 21:14:21 +0000 Subject: [PATCH] fix reference (restoring some text that was lost in the reference-manual rewrite) to describe the problem with macro-introduced bindings and the top level svn: r16205 --- .../scribblings/reference/syntax-model.scrbl | 114 +++++++++++++++++- collects/scribblings/reference/syntax.scrbl | 9 +- 2 files changed, 119 insertions(+), 4 deletions(-) diff --git a/collects/scribblings/reference/syntax-model.scrbl b/collects/scribblings/reference/syntax-model.scrbl index 2060d83dc3..f5c15c9fe3 100644 --- a/collects/scribblings/reference/syntax-model.scrbl +++ b/collects/scribblings/reference/syntax-model.scrbl @@ -3,6 +3,9 @@ (for-syntax mzscheme) "mz.ss") +@(define scheme-eval (make-base-eval)) +@(interaction-eval #:eval scheme-eval (require (for-syntax scheme/base))) + @;------------------------------------------------------------------------ @title[#:tag "syntax-model"]{Syntax Model} @@ -447,7 +450,7 @@ core syntactic forms are encountered: right-hand-side expressions are also extended with the bindings.} - @item{Definitions in @scheme[internal-definition contexts] introduce + @item{Definitions in @tech{internal-definition contexts} introduce bindings as described in @secref["intdef-body"].} ] @@ -600,7 +603,7 @@ then expansion stops without adding the identifier. @;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @subsection[#:tag "intdef-body"]{Internal Definitions} -An internal-definition context corresponds to a partial expansion step +An @tech{internal-definition context} corresponds to a partial expansion step (see @secref["partial-expansion"]). A form that supports internal definitions starts by expanding its first form in an internal-definition context, but only partially. That is, it @@ -692,6 +695,109 @@ module is attached to a namespace through are transitively attached, but instances are attached only at phases at or below the namespace's @tech{base phase}. +@;------------------------------------------------------------------------ +@subsection[#:tag "macro-introduced-bindings"]{Macro-Introduced Bindings} + +When a top-level definition binds an identifier that originates from a + macro expansion, the definition captures only uses of the identifier + that are generated by the same expansion. This behavior is consistent + with expansion in @tech{internal-definition contexts}, where the + defined identifier turns into a fresh lexical binding. + +@examples[ +(define-syntax def-and-use-of-x + (syntax-rules () + [(def-and-use-of-x val) + (code:comment @#,t{@scheme[x] below originates from this macro:}) + (begin (define x val) x)])) +(define x 1) +x +(def-and-use-of-x 2) +x + +(define-syntax def-and-use + (syntax-rules () + [(def-and-use x val) + (code:comment @#,t{@scheme{x} below was provided by the macro use:}) + (begin (define x val) x)])) +(def-and-use x 3) +x +] + +For a top-level definition (outside of a module), the order of + evaluation affects the binding of a generated definition for a + generated identifier use. If the use precedes the definition, then + the use refers to a non-generated binding, just as if the generated + definition were not present. (No such dependency on order occurs + within a module, since a module binding covers the entire module + body.) To support the declaration of an identifier before its use, + the @scheme[define-syntaxes] form avoids binding an identifier if the + body of the @scheme[define-syntaxes] declaration produces zero + results. + +@examples[ +#:eval scheme-eval +(define bucket-1 0) +(define bucket-2 0) +(define-syntax def-and-set!-use-of-x + (syntax-rules () + [(def-and-set!-use-of-x val) + (begin (set! bucket-1 x) (define x val) (set! bucket-2 x))])) +(define x 1) +(def-and-set!-use-of-x 2) +x +bucket-1 +bucket-2 + +(define-syntax defs-and-uses/fail + (syntax-rules () + [(def-and-use) + (begin + (code:comment @#,t{Initial reference to @scheme[even] precedes definition:}) + (define (odd x) (if (zero? x) #f (even (sub1 x)))) + (define (even x) (if (zero? x) #t (odd (sub1 x)))) + (odd 17))])) +(defs-and-uses/fail) + +(define-syntax defs-and-uses + (syntax-rules () + [(def-and-use) + (begin + (code:comment @#,t{Declare before definition via no-values @scheme[define-syntaxes]:}) + (define-syntaxes (odd even) (values)) + (define (odd x) (if (zero? x) #f (even (sub1 x)))) + (define (even x) (if (zero? x) #t (odd (sub1 x)))) + (odd 17))])) +(defs-and-uses) +] + +Macro-generated \scheme{require} and \scheme{provide} + clauses also introduce and reference generation-specific bindings: + +@itemize[ + + @item{In @scheme[require], for a @scheme[_require-spec] of the form + @scheme[(rename-in [_orig-id _bind-id])] or @scheme[(only-in + .... [_orig-id _bind-id])], the @scheme[_bind-id] is bound only for + uses of the identifier generated by the same macro expansion as + @scheme[_bind-id]. In @scheme[require] for other + @scheme[_require-spec]s, the generator of the @scheme[_require-spec] + determines the scope of the bindings.} + + @item{In @scheme[provide], for a @scheme[_provide-spec] of the form + @scheme[_id], the exported identifier is the one that binds + @scheme[_id] within the module in a generator-specific way, but the + external name is the plain @scheme[_id]. The exceptions for + @scheme[all-except-out] are similarly determined in a + generator-specific way, as is the @scheme[_orig-id] binding of a + @scheme[rename-out] form, but plain identifiers are used for the + external names. For @scheme[all-defined-out], only identifiers with + definitions having the same generator as the + @scheme[(all-defined-out)] form are exported; the external name is + the plain identifier from the definition.} + +] + @;------------------------------------------------------------------------ @section[#:tag "compilation-model"]{Compilation} @@ -860,3 +966,7 @@ When an inferred name is not available, but a source location is available, a name is constructed using the source location information. Inferred and property-assigned names are also available to syntax transformers, via @scheme[syntax-local-name]. + +@;---------------------------------------- + +@close-eval[scheme-eval] diff --git a/collects/scribblings/reference/syntax.scrbl b/collects/scribblings/reference/syntax.scrbl index 7e171cc41d..1f4f1d2861 100644 --- a/collects/scribblings/reference/syntax.scrbl +++ b/collects/scribblings/reference/syntax.scrbl @@ -1896,7 +1896,12 @@ expands to a definition of the first form where the @scheme[expr] is a Like @scheme[define-syntax], but creates a @tech{transformer binding} for each @scheme[id]. The @scheme[expr] should produce as many values as @scheme[id]s, and each value is bound to the corresponding -@scheme[id]. } +@scheme[id]. + +When @scheme[expr] produces zero values for a top-level +@scheme[define-syntaxes] (i.e., not in a module or internal-definition +position), then the @scheme[id]s are effectively declared without +binding; see @secref["macro-introduced-bindings"]. @defexamples[#:eval (syntax-eval) (define-syntaxes (foo1 foo2 foo3) @@ -1915,7 +1920,7 @@ as @scheme[id]s, and each value is bound to the corresponding (foo1) (foo2) (foo3) -] +]} @defform*[[(define-for-syntax id expr) (define-for-syntax (head args) body ...+)]]{