Re: [racket-users] Extracting the body of a fully-expanded module (with submodules)
Thanks Matthew! Your solution seems to work fine, the trampoline idea is a very neat trick. I like how it's safe to use require and begin because the continue macro returns fully-expanded syntax which won't be affected by the code injected around (for some reason I thought it was necessary to only inject fully-expanded forms like #%require, but that assumption was wrong). I'd like to read more about the shifting of "relative" module references, is there anything in the docs about it (I vaguely remember seeing something, but couldn't find it again)? -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Extracting the body of a fully-expanded module (with submodules)
At Wed, 14 Dec 2016 18:12:52 -0800 (PST), Dupéron Georges wrote: > Hello! > > This is a follow-up to the excellent answer by Alex Knauth on StackOverflow > here: http://stackoverflow.com/a/38032107/324969 and this mailing-list > thread: > https://groups.google.com/forum/#!topic/racket-users/sS-pUUGp9o4 > > I'm trying to write a module meta-language mylang, which accepts a second > language to which is passes the modified body, such that: > > (module foo mylang typed/racket body) > > is equivalent to: > > (module foo typed/racket transformed-body) > > The real-world goal is to transform the fully-expanded body (e.g. add a > submodule, like the "doc" module added by scribble/lp2). > > Alex came up with the implementation below. It puts the body into a dummy > module, fully expands it, and extracts the (#%plain-module-begin . mod-body), > patching it to require the user-provided lang. This works very well in all > cases except when the body contains submodules. The problem here is somewhat related to the thread about syntax objects in properties. When a module expansion completes, bindings in syntax objects are shifted so that a binding from "the module currently being expanded" is redirected to be a binding from "this module". If you re-expand a whole module, then "this module" is shifted back to "the module currently being expanded"; at the end of the at re-expansion, it's shifted back to "this module", and so on. The problem is that you're already inside one module, the so the expanded module's content is not shifted from "this module" to "the module currently being expanded" as the module-body expansion continues. That absence of a shift turns out not to matter for most things, but submodules the second time around are instantiated as relative to "the module currently being expanded". Meanwhile, unshifted references remain relative to "this module". I think you probably want something like the variant below. It's similar to Alex's strategy, but it wraps the body in a `#%module-begin` form, instead of `module`, so that you can use 'module-begin with `local-expand`. That way, you stay within the same overall module expansion. The main extra trick in the implementation is a trampoline via `continue` to first `require` the language to get its bindings, including `#%module-begin`. #lang racket ;; The language definition (module mylang racket (provide (rename-out [-#%module-begin #%module-begin])) (define-syntax (-#%module-begin stx) (syntax-case stx () [(_ lng . rest) (with-syntax ([#%module-begin (datum->syntax #'lng '#%module-begin)]) #`(#%plain-module-begin (require lng) (continue #%module-begin . rest)))])) (define-syntax (continue stx) (syntax-case stx () [(_ lang-module-begin . rest) (let ([body-stx (local-expand #'(lang-module-begin . rest) 'module-begin (list))]) ;; pattern-match on the #%plain-module-begin form to insert a require (syntax-case body-stx (#%plain-module-begin) [(#%plain-module-begin . mod-body) #`(begin . #,((make-syntax-introducer) #'mod-body))]))]))) ;; A module using that language (module foo (submod ".." mylang) typed/racket/base (module a-submod typed/racket/base (define x 1) (provide x)) (require 'a-submod) (ann (+ x 1) Number)) (require 'foo) -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[racket-users] Extracting the body of a fully-expanded module (with submodules)
Hello! This is a follow-up to the excellent answer by Alex Knauth on StackOverflow here: http://stackoverflow.com/a/38032107/324969 and this mailing-list thread: https://groups.google.com/forum/#!topic/racket-users/sS-pUUGp9o4 I'm trying to write a module meta-language mylang, which accepts a second language to which is passes the modified body, such that: (module foo mylang typed/racket body) is equivalent to: (module foo typed/racket transformed-body) The real-world goal is to transform the fully-expanded body (e.g. add a submodule, like the "doc" module added by scribble/lp2). Alex came up with the implementation below. It puts the body into a dummy module, fully expands it, and extracts the (#%plain-module-begin . mod-body), patching it to require the user-provided lang. This works very well in all cases except when the body contains submodules. In that case, I get an "require: namespace mismatch; reference to a module that is not available" error. I'm rather clueless about how to solve that problem. I tried using local-expand with a 'module-begin context, but it then complains that x is unbound when the user-supplied language is typed/racket, and the error seems to be related to the submodules generated by TR. Any suggestions? Georges Dupéron #lang racket ;; The language definition (module mylang racket (provide (rename-out [-#%module-begin #%module-begin])) (define-syntax (-#%module-begin stx) (syntax-case stx () [(_ lng . rest) (with-syntax ([#%module-begin (datum->syntax #f '#%module-begin)]) ;; put the code in a module form, and fully expand that module (define mod-stx (local-expand #'(module ignored lng (#%module-begin . rest)) 'top-level (list))) ;; pattern-match on the #%plain-module-begin form to insert a require (syntax-case mod-stx (module #%plain-module-begin) [(module _ lng (#%plain-module-begin . mod-body)) #`(#%plain-module-begin (#%require lng) . #,((make-syntax-introducer) #'mod-body))]))]))) ;; A module using that language (module foo (submod ".." mylang) typed/racket/base (module a-submod typed/racket/base (define x 1) (provide x)) (require 'a-submod) (ann (+ x 1) Number)) (require 'foo) -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.