test-expansion-order.rkt (2312B)
1 #lang racket 2 3 ;; This is a quick experiment to see in what order are macros expanded. 4 ;; 5 ;; It is necessary to understand this in order to internally build a stack of 6 ;; definitions of pattern variables, and correctly pop pvars from the stack when 7 ;; they go out of scope. 8 9 ;; Macros in definition contexts are expanded in a breadth-first order 10 ;; Macros in expression contexts are expanded in a breadth-first order 11 ;; 12 ;; Within a scope (let or top-level), all definitions are expanded, 13 ;; then all the expressions 14 15 (require rackunit) 16 17 (define-for-syntax order '()) 18 (define-for-syntax (record-order x) 19 (set! order (cons x order))) 20 21 (define-syntax (d stx) 22 (syntax-case stx () 23 [(_ a) 24 (begin (record-order `(d . ,(syntax-e #'a))) 25 #'(define x 42))])) 26 27 (define-syntax (e stx) 28 (syntax-case stx () 29 [(_ a) 30 (begin (record-order `(e . ,(syntax-e #'a))) 31 #'42)])) 32 33 (define (expr x) (void)) 34 35 (d "+0 012") 36 (expr (e "?3 012")) 37 38 (let () 39 (d "+4 012_45") 40 (expr (e "?6 012_45")) 41 ;; here, we're evaluating an "e" in a definition context, 42 ;; therefore it does not know that 5 will exist. 43 (e "¿5 012_4X\"") 44 ;; wrapping it with #%expression ensures that it runs after all definitions 45 ;; in the current scope (of course it then cannot introduce new definitions). 46 (#%expression (e "e6 012_46\"'")) 47 (let () 48 (d "+7 012_45_7") 49 (expr (e "?8 012_45_7")) 50 (d "+7 012_45_7'") 51 (expr (e "?8 012_45_7'"))) 52 (d "+5 012_45") 53 (expr (e "?9 012_45"))) 54 55 (d "+1 012") 56 (expr (e "?A 012")) 57 58 (let () 59 (d "+B 012_B") 60 (expr (e "?C 012_B"))) 61 62 (d "+2 012") 63 (expr (e "?D 012")) 64 (check-equal? (let-syntax ([get (λ (stx) #`'#,(reverse order))]) 65 get) 66 '((d . "+0 012") 67 (d . "+1 012") 68 (d . "+2 012") 69 (e . "?3 012") 70 (d . "+4 012_45") 71 (e . "¿5 012_4X\"") 72 (d . "+5 012_45") 73 (e . "?6 012_45") 74 (e . "e6 012_46\"'") 75 (d . "+7 012_45_7") 76 (d . "+7 012_45_7'") 77 (e . "?8 012_45_7") 78 (e . "?8 012_45_7'") 79 (e . "?9 012_45") 80 (e . "?A 012") 81 (d . "+B 012_B") 82 (e . "?C 012_B") 83 (e . "?D 012")))