hackett
hackett copied to clipboard
Allow a macro to "reset" the elaborator and do all the elaboration passes within itself
Some macros, and specifically the mod
macro in the Module/Functor system @iitalics and I are working on, should do all the elaboration passes themselves, and they should not be part of the elaboration passes of the outer module. Given this, they should call local-expand+elaborate
to set up those passes. However, when submodules of an outer module expand, they are already within an elaboration pass, so the call to local-expand+elaborate
errors out.
Should there be a call-with-no-elaborate-pass
function or an extra argument to local-expand+elaborate
so that macros like this can reset the elaborator and start a new set of passes?
Using the call-with-no-elaborate-pass
function would look like this:
(call-with-no-elaborate-pass
(λ ()
(local-expand+elaborate ...expr...))))
Or using some kind of extra argument might look like this:
(local-expand+elaborate ...expr... #:reset? #true)
An implementation of call-with-no-elaborate-pass
might look like:
(define (call-with-no-elaborate-pass f)
(parameterize ([current-syntax-elaborate-pass #f]
[current-elaborate-did-make-progress? #f]
[current-elaborate-did-defer? #f]
[current-elaborate-defer-id #f])
(f)))
Or an implementation of the #:reset?
argument might look like:
(define (local-expand+elaborate stx #:reset? [reset? #f] [intdef-ctxs '()])
....
(when (and (current-syntax-elaborate-pass) (not reset?))
(raise-arguments-error 'local-expand+elaborate "already elaborating"))
....)
Should mod
forms work like module*
? That is, should they be expanded after the enclosing Racket module has been expanded and elaborated? Or should they be more like module
submodules, which are expanded as soon as they are discovered?
They currently work like module
and not module*
. Modules cannot refer to definitions from their enclosing modules, but definitions in an outer module can refer to submodules.
PS:
Even with a form that behaved more like module*
, the mod
form should ideally stay the same. It wouldn't be (def-module M (mod ....))
vs. (def-module M (mod* ....))
, it would be:
(def-module M (mod ....))
vs.
(def-module* M (mod ....))
With the same mod
form for both.
I'm imagining that the def-module
form would expand right away while def-module*
form would have its expansion delayed until after everything else in the enclosing module is expanded. And whether it's within one or the other, the mod
form would want to do all the passes of the elaborator at that time.
Would you rather have a function like call-with-no-elaborate-pass
, or an optional extra argument like (local-expand+elaborate .... #:reset? #true)
?