Re: [racket-users] Extracting the body of a fully-expanded module (with submodules)

2016-12-15 Thread Dupéron Georges
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)

2016-12-14 Thread Matthew Flatt
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)

2016-12-14 Thread Dupéron Georges
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.