www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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