expander: allow syntax-local-lift-require
during #%module-begin
expansion
Making `syntax-local-lift-require` during `#%module-begin` expansion provides a solution to a long-standing problem with composing languages via `#%module-begin`, where the bindings of some lanuage should be made available for expanding the module body by `#%module-begin` expansion (i.e., the language is *not* the initial import). If the language does not support `require`, then there was no way to expand and expose the language import dependency. Closes #1352
This commit is contained in:
parent
f4ccd0fdc6
commit
bff31f0768
|
@ -1075,9 +1075,7 @@
|
||||||
|
|
||||||
(for ([lift-attempt+rx:expected-error
|
(for ([lift-attempt+rx:expected-error
|
||||||
(in-list
|
(in-list
|
||||||
(list (cons '(syntax-local-lift-require 'racket #'body)
|
(list (cons '(syntax-local-lift-expression #'body)
|
||||||
#rx"could not find target context")
|
|
||||||
(cons '(syntax-local-lift-expression #'body)
|
|
||||||
#rx"no lift target")
|
#rx"no lift target")
|
||||||
(cons '(syntax-local-lift-module #'(module m racket/base))
|
(cons '(syntax-local-lift-module #'(module m racket/base))
|
||||||
#rx"not currently transforming within a module declaration or top level")
|
#rx"not currently transforming within a module declaration or top level")
|
||||||
|
|
|
@ -2703,6 +2703,61 @@ case of module-leve bindings; it doesn't cover local bindings.
|
||||||
|
|
||||||
(dynamic-require '(submod 'm-use main) #f))
|
(dynamic-require '(submod 'm-use main) #f))
|
||||||
|
|
||||||
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Check that syntax-local-lift-require works in `#%module-begin` expansion
|
||||||
|
|
||||||
|
(module adds-racket-promise-but-without-reachable-bindings racket/base
|
||||||
|
(require (for-syntax racket/base))
|
||||||
|
|
||||||
|
(provide (except-out (all-from-out racket/base)
|
||||||
|
#%module-begin)
|
||||||
|
(rename-out [module-begin #%module-begin]))
|
||||||
|
|
||||||
|
(define-syntax (module-begin stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ . body)
|
||||||
|
(syntax-local-lift-require 'racket/promise #'body)
|
||||||
|
#'(#%module-begin . body)])))
|
||||||
|
|
||||||
|
(test '(module m 'adds-racket-promise-but-without-reachable-bindings
|
||||||
|
(#%module-begin
|
||||||
|
(#%require racket/promise)
|
||||||
|
(module configure-runtime '#%kernel
|
||||||
|
(#%module-begin
|
||||||
|
(#%require racket/runtime-config)
|
||||||
|
(#%app configure '#f)))))
|
||||||
|
syntax->datum
|
||||||
|
(expand '(module m 'adds-racket-promise-but-without-reachable-bindings)))
|
||||||
|
|
||||||
|
(err/rt-test/once (expand '(module m 'adds-racket-promise-but-without-reachable-bindings
|
||||||
|
force))
|
||||||
|
exn:fail:syntax?)
|
||||||
|
|
||||||
|
(module adds-racket-promise-with-reachable-bindings racket/base
|
||||||
|
(require (for-syntax racket/base))
|
||||||
|
|
||||||
|
(provide (except-out (all-from-out racket/base)
|
||||||
|
#%module-begin)
|
||||||
|
(rename-out [module-begin #%module-begin]))
|
||||||
|
|
||||||
|
(define-syntax (module-begin stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ . body)
|
||||||
|
(with-syntax ([body (syntax-local-lift-require 'racket/promise #'body)])
|
||||||
|
#'(#%module-begin . body))])))
|
||||||
|
|
||||||
|
(test '(module m 'adds-racket-promise-with-reachable-bindings
|
||||||
|
(#%module-begin
|
||||||
|
(#%require racket/promise)
|
||||||
|
(module configure-runtime '#%kernel
|
||||||
|
(#%module-begin
|
||||||
|
(#%require racket/runtime-config)
|
||||||
|
(#%app configure '#f)))
|
||||||
|
(#%app call-with-values (lambda () force) print-values)))
|
||||||
|
syntax->datum
|
||||||
|
(expand '(module m 'adds-racket-promise-with-reachable-bindings
|
||||||
|
force)))
|
||||||
|
|
||||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Make sure that a module can be attached without a recorded namespace syntax context
|
;; Make sure that a module can be attached without a recorded namespace syntax context
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
make-require-lift-context
|
make-require-lift-context
|
||||||
add-lifted-require!
|
add-lifted-require!
|
||||||
|
get-require-lifts
|
||||||
get-and-clear-require-lifts!
|
get-and-clear-require-lifts!
|
||||||
require-lift-context-wrt-phase
|
require-lift-context-wrt-phase
|
||||||
|
|
||||||
|
@ -182,8 +183,11 @@
|
||||||
requires) ; records lifted requires
|
requires) ; records lifted requires
|
||||||
#:authentic)
|
#:authentic)
|
||||||
|
|
||||||
(define (make-require-lift-context wrt-phase do-require)
|
(define (make-require-lift-context wrt-phase do-require [initial-lifts null])
|
||||||
(require-lift-context do-require wrt-phase (box null)))
|
(require-lift-context do-require wrt-phase (box initial-lifts)))
|
||||||
|
|
||||||
|
(define (get-require-lifts require-lifts)
|
||||||
|
(unbox (require-lift-context-requires require-lifts)))
|
||||||
|
|
||||||
(define (get-and-clear-require-lifts! require-lifts)
|
(define (get-and-clear-require-lifts! require-lifts)
|
||||||
(box-clear! (require-lift-context-requires require-lifts)))
|
(box-clear! (require-lift-context-requires require-lifts)))
|
||||||
|
|
|
@ -283,6 +283,9 @@
|
||||||
;; Accumulated declared submodule names for `syntax-local-submodules`
|
;; Accumulated declared submodule names for `syntax-local-submodules`
|
||||||
(define declared-submodule-names (make-hasheq))
|
(define declared-submodule-names (make-hasheq))
|
||||||
|
|
||||||
|
;; Requires that were lifted during `#%module-begin` expansion:
|
||||||
|
(define initial-lifted-requires (get-require-lifts (expand-context-require-lifts ctx)))
|
||||||
|
|
||||||
;; Module expansion always parses the module body along the way,
|
;; Module expansion always parses the module body along the way,
|
||||||
;; even if `to-parsed?` in `ctx` is not true. The body is parsed
|
;; even if `to-parsed?` in `ctx` is not true. The body is parsed
|
||||||
;; so that the module can be declared for reference by
|
;; so that the module can be declared for reference by
|
||||||
|
@ -298,7 +301,8 @@
|
||||||
|
|
||||||
;; Passes 1 and 2 are nested via `begin-for-syntax`:
|
;; Passes 1 and 2 are nested via `begin-for-syntax`:
|
||||||
(define expression-expanded-bodys
|
(define expression-expanded-bodys
|
||||||
(let pass-1-and-2-loop ([bodys bodys] [phase phase] [keep-stops? (stop-at-module*? ctx)])
|
(let pass-1-and-2-loop ([bodys bodys] [phase phase] [keep-stops? (stop-at-module*? ctx)]
|
||||||
|
[initial-lifted-requires initial-lifted-requires])
|
||||||
|
|
||||||
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
;; Pass 1: partially expand to discover all bindings and install all
|
;; Pass 1: partially expand to discover all bindings and install all
|
||||||
|
@ -325,7 +329,8 @@
|
||||||
[require-lifts (make-require-lift-context
|
[require-lifts (make-require-lift-context
|
||||||
phase
|
phase
|
||||||
(make-parse-lifted-require m-ns self requires+provides
|
(make-parse-lifted-require m-ns self requires+provides
|
||||||
#:declared-submodule-names declared-submodule-names))]
|
#:declared-submodule-names declared-submodule-names)
|
||||||
|
initial-lifted-requires)]
|
||||||
[to-module-lifts (make-to-module-lift-context
|
[to-module-lifts (make-to-module-lift-context
|
||||||
phase
|
phase
|
||||||
#:shared-module-ends module-ends
|
#:shared-module-ends module-ends
|
||||||
|
@ -481,7 +486,10 @@
|
||||||
[lifts #f]
|
[lifts #f]
|
||||||
[module-lifts #f]
|
[module-lifts #f]
|
||||||
[to-module-lifts #f]
|
[to-module-lifts #f]
|
||||||
[require-lifts #f]))
|
[require-lifts (make-require-lift-context
|
||||||
|
phase
|
||||||
|
(make-parse-lifted-require m-ns self requires+provides
|
||||||
|
#:declared-submodule-names (make-hasheq)))]))
|
||||||
|
|
||||||
(define mb-scopes-s
|
(define mb-scopes-s
|
||||||
(if keep-enclosing-scope-at-phase
|
(if keep-enclosing-scope-at-phase
|
||||||
|
@ -773,7 +781,7 @@
|
||||||
(define ct-m-ns (namespace->namespace-at-phase m-ns (add1 phase)))
|
(define ct-m-ns (namespace->namespace-at-phase m-ns (add1 phase)))
|
||||||
(prepare-next-phase-namespace partial-body-ctx)
|
(prepare-next-phase-namespace partial-body-ctx)
|
||||||
(log-expand partial-body-ctx 'phase-up)
|
(log-expand partial-body-ctx 'phase-up)
|
||||||
(define nested-bodys (pass-1-and-2-loop (m 'e) (add1 phase) #f))
|
(define nested-bodys (pass-1-and-2-loop (m 'e) (add1 phase) #f null))
|
||||||
(log-expand partial-body-ctx 'next-group)
|
(log-expand partial-body-ctx 'next-group)
|
||||||
(namespace-run-available-modules! m-ns (add1 phase)) ; to support running `begin-for-syntax`
|
(namespace-run-available-modules! m-ns (add1 phase)) ; to support running `begin-for-syntax`
|
||||||
(eval-nested-bodys nested-bodys (add1 phase) ct-m-ns self partial-body-ctx)
|
(eval-nested-bodys nested-bodys (add1 phase) ct-m-ns self partial-body-ctx)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user