Document and generalize some things for first-class definition contexts
This commit adds a section to the reference to document how the expander tracks information about local bindings, and it extends some syntax-local functions to allow them to accept multiple definition contexts instead of just one. In addition, it improves the documentation on how first-class definition contexts interact with local-expand, syntax-local-value, and syntax-local-bind-syntaxes, and it also clarifies what it means to create a child definition context.
This commit is contained in:
parent
e5b5747566
commit
6834e4a12c
|
@ -12,7 +12,7 @@
|
|||
|
||||
(define collection 'multi)
|
||||
|
||||
(define version "6.90.0.26")
|
||||
(define version "6.90.0.27")
|
||||
|
||||
(define deps `("racket-lib"
|
||||
["racket" #:version ,version]))
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
@(define (transform-time) @t{This procedure must be called during the
|
||||
dynamic extent of a @tech{syntax transformer} application by the
|
||||
expander or while a module is @tech{visit}ed (see
|
||||
expander or while a module is @tech{visit}ed (see
|
||||
@racket[syntax-transforming?]), otherwise the
|
||||
@exnraise[exn:fail:contract].})
|
||||
|
||||
|
@ -233,11 +233,10 @@ identifier, the @racket[exn:fail:contract] exception is raised.
|
|||
@defproc[(local-expand [stx any/c]
|
||||
[context-v (or/c 'expression 'top-level 'module 'module-begin list?)]
|
||||
[stop-ids (or/c (listof identifier?) empty #f)]
|
||||
[intdef-ctx (or/c internal-definition-context?
|
||||
(and/c pair?
|
||||
(listof internal-definition-context?))
|
||||
[intdef-ctx (or/c internal-definition-context?
|
||||
(listof internal-definition-context?)
|
||||
#f)
|
||||
#f])
|
||||
'()])
|
||||
syntax?]{
|
||||
|
||||
Expands @racket[stx] in the lexical context of the expression
|
||||
|
@ -293,13 +292,17 @@ expansion is a @racket[#%plain-module-begin] form, then a
|
|||
@racket[module] form (but not @racket[module*] forms) in the same way as by
|
||||
@racket[module] expansion.
|
||||
|
||||
The optional @racket[intdef-ctx] argument must be either @racket[#f],
|
||||
the result of @racket[syntax-local-make-definition-context], or a list
|
||||
of such results. In the latter two cases, lexical information for
|
||||
internal definitions is added to @racket[stx] before it is expanded
|
||||
(in reverse order relative to the list). The lexical information is
|
||||
also added to the expansion result (because the expansion might
|
||||
introduce bindings or references to internal-definition bindings).
|
||||
If the @racket[intdef-ctx] argument is an internal-definition context, its @tech{bindings} are added
|
||||
to the @tech{local binding context} during the dynamic extent of the call to @racket[local-expand].
|
||||
Additionally, unless @racket[#f] was provided for the @racket[_add-scope?] argument to
|
||||
@racket[syntax-local-make-definition-context] when the internal-definition context was created,
|
||||
its @tech{scope} is added to the @tech{lexical information} for both @racket[stx] prior to its
|
||||
expansion and the expansion result (because the expansion might introduce bindings or references to
|
||||
internal-definition bindings). If @racket[intdef-ctx] is a list, all @tech{bindings} from all of the
|
||||
provided internal-definition contexts are added to the @tech{local binding context}, and the
|
||||
@tech{scope} from each context for which @racket[_add-scope?] was not @racket[#f] is added in the same
|
||||
way. For backwards compatibility, providing @racket[#f] for @racket[intdef-ctx] is treated the same as
|
||||
providing an empty list.
|
||||
|
||||
For a particular @tech{internal-definition context}, generate a unique
|
||||
value and put it into a list for @racket[context-v]. To allow
|
||||
|
@ -346,7 +349,10 @@ expansion history to external tools.
|
|||
|
||||
@history[#:changed "6.0.1.3" @elem{Changed treatment of @racket[#%top]
|
||||
so that it is never introduced as
|
||||
an explicit wrapper.}]}
|
||||
an explicit wrapper.}
|
||||
#:changed "6.0.90.27" @elem{Loosened the contract on the @racket[intdef-ctx] argument to
|
||||
allow an empty list, which is treated the same way as
|
||||
@racket[#f].}]}
|
||||
|
||||
|
||||
@defproc[(syntax-local-expand-expression [stx any/c] [opaque-only? #f])
|
||||
|
@ -377,9 +383,12 @@ result can be more efficient in some expansion contexts.
|
|||
|
||||
|
||||
@defproc[(local-transformer-expand [stx any/c]
|
||||
[context-v (or/c 'expression 'top-level list?)]
|
||||
[stop-ids (or/c (listof identifier?) #f)]
|
||||
[intdef-ctx (or/c internal-definition-context? #f) #f])
|
||||
[context-v (or/c 'expression 'top-level list?)]
|
||||
[stop-ids (or/c (listof identifier?) #f)]
|
||||
[intdef-ctx (or/c internal-definition-context?
|
||||
(listof internal-definition-context?)
|
||||
#f)
|
||||
'()])
|
||||
syntax?]{
|
||||
|
||||
Like @racket[local-expand], but @racket[stx] is expanded as a
|
||||
|
@ -397,11 +406,15 @@ or @racket[let-values] wrapper is added.
|
|||
@racket['top-level] context.}]}
|
||||
|
||||
|
||||
@defproc[(local-expand/capture-lifts [stx any/c]
|
||||
[context-v (or/c 'expression 'top-level 'module 'module-begin list?)]
|
||||
[stop-ids (or/c (listof identifier?) #f)]
|
||||
[intdef-ctx (or/c internal-definition-context? #f) #f]
|
||||
[lift-ctx any/c (gensym 'lifts)])
|
||||
@defproc[(local-expand/capture-lifts
|
||||
[stx any/c]
|
||||
[context-v (or/c 'expression 'top-level 'module 'module-begin list?)]
|
||||
[stop-ids (or/c (listof identifier?) #f)]
|
||||
[intdef-ctx (or/c internal-definition-context?
|
||||
(listof internal-definition-context?)
|
||||
#f)
|
||||
'()]
|
||||
[lift-ctx any/c (gensym 'lifts)])
|
||||
syntax?]{
|
||||
|
||||
Like @racket[local-expand], but the result is a syntax object that
|
||||
|
@ -420,11 +433,15 @@ If @racket[context-v] is @racket['top-level] or @racket['module], then
|
|||
@racket['module], then @racket[module*] forms can appear, too.}
|
||||
|
||||
|
||||
@defproc[(local-transformer-expand/capture-lifts [stx any/c]
|
||||
[context-v (or/c 'expression 'top-level list?)]
|
||||
[stop-ids (or/c (listof identifier?) #f)]
|
||||
[intdef-ctx (or/c internal-definition-context? #f) #f]
|
||||
[lift-ctx any/c (gensym 'lifts)])
|
||||
@defproc[(local-transformer-expand/capture-lifts
|
||||
[stx any/c]
|
||||
[context-v (or/c 'expression 'top-level list?)]
|
||||
[stop-ids (or/c (listof identifier?) #f)]
|
||||
[intdef-ctx (or/c internal-definition-context?
|
||||
(listof internal-definition-context?)
|
||||
#f)
|
||||
'()]
|
||||
[lift-ctx any/c (gensym 'lifts)])
|
||||
syntax?]{
|
||||
|
||||
Like @racket[local-expand/capture-lifts], but @racket[stx] is expanded
|
||||
|
@ -458,11 +475,10 @@ An @tech{internal-definition context} internally creates a
|
|||
within the context or that appears as the result of a (partial)
|
||||
expansion within the context.
|
||||
|
||||
If @racket[intdef-ctx] is not @racket[#f], then the new
|
||||
internal-definition context extends the given one. An extending
|
||||
definition context adds all @tech{scopes} that are added by
|
||||
@racket[intdef-ctx], and expanding in the new internal-definition context
|
||||
can use bindings previously introduced into @racket[intdef-ctx].
|
||||
If the created definition context is intended to be spliced into a
|
||||
surrounding definition context, the surrounding context should be
|
||||
provided for the @racket[intdef-ctx] argument to ensure the necessary
|
||||
@tech{use-site scopes} are added to macros expanded in the context.
|
||||
|
||||
@transform-time[]
|
||||
|
||||
|
@ -474,7 +490,10 @@ can use bindings previously introduced into @racket[intdef-ctx].
|
|||
|
||||
@defproc[(syntax-local-bind-syntaxes [id-list (listof identifier?)]
|
||||
[expr (or/c syntax? #f)]
|
||||
[intdef-ctx internal-definition-context?])
|
||||
[intdef-ctx internal-definition-context?]
|
||||
[extra-intdef-ctxs (or/c internal-definition-context?
|
||||
(listof internal-definition-context?))
|
||||
'()])
|
||||
void?]{
|
||||
|
||||
Binds each identifier in @racket[id-list] within the
|
||||
|
@ -488,7 +507,15 @@ in the latter case, the number of values produced by the expression should
|
|||
match the number of identifiers, otherwise the
|
||||
@exnraise[exn:fail:contract:arity].
|
||||
|
||||
@transform-time[]}
|
||||
When @racket[expr] is not @racket[#f], it is expanded in an @tech{expression context} and evaluated in
|
||||
the current @tech{transformer environment}. In this case, the value provided for
|
||||
@racket[extra-intdef-ctxs] is used to enrich @racket[expr]’s @tech{lexical information} and extend the
|
||||
@tech{local binding context} in the same way as the fourth argument to @racket[local-expand]. If
|
||||
@racket[expr] is @racket[#f], the value provided for @racket[extra-intdef-ctxs] is ignored.
|
||||
|
||||
@transform-time[]
|
||||
|
||||
@history[#:changed "6.90.0.27" @elem{Added the @racket[extra-intdef-ctxs] argument.}]}
|
||||
|
||||
|
||||
@defproc[(internal-definition-context-binding-identifiers
|
||||
|
@ -584,16 +611,16 @@ the binding creates a binding alias that effectively routes around the
|
|||
[failure-thunk (or/c (-> any) #f)
|
||||
#f]
|
||||
[intdef-ctx (or/c internal-definition-context?
|
||||
(listof internal-definition-context?)
|
||||
#f)
|
||||
#f])
|
||||
'()])
|
||||
any]{
|
||||
|
||||
Returns the @tech{transformer} binding value of the identifier
|
||||
@racket[id-stx] in either the context associated with
|
||||
@racket[intdef-ctx] (if not @racket[#f]) or the context of the
|
||||
expression being expanded (if @racket[intdef-ctx] is @racket[#f]). If
|
||||
@racket[intdef-ctx] is provided, it must be an extension of the
|
||||
context of the expression being expanded.
|
||||
Returns the @tech{transformer} binding value of the identifier @racket[id-stx] in the context of the
|
||||
current expansion. If @racket[intdef-ctx] is not @racket[#f], bindings from all provided definition
|
||||
contexts are also considered. @emph{Unlike} the fourth argument to @racket[local-expand], the
|
||||
@tech{scopes} associated with the provided definition contexts are @emph{not} used to enrich
|
||||
@racket[id-stx]’s @tech{lexical information}.
|
||||
|
||||
If @racket[id-stx] is bound to a @tech{rename transformer} created
|
||||
with @racket[make-rename-transformer], @racket[syntax-local-value]
|
||||
|
@ -627,15 +654,21 @@ if not @racket[#f]. If @racket[failure-thunk] is @racket[false], the
|
|||
(define-syntax (transformer-3 stx)
|
||||
(syntax-local-value #'chips))
|
||||
(transformer-3)
|
||||
]}
|
||||
]
|
||||
|
||||
@history[
|
||||
#:changed "6.90.0.27" @elem{Changed @racket[intdef-ctx] to accept a list of internal-definition
|
||||
contexts in addition to a single internal-definition context or
|
||||
@racket[#f].}]}
|
||||
|
||||
|
||||
@defproc[(syntax-local-value/immediate [id-stx syntax?]
|
||||
[failure-thunk (or/c (-> any) #f)
|
||||
#f]
|
||||
[intdef-ctx (or/c internal-definition-context?
|
||||
(listof internal-definition-context?)
|
||||
#f)
|
||||
#f])
|
||||
'()])
|
||||
any]{
|
||||
|
||||
Like @racket[syntax-local-value], but the result is normally two
|
||||
|
@ -671,7 +704,7 @@ to a top-level definition. A compile-time expression in a
|
|||
lifted to a @racket[let] wrapper around the corresponding right-hand
|
||||
side of the binding. A compile-time expression within
|
||||
@racket[begin-for-syntax] is lifted to a @racket[define]
|
||||
declaration just before the requesting expression within the
|
||||
declaration just before the requesting expression within the
|
||||
@racket[begin-for-syntax].
|
||||
|
||||
Other syntactic forms can capture lifts by using
|
||||
|
@ -742,7 +775,7 @@ is placed at the very end of the module (under a suitable number of
|
|||
enclosing @racket[begin-for-syntax].
|
||||
|
||||
@transform-time[] If the current expression being transformed is not
|
||||
within a @racket[module] form (see @racket[syntax-transforming-module-expression?]),
|
||||
within a @racket[module] form (see @racket[syntax-transforming-module-expression?]),
|
||||
then the @exnraise[exn:fail:contract].}
|
||||
|
||||
|
||||
|
@ -893,7 +926,7 @@ For (limited) backward compatibility only; raises @racket[exn:fail:unsupported].
|
|||
|
||||
|
||||
@defproc[(syntax-local-certifier [active? boolean? #f])
|
||||
((syntax?) (any/c (or/c procedure? #f))
|
||||
((syntax?) (any/c (or/c procedure? #f))
|
||||
. ->* . syntax?)]{
|
||||
|
||||
For backward compatibility only; returns a procedure that returns its
|
||||
|
@ -979,7 +1012,7 @@ and different result procedures use distinct scopes.
|
|||
added the optional operation argument
|
||||
in the result procedure.}]}
|
||||
|
||||
@defproc[(make-syntax-delta-introducer [ext-stx identifier?]
|
||||
@defproc[(make-syntax-delta-introducer [ext-stx identifier?]
|
||||
[base-stx (or/c syntax? #f)]
|
||||
[phase-level (or/c #f exact-integer?)
|
||||
(syntax-local-phase-level)])
|
||||
|
@ -1172,9 +1205,9 @@ Returns @racket[#t] if @racket[v] has the
|
|||
|
||||
@defstruct[import ([local-id identifier?]
|
||||
[src-sym symbol?]
|
||||
[src-mod-path (or/c module-path?
|
||||
[src-mod-path (or/c module-path?
|
||||
(and/c syntax?
|
||||
(lambda (stx)
|
||||
(lambda (stx)
|
||||
(module-path? (syntax->datum stx)))))]
|
||||
[mode (or/c exact-integer? #f)]
|
||||
[req-mode (or/c exact-integer? #f)]
|
||||
|
@ -1267,7 +1300,7 @@ converted to an absolute module path that is equivalent to
|
|||
|
||||
|
||||
@defproc[(syntax-local-require-certifier)
|
||||
((syntax?) (or/c #f (syntax? . -> . syntax?))
|
||||
((syntax?) (or/c #f (syntax? . -> . syntax?))
|
||||
. ->* . syntax?)]{
|
||||
|
||||
For backward compatibility only; returns a procedure that returns its
|
||||
|
@ -1444,7 +1477,7 @@ A structure representing a single imported identifier:
|
|||
|
||||
|
||||
@defproc[(syntax-local-provide-certifier)
|
||||
((syntax?) (or/c #f (syntax? . -> . syntax?))
|
||||
((syntax?) (or/c #f (syntax? . -> . syntax?))
|
||||
. ->* . syntax?)]{
|
||||
|
||||
For backward compatibility only; returns a procedure that returns its
|
||||
|
@ -1458,13 +1491,13 @@ first argument.}
|
|||
|
||||
@deftogether[(
|
||||
@defproc[(syntax-procedure-alias-property [stx syntax?])
|
||||
(or/c #f
|
||||
(or/c #f
|
||||
(letrec ([val? (recursive-contract
|
||||
(or/c (cons/c identifier? identifier?)
|
||||
(cons/c val? val?)))])
|
||||
val?))]
|
||||
@defproc[(syntax-procedure-converted-arguments-property [stx syntax?])
|
||||
(or/c #f
|
||||
(or/c #f
|
||||
(letrec ([val? (recursive-contract
|
||||
(or/c (cons/c identifier? identifier?)
|
||||
(cons/c val? val?)))])
|
||||
|
|
|
@ -155,15 +155,12 @@ relevant.
|
|||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "stxobj-model"]{Syntax Objects}
|
||||
|
||||
A @deftech{syntax object} combines a simpler Racket value, such as a
|
||||
symbol or pair, with a @tech{scope set} at each @tech{phase level},
|
||||
source-location information, @tech{syntax properties}, and
|
||||
@tech{tamper status}. In particular, an @tech{identifier} is
|
||||
represented as a syntax object that combines a @tech{symbol} with scope sets
|
||||
and other information. The @deftech{lexical information} of a
|
||||
@tech{syntax object} is its @tech{scope set} combined with the portion
|
||||
of the global table of bindings that is relevant to the syntax
|
||||
object's set of scopes.
|
||||
A @deftech{syntax object} combines a simpler Racket value, such as a symbol or pair, with
|
||||
@tech{lexical information}, source-location information, @tech{syntax properties}, and @tech{tamper
|
||||
status}. The @deftech{lexical information} of a @tech{syntax object} is comprised of a set of
|
||||
@tech{scope sets}, one for each @tech{phase level}. In particular, an @tech{identifier} is represented
|
||||
as a syntax object containing a @tech{symbol}, and its @tech{lexical information} can be combined with
|
||||
the global table of bindings to determine its @tech{binding} (if any) at each @tech{phase level}.
|
||||
|
||||
For example, a @racketidfont{car} @tech{identifier} might have
|
||||
@tech{lexical information} that designates it as the @racket[car] from
|
||||
|
@ -717,6 +714,81 @@ any introduced bindings from definition within
|
|||
@racket[begin-for-syntax] are at @tech{phase level} 1 (not a
|
||||
@tech{transformer} binding at @tech{phase level} 0).
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@subsection[#:tag "local-binding-context"]{Local Binding Context}
|
||||
|
||||
Although the @tech{binding} of an @tech{identifier} can be uniquely determined from the combination of
|
||||
its @tech{lexical information} and the global binding table, the expander also maintains a
|
||||
@deftech{local binding context} that records additional information about @tech{local bindings} to
|
||||
ensure they are not used outside of the lexical region in which they are bound.
|
||||
|
||||
Due to the way local binding forms like @racket[let] add a fresh @tech{scope} to both bound
|
||||
@tech{identifiers} and body forms, it isn’t ordinarily possible for an @tech{identifier} to reference
|
||||
a @tech{local binding} without appearing in the body of the @racket[let]. However, if macros use
|
||||
compile-time state to stash bound @tech{identifiers}, or use @racket[local-expand] to extract
|
||||
@tech{identifiers} from an expanded binding form, they can violate this constraint. For example, the
|
||||
following @racket[stash-id] and @racket[unstash-id] macros cooperate to move a reference to a
|
||||
locally-bound @racket[x] @tech{identifier} outside of the lexical region in which it is bound:
|
||||
|
||||
@(examples
|
||||
#:label #f
|
||||
#:eval racket-eval
|
||||
(begin-for-syntax
|
||||
(define stashed-id #f))
|
||||
(define-syntax (stash-id stx)
|
||||
(syntax-case stx ()
|
||||
[(_ id)
|
||||
(begin
|
||||
(set! stashed-id #'id)
|
||||
#'(void))]))
|
||||
(define-syntax (unstash-id stx)
|
||||
stashed-id)
|
||||
(let ([x 42])
|
||||
(stash-id x)
|
||||
(unstash-id))
|
||||
(eval:error (unstash-id)))
|
||||
|
||||
In general, an @tech{identifier}’s @tech{lexical information} is not sufficient to know whether or not
|
||||
its @tech{binding} is available in the enclosing context, since the @tech{scope set} for the
|
||||
@tech{identifier} stored in @racket[stashed-id] unambiguously refers to a binding in the global
|
||||
binding table. This can be observed by the fact that @racket[identifier-binding] produces
|
||||
@racket['lexical], not @racket[#f]:
|
||||
|
||||
@(examples
|
||||
#:label #f
|
||||
#:eval racket-eval
|
||||
#:escape UNSYNTAX
|
||||
(define-syntax (stashed-id-binding stx)
|
||||
#`(quote #,(identifier-binding stashed-id)))
|
||||
(eval:check (stashed-id-binding) 'lexical))
|
||||
|
||||
However, the reference produced by @racket[(unstash-id)] in the above program is still illegal, even
|
||||
if it isn’t technically unbound. To record the fact that @racket[x]’s @tech{binding} is in scope only
|
||||
within the body of its corresponding @racket[let] form, the expander adds @racket[x]’s @tech{binding}
|
||||
to the @tech{local binding context} while expanding the @racket[let] body. More generally, the
|
||||
expander adds all @tech{local variable} @tech{bindings} to the @tech{local binding context} while
|
||||
expanding expressions in which a reference to the @tech{variable} would be legal. When the expander
|
||||
encounters an @tech{identifier} bound to a @tech{local variable}, and the associated @tech{binding} is
|
||||
not in the current @tech{local binding context}, it raises a syntax error.
|
||||
|
||||
The @tech{local binding context} also tracks local @tech{transformer} @tech{bindings} (i.e. bindings
|
||||
bound by forms like @racket[let-syntax]) in a similar way, except that the context also stores the
|
||||
compile-time value associated with the @tech{transformer}. When an @tech{identifier} that is locally
|
||||
bound as a @tech{transformer} is used in application position as a @tech{syntax transformer}, or its
|
||||
compile-time value is looked up using @racket[syntax-local-value], the @tech{local binding context} is
|
||||
consulted to retrieve the value. If the @tech{binding} is in scope, its associated compile-time value
|
||||
is used; otherwise, the expander raises a syntax error.
|
||||
|
||||
@(examples
|
||||
#:eval racket-eval
|
||||
#:escape UNSYNTAX
|
||||
(define-syntax (stashed-id-local-value stx)
|
||||
#`(quote #,(syntax-local-value stashed-id)))
|
||||
(let-syntax ([y 42])
|
||||
(stash-id y)
|
||||
(stashed-id-local-value))
|
||||
(eval:error (stashed-id-local-value)))
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@subsection[#:tag "partial-expansion"]{Partial Expansion}
|
||||
|
||||
|
|
|
@ -195,16 +195,22 @@ is used as the basis for the identifier's name.
|
|||
[stx syntax?])
|
||||
syntax?]{
|
||||
|
||||
Applies the renamings of @racket[intdef-ctx] to @racket[stx].
|
||||
Equivalent to @racket[(internal-definition-context-introduce intdef-ctx stx 'add)]. The
|
||||
@racket[internal-definition-context-apply] function is provided for backwards compatibility; the more
|
||||
general @racket[internal-definition-context-introduce] function is preferred.
|
||||
}
|
||||
|
||||
@defproc[(syntax-local-eval [stx syntax?]
|
||||
[intdef-ctx (or/c internal-definition-context? #f) #f])
|
||||
[intdef-ctx (or/c internal-definition-context?
|
||||
(listof internal-definition-context?)
|
||||
#f)
|
||||
'()])
|
||||
any]{
|
||||
|
||||
Evaluates @racket[stx] as an expression in the current transformer
|
||||
environment (that is, at phase level 1), optionally extended with
|
||||
@racket[intdef-ctx].
|
||||
Evaluates @racket[stx] as an expression in the current @tech{transformer environment} (that is, at
|
||||
@tech{phase level} 1). If @racket[intdef-ctx] is not @racket[#f], the value provided for
|
||||
@racket[intdef-ctx] is used to enrich @racket[stx]’s @tech{lexical information} and extend the
|
||||
@tech{local binding context} in the same way as the fourth argument to @racket[local-expand].
|
||||
|
||||
@examples[#:eval the-eval
|
||||
(define-syntax (show-me stx)
|
||||
|
@ -220,6 +226,11 @@ environment (that is, at phase level 1), optionally extended with
|
|||
(define fruit 'pear)
|
||||
(show-me fruit)
|
||||
]
|
||||
|
||||
@history[
|
||||
#:changed "6.90.0.27" @elem{Changed @racket[intdef-ctx] to accept a list of internal-definition
|
||||
contexts in addition to a single internal-definition context or
|
||||
@racket[#f].}]
|
||||
}
|
||||
|
||||
@defform[(with-syntax* ([pattern stx-expr] ...)
|
||||
|
|
|
@ -1922,6 +1922,35 @@
|
|||
(let-syntax ([#%datum (make-rename-transformer #'unbound)])
|
||||
(+ 1 2))))
|
||||
|
||||
;; ----------------------------------------
|
||||
;; Check that definition context bindings are made available when the context is provided as fourth
|
||||
;; argument of syntax-local-bind-syntaxes
|
||||
|
||||
(module syntax-local-bind-syntaxes-local-value-in-other-context racket/base
|
||||
(require (for-syntax racket/base))
|
||||
(begin-for-syntax
|
||||
(define intdef-ctx-a (syntax-local-make-definition-context))
|
||||
(syntax-local-bind-syntaxes (list #'x) #'42 intdef-ctx-a)
|
||||
|
||||
(define intdef-ctx-b (syntax-local-make-definition-context intdef-ctx-a))
|
||||
(syntax-local-bind-syntaxes (list #'y) #'(syntax-local-value #'x) intdef-ctx-b intdef-ctx-a)))
|
||||
|
||||
;; ----------------------------------------
|
||||
;; internal-definition-context-introduce always adds scope
|
||||
|
||||
(module internal-definition-context-introduce-always-adds-scope racket/base
|
||||
(require (for-syntax racket/base))
|
||||
(provide result)
|
||||
(define-syntax (m stx)
|
||||
(define intdef-ctx (syntax-local-make-definition-context #f #f))
|
||||
(syntax-local-bind-syntaxes (list #'x) #''value intdef-ctx)
|
||||
#`(list '#,(syntax-local-value #'x (λ () #f) intdef-ctx)
|
||||
'#,(syntax-local-value (internal-definition-context-introduce intdef-ctx #'x)
|
||||
(λ () #f) intdef-ctx)))
|
||||
(define result (m)))
|
||||
|
||||
(test '(#f value) dynamic-require ''internal-definition-context-introduce-always-adds-scope 'result)
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
(report-errs)
|
||||
|
|
|
@ -185,21 +185,20 @@
|
|||
(define (generate-temporary [stx 'g])
|
||||
(car (generate-temporaries (list stx))))
|
||||
|
||||
;; Applies the renaming of intdefs to stx.
|
||||
;; Included for backwards compatibility.
|
||||
(define (internal-definition-context-apply intdefs stx)
|
||||
(let ([qastx (local-expand #`(quote #,stx) 'expression (list #'quote) intdefs)])
|
||||
(with-syntax ([(q astx) qastx]) #'astx)))
|
||||
(internal-definition-context-introduce intdefs stx 'add))
|
||||
|
||||
(define (syntax-local-eval stx [intdef0 #f])
|
||||
(define (syntax-local-eval stx [intdefs '()])
|
||||
(let* ([name (generate-temporary)]
|
||||
[intdefs (syntax-local-make-definition-context intdef0)])
|
||||
[intdef (syntax-local-make-definition-context)])
|
||||
(syntax-local-bind-syntaxes (list name)
|
||||
#`(call-with-values (lambda () #,stx) list)
|
||||
intdef
|
||||
intdefs)
|
||||
(internal-definition-context-seal intdefs)
|
||||
(apply values
|
||||
(syntax-local-value (internal-definition-context-apply intdefs name)
|
||||
#f intdefs))))
|
||||
(syntax-local-value (internal-definition-context-introduce intdef name)
|
||||
#f intdef))))
|
||||
|
||||
(define-syntax (with-syntax* stx)
|
||||
(syntax-case stx ()
|
||||
|
|
|
@ -26,7 +26,12 @@
|
|||
identifier-remove-from-definition-context
|
||||
|
||||
make-local-expand-context
|
||||
flip-introduction-scopes)
|
||||
flip-introduction-scopes
|
||||
|
||||
intdefs?
|
||||
intdefs?-string
|
||||
intdefs-or-false?
|
||||
intdefs-or-false?-string)
|
||||
|
||||
(struct internal-definition-context (frame-id ; identifies the frame for use-site scopes
|
||||
scope ; scope that represents the context
|
||||
|
@ -54,7 +59,7 @@
|
|||
(internal-definition-context frame-id sc add-scope? (box null)))
|
||||
|
||||
;; syntax-local-bind-syntaxes
|
||||
(define (syntax-local-bind-syntaxes ids s intdef)
|
||||
(define (syntax-local-bind-syntaxes ids s intdef [extra-intdefs '()])
|
||||
(unless (and (list? ids)
|
||||
(andmap identifier? ids))
|
||||
(raise-argument-error 'syntax-local-bind-syntaxes "(listof identifier?)" ids))
|
||||
|
@ -62,15 +67,19 @@
|
|||
(raise-argument-error 'syntax-local-bind-syntaxes "(or/c syntax? #f)" s))
|
||||
(unless (internal-definition-context? intdef)
|
||||
(raise-argument-error 'syntax-local-bind-syntaxes "internal-definition-context?" intdef))
|
||||
(unless (intdefs? extra-intdefs)
|
||||
(raise-argument-error 'syntax-local-bind-syntaxes intdefs?-string extra-intdefs))
|
||||
(define ctx (get-current-expand-context 'local-expand))
|
||||
(log-expand ctx 'local-bind ids)
|
||||
(define phase (expand-context-phase ctx))
|
||||
(define intdef-env (add-intdef-bindings (expand-context-env ctx)
|
||||
intdef))
|
||||
(define all-intdefs (if (list? extra-intdefs)
|
||||
(cons intdef extra-intdefs)
|
||||
(list intdef extra-intdefs)))
|
||||
(define intdef-ids (for/list ([id (in-list ids)])
|
||||
(define pre-id (remove-use-site-scopes (flip-introduction-scopes id ctx)
|
||||
ctx))
|
||||
(add-intdef-scopes pre-id intdef #:always? #t)))
|
||||
(add-intdef-scopes (add-intdef-scopes pre-id intdef #:always? #t)
|
||||
extra-intdefs)))
|
||||
(log-expand ctx 'rename-list intdef-ids)
|
||||
(define syms (for/list ([intdef-id (in-list intdef-ids)])
|
||||
(add-local-binding! intdef-id phase (root-expand-context-counter ctx)
|
||||
|
@ -78,9 +87,8 @@
|
|||
(define vals
|
||||
(cond
|
||||
[s
|
||||
(define input-s (flip-introduction-scopes (add-intdef-scopes s intdef #:always? #t)
|
||||
ctx))
|
||||
(define tmp-env (for/fold ([env intdef-env]) ([sym (in-list syms)])
|
||||
(define input-s (flip-introduction-scopes (add-intdef-scopes s all-intdefs) ctx))
|
||||
(define tmp-env (for/fold ([env (expand-context-env ctx)]) ([sym (in-list syms)])
|
||||
(hash-set env sym variable)))
|
||||
(log-expand ctx 'enter-bind)
|
||||
(define vals
|
||||
|
@ -89,7 +97,7 @@
|
|||
(make-local-expand-context (struct*-copy expand-context ctx
|
||||
[env tmp-env])
|
||||
#:context 'expression
|
||||
#:intdefs intdef)))
|
||||
#:intdefs all-intdefs)))
|
||||
(log-expand ctx 'exit-bind)
|
||||
vals]
|
||||
[else
|
||||
|
@ -117,12 +125,13 @@
|
|||
(unless (syntax? s)
|
||||
(raise-argument-error 'internal-definition-context-introduce "syntax?" s))
|
||||
(add-intdef-scopes s intdef
|
||||
#:always? #t
|
||||
#:action (case mode
|
||||
[(add) add-scope]
|
||||
[(remove) remove-scope]
|
||||
[(flip) flip-scope]
|
||||
[else (raise-argument-error
|
||||
internal-definition-context-introduce
|
||||
'internal-definition-context-introduce
|
||||
"(or/c 'add 'remove 'flip)"
|
||||
mode)])))
|
||||
|
||||
|
@ -145,6 +154,18 @@
|
|||
(for/fold ([id id]) ([intdef (in-intdefs intdef)])
|
||||
(internal-definition-context-introduce intdef id 'remove)))
|
||||
|
||||
;; For contract errors:
|
||||
(define (intdefs? x)
|
||||
(or (internal-definition-context? x)
|
||||
(and (list? x)
|
||||
(andmap internal-definition-context? x))))
|
||||
(define intdefs?-string
|
||||
"(or/c internal-definition-context? (listof internal-definition-context?))")
|
||||
(define (intdefs-or-false? x)
|
||||
(or (not x) (intdefs? x)))
|
||||
(define intdefs-or-false?-string
|
||||
"(or/c internal-definition-context? (listof internal-definition-context?) #f)")
|
||||
|
||||
;; Sequence for intdefs provided to `local-expand`
|
||||
(define-sequence-syntax in-intdefs
|
||||
(lambda (stx) (raise-syntax-error #f "only allowed in a `for` form" stx))
|
||||
|
@ -230,13 +251,13 @@
|
|||
[else (or frame-id i-frame-id)]))]
|
||||
[post-expansion-scope
|
||||
#:parent root-expand-context
|
||||
(if intdefs
|
||||
(if (and intdefs (not (null? intdefs)))
|
||||
(new-scope 'macro) ; placeholder; action uses `indefs`
|
||||
(and same-kind?
|
||||
(memq context '(module module-begin top-level))
|
||||
(root-expand-context-post-expansion-scope ctx)))]
|
||||
[post-expansion-scope-action
|
||||
(if intdefs
|
||||
(if (and intdefs (not (null? intdefs)))
|
||||
(lambda (s placeholder-sc)
|
||||
(add-intdef-scopes s intdefs))
|
||||
(expand-context-post-expansion-scope-action ctx))]
|
||||
|
|
|
@ -22,19 +22,19 @@
|
|||
local-transformer-expand/capture-lifts
|
||||
syntax-local-expand-expression)
|
||||
|
||||
(define (local-expand s context stop-ids [intdefs #f])
|
||||
(define (local-expand s context stop-ids [intdefs '()])
|
||||
(do-local-expand 'local-expand s context stop-ids intdefs))
|
||||
|
||||
(define (local-expand/capture-lifts s context stop-ids [intdefs #f] [lift-key (generate-lift-key)])
|
||||
(define (local-expand/capture-lifts s context stop-ids [intdefs '()] [lift-key (generate-lift-key)])
|
||||
(do-local-expand 'local-expand s context stop-ids intdefs
|
||||
#:capture-lifts? #t
|
||||
#:lift-key lift-key))
|
||||
|
||||
(define (local-transformer-expand s context stop-ids [intdefs #f])
|
||||
(define (local-transformer-expand s context stop-ids [intdefs '()])
|
||||
(do-local-expand 'local-expand s context stop-ids intdefs
|
||||
#:as-transformer? #t))
|
||||
|
||||
(define (local-transformer-expand/capture-lifts s context stop-ids [intdefs #f] [lift-key (generate-lift-key)])
|
||||
(define (local-transformer-expand/capture-lifts s context stop-ids [intdefs '()] [lift-key (generate-lift-key)])
|
||||
(do-local-expand 'local-expand s context stop-ids intdefs
|
||||
#:as-transformer? #t
|
||||
#:capture-lifts? #t
|
||||
|
@ -63,7 +63,7 @@
|
|||
|
||||
;; ----------------------------------------
|
||||
|
||||
(define (do-local-expand who s-or-s-exp context stop-ids [intdefs #f]
|
||||
(define (do-local-expand who s-or-s-exp context stop-ids [intdefs '()]
|
||||
#:capture-lifts? [capture-lifts? #f]
|
||||
#:as-transformer? [as-transformer? #f]
|
||||
#:to-parsed-ok? [to-parsed-ok? #f]
|
||||
|
@ -89,12 +89,8 @@
|
|||
(and (list? stop-ids)
|
||||
(andmap identifier? stop-ids)))
|
||||
(raise-argument-error who "(or/c (listof identifier?) #f)" stop-ids))
|
||||
(unless (or (not intdefs)
|
||||
(internal-definition-context? intdefs)
|
||||
(and (list? intdefs) (andmap internal-definition-context? intdefs)))
|
||||
(raise-argument-error who
|
||||
"(or/c #f internal-definition-context? (listof internal-definition-context?))"
|
||||
intdefs))
|
||||
(unless (intdefs-or-false? intdefs)
|
||||
(raise-argument-error who intdefs-or-false?-string intdefs))
|
||||
|
||||
(define ctx (get-current-expand-context who))
|
||||
(define phase (if as-transformer?
|
||||
|
|
|
@ -152,16 +152,16 @@
|
|||
|
||||
;; ----------------------------------------
|
||||
|
||||
(define (do-syntax-local-value who id intdef failure-thunk
|
||||
(define (do-syntax-local-value who id intdefs failure-thunk
|
||||
#:immediate? immediate?)
|
||||
(check who identifier? id)
|
||||
(check who #:or-false (procedure-arity-includes/c 0) failure-thunk)
|
||||
(check who #:or-false internal-definition-context? intdef)
|
||||
(check who intdefs-or-false? #:contract intdefs-or-false?-string intdefs)
|
||||
(define current-ctx (get-current-expand-context who))
|
||||
(define ctx (if intdef
|
||||
(define ctx (if intdefs
|
||||
(struct*-copy expand-context current-ctx
|
||||
[env (add-intdef-bindings (expand-context-env current-ctx)
|
||||
intdef)])
|
||||
intdefs)])
|
||||
current-ctx))
|
||||
(log-expand ctx 'local-value id)
|
||||
(define phase (expand-context-phase ctx))
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
consistently.)
|
||||
*/
|
||||
|
||||
#define MZSCHEME_VERSION "6.90.0.26"
|
||||
#define MZSCHEME_VERSION "6.90.0.27"
|
||||
|
||||
#define MZSCHEME_VERSION_X 6
|
||||
#define MZSCHEME_VERSION_Y 90
|
||||
#define MZSCHEME_VERSION_Z 0
|
||||
#define MZSCHEME_VERSION_W 26
|
||||
#define MZSCHEME_VERSION_W 27
|
||||
|
||||
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
|
||||
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user