Hi Éric, This is a nice idea - I pondered the concept before, but today I got a little further. I am unsure whether the approach scales. You could look at nanopass too. Anyways, here is a little experiment.
/Jens Axel https://racket-stories.com #lang racket (require (for-syntax syntax/parse racket/syntax syntax/stx)) ;;; ;;; Expansion Example ;;; ; This example shows how to use Racket's expander for non-Racket languages. ; The expansion is done by our-expand, which expands an expression in the ; input language L1 to the output language L2. ; The forms in the input language are: ; (:let ([id expr] ...) body ...) ; let bindings ; (:set! id expr) ; assignment ; (expr ...) ; application ; The output language is: ; (let ([id expr] ...) body ...) ; let bindings ; (set! id expr) ; assignment ; (#%app expr ...) ; application ; The idea is to use `local-expand` with a list of stop-ids ; determined by our output language. (begin-for-syntax (define usual-stop-ids (syntax->list #'(begin quote set! #%plain-lambda case-lambda let-values letrec-values if begin0 with-continuation-mark letrec-syntaxes+values #%plain-app #%expression #%top #%variable-reference))) (define our-stop-ids (syntax->list #'(let set!))) (define stop-ids (append our-stop-ids usual-stop-ids))) ; We can now expand an expression using `local-expand`: ; SYNTAX (our-expand form) ; expand form into the output language (define-syntax (our-expand stx) (syntax-parse stx [(_our-expand s) (with-syntax ([expansion (local-expand #'s 'expression stop-ids)]) (syntax/loc stx 'expansion))])) ; We need to specify how the contstructs in the input language are to ; be expanded. ; In an assignment the expression needs to be expanded. (define-syntax (:set! stx) (syntax-parse stx [(_set! x e) (define (le s) (local-expand s 'expression stop-ids)) (with-syntax ([e (le #'e)]) (syntax/loc stx (set! x e)))])) ; In a let binding both the expressions and the body ; must be expanded. The body needs to be expanded in an internal definition ; context (at least if we allow internal defines in the body - otherwise ; an expression context can be used instead). (define-syntax (:let stx) (syntax-parse stx [(_let ([x e] ...) b ...) ; The expressions e ... are expanding in an expression context (define (le s) (local-expand s 'expression stop-ids)) ; The body b ... is expanded in a new internal definition context (define ctx (list (gensym))) (define ictx (syntax-local-make-definition-context)) (define (ile b) (local-expand b ctx stop-ids ictx)) ; The expressions and body are now locally expanded (with-syntax ([(e ...) (stx-map le #'(e ...))] [(b ...) (stx-map ile #'(b ...))]) ; assemble the results (syntax/loc stx (let ([x e] ...) b ...)))])) ; Let's see if we can define macros that expand ; into our input language. (define-syntax-rule (swap x y) (:let ([tmp x]) (:set! x y) (:set! y tmp))) (define a 10) (define b 20) (our-expand (swap a b)) (our-expand (:let ([x (+ 1 2)] [y 4]) (swap x y) y)) ; The output becomes: '(let ((tmp a)) (set! a b) (set! b tmp)) '(let ((x (#%app + 1 2)) (y '4)) (let ((tmp x)) (set! x y) (set! y tmp)) y) Den man. 10. aug. 2020 kl. 15.44 skrev Éric Tanter <[email protected]>: > Hi, > > I’d like to use the Racket macro expander to translate programs from a > given source language to a target language (both scheme-ish). > > However, the expansion that `raco expand` does is too violent for my > purposes---I would need a way to specify macro hiding (as in the macro > stepper), in order to control the level of abstraction of the expanded > code. Is that possible? > [see example below] > > Thanks, > > — Éric > > ; test.rkt > (define-syntax-rule (swap x y) > (let ([tmp x]) > (set! x y) > (set! y tmp))) > > (define a 10) > (define b 20) > (swap a b) > > ; I’d like to obtain: > > …prelude… > (define a 10) > (define b 20) > (let ([tmp a]) > (set! a b) > (set! b tmp))) > > ; but raco expand gives me the full story: > > (module test play > (#%module-begin > (module configure-runtime '#%kernel > (#%module-begin (#%require racket/runtime-config) (#%app configure > '#f))) > (#%provide b swap a) > (define-syntaxes > (swap) > (lambda (user-stx) > (let-values (((arg) user-stx)) > (let-values (((rslt) > (#%app > (lambda (e) > (if (#%app stx-pair? e) > (if (#%app (lambda (e) null) (#%app stx-car e)) > (#%app > (lambda (e) > (if (#%app stx-pair? e) > (#%app > cons/#f > (#%app stx-car e) > (#%app > (lambda (e) > (if (#%app stx-pair? e) > (let-values (((mh) (#%app stx-car > e))) > (if mh > (if (#%app > stx-null/#f > (#%app stx-cdr e)) > mh > '#f) > '#f)) > '#f)) > (#%app stx-cdr e))) > '#f)) > (#%app stx-cdr e)) > '#f) > '#f)) > arg))) > (if rslt > (let-values (((sc1) (#%app unsafe-car rslt)) > ((sc2) (#%app unsafe-cdr rslt))) > (let-values () > (#%app > syntax-protect > (let-values (((loc) (#%app check-loc 'syntax/loc > user-stx))) > (#%app > t-subst > loc > (quote-syntax (let _ (set! _ _) (set! _ tmp))) > '(1 recur 2 recur 3) > (#%app > t-resyntax > '#f > (quote-syntax STX) > (#%app > t-list > (#%app t-subst '#f (quote-syntax (tmp _)) '(1) sc1))) > (#%app list '(1 2) sc1 sc2) > (#%app list '(1) sc2)))))) > (let-values (((rslt) (#%app (lambda (e) null) arg))) > (if rslt > (let-values () > (let-values () (#%app pattern-failure user-stx '(x y)))) > (#%app raise-syntax-error '#f '"bad syntax" arg)))))))) > (define-values (a) '10) > (define-values (b) '20) > (#%app > call-with-values > (lambda () (let-values (((tmp) a)) (set! a b) (set! b tmp))) > print-values))) > > -- > 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 [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/racket-users/94E20736-F1F7-4073-B3FA-505ADD71DB4F%40dcc.uchile.cl > <https://groups.google.com/d/msgid/racket-users/94E20736-F1F7-4073-B3FA-505ADD71DB4F%40dcc.uchile.cl?utm_medium=email&utm_source=footer> > . > -- -- Jens Axel Søgaard -- 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 [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/CABefVgxMiOCUJkBwJhXOMzFu5gRaK%2BfefE-gkvSfXSkiuMT4vw%40mail.gmail.com.

