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:
Alexis King 2018-04-20 11:47:23 -05:00
parent e5b5747566
commit 6834e4a12c
11 changed files with 5832 additions and 5548 deletions

View File

@ -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]))

View File

@ -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?)))])

View File

@ -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 isnt 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 isnt 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}

View File

@ -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] ...)

View File

@ -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)

View File

@ -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 ()

View File

@ -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))]

View File

@ -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?

View File

@ -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))

View File

@ -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