hackett icon indicating copy to clipboard operation
hackett copied to clipboard

Allow a macro to "reset" the elaborator and do all the elaboration passes within itself

Open AlexKnauth opened this issue 6 years ago • 4 comments

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

AlexKnauth avatar Jul 03 '18 18:07 AlexKnauth

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?

lexi-lambda avatar Jul 03 '18 19:07 lexi-lambda

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.

AlexKnauth avatar Jul 03 '18 19:07 AlexKnauth

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.

AlexKnauth avatar Jul 03 '18 19:07 AlexKnauth

Would you rather have a function like call-with-no-elaborate-pass, or an optional extra argument like (local-expand+elaborate .... #:reset? #true)?

AlexKnauth avatar Jul 04 '18 14:07 AlexKnauth