Re: [racket-users] Using local-expand to mostly expand a module?

2016-01-31 Thread Matthew Flatt
I think you need to use a trampoline for the module body's expansion,
where you expand only one module-body form at a time and let
`#%module-begin` finish up forms like `require` or `define-syntaxes`
before you macro continues with later forms.

The general pattern is that you have a macro `do-module-begin` where

 (do-module-begin
  expr-0
  expr ...)

turns into 

 (begin
  expanded-expr-0
  (do-module-begin
   expr ...))

where `expr-0` is `local-expand`ed and transformed as needed. The base
module-body expander will process `expanded-expr-0`, importing and
binding macros as needed, before continuing with `(do-module-begin expr
...)` for the rest of the module.

For an example, see the implementation of `syntax/wrap-modbeg`.

This pattern shows up frequently, but I've never hit on quite the right
abstraction to turn the pattern into a library. It's probably just a
matter of trying harder.

At Fri, 29 Jan 2016 21:29:16 -0800 (PST), reilithion wrote:
> I'm trying to make a little EDSL that has one form that is special and needs 
> to be collected and later processed. I want to allow a user of the EDSL to 
> write a macro that expands to the special form. I have a module-begin that 
> (so 
> far) looks like this:
> 
> (define-syntax (module-begin stx)
>   (syntax-parse stx
> ((_ module-contents ...)
>  (let-values
>   ([(tasks other)
> (partition
>  (syntax-parser #:literals (task-internal) ((task-internal _ ...) #t) 
> (_ #f))
>  (rest
>   ;; Problems start here
>   (syntax->list
>(local-expand
> #'(#%plain-module-begin module-contents ...)
> 'module-begin
> (list #'task-internal #'module* #'#%app)])
>   #`(#%module-begin
>  #,@other
>  (define all-tasks (list #,@tasks))
>  (process all-tasks))
> 
> If I don't bother with the local-expand and just use (rest (syntax->list 
> stx)), it works basically fine but won't treat macros that expand to 
> task-internal specially. I tried mapping local-expand over (syntax->list 
> stx), 
> but that led to strange errors when I tried to define macros within the EDSL.
> 
> This current implementation fails because it expands too much too soon. A 
> macro will happily expand into (task-internal args ...), then (task-internal1 
> args ...), then (#%app task-internal1 args ...), and then the call to 
> partition won't see what it's expecting (in fact, I think it CAN'T see what 
> it 
> needs to, because I suspect the local-expand of the #%plain-module-begin 
> effectively hides the task-internal identifier).
> 
> I added a bunch of stuff to the stop-ids list, hoping it would bail before 
> transforming task-internal beyond recognition, but nothing I added seemed to 
> work.
> 
> I also tried calling local-expand on #'(begin module-contexts ...) with the 
> 'top-level context-v, but of course begin is automatically added to the 
> stop-ids list and local-expand stops right away.
> 
> Can I somehow get local-expand to only mostly expand a module? How do I do 
> what I'm trying to do here?
> 
> Thanks!
> Lucas Paul
> 
> -- 
> 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.

-- 
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] Using local-expand to mostly expand a module?

2016-01-29 Thread reilithion
I'm trying to make a little EDSL that has one form that is special and needs to 
be collected and later processed. I want to allow a user of the EDSL to write a 
macro that expands to the special form. I have a module-begin that (so far) 
looks like this:

(define-syntax (module-begin stx)
  (syntax-parse stx
((_ module-contents ...)
 (let-values
  ([(tasks other)
(partition
 (syntax-parser #:literals (task-internal) ((task-internal _ ...) #t) 
(_ #f))
 (rest
  ;; Problems start here
  (syntax->list
   (local-expand
#'(#%plain-module-begin module-contents ...)
'module-begin
(list #'task-internal #'module* #'#%app)])
  #`(#%module-begin
 #,@other
 (define all-tasks (list #,@tasks))
 (process all-tasks))

If I don't bother with the local-expand and just use (rest (syntax->list stx)), 
it works basically fine but won't treat macros that expand to task-internal 
specially. I tried mapping local-expand over (syntax->list stx), but that led 
to strange errors when I tried to define macros within the EDSL.

This current implementation fails because it expands too much too soon. A macro 
will happily expand into (task-internal args ...), then (task-internal1 args 
...), then (#%app task-internal1 args ...), and then the call to partition 
won't see what it's expecting (in fact, I think it CAN'T see what it needs to, 
because I suspect the local-expand of the #%plain-module-begin effectively 
hides the task-internal identifier).

I added a bunch of stuff to the stop-ids list, hoping it would bail before 
transforming task-internal beyond recognition, but nothing I added seemed to 
work.

I also tried calling local-expand on #'(begin module-contexts ...) with the 
'top-level context-v, but of course begin is automatically added to the 
stop-ids list and local-expand stops right away.

Can I somehow get local-expand to only mostly expand a module? How do I do what 
I'm trying to do here?

Thanks!
Lucas Paul

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