62 lines
1.7 KiB
Scheme
62 lines
1.7 KiB
Scheme
|
|
(module dmhelp mzscheme
|
|
(require syntax/stx)
|
|
|
|
(provide dm-syntax->datum
|
|
dm-subst)
|
|
|
|
;; `dm-syntax->datum' is like syntax-object->datum, but it also
|
|
;; builds a hash table that maps generated data to original syntax
|
|
;; objects. The hash table can then be used with `dm-subst' to
|
|
;; replace each re-used, unmodified datum with the original syntax
|
|
;; object.
|
|
|
|
(define (dm-syntax->datum stx ht)
|
|
;; Easiest to handle cycles by letting `syntax-object->datum'
|
|
;; do all the work.
|
|
(let ([v (syntax-object->datum stx)])
|
|
(let loop ([stx stx][v v])
|
|
(let ([already (hash-table-get ht v (lambda () #f))])
|
|
(if already
|
|
(hash-table-put! ht v #t) ;; not stx => don't subst later
|
|
(hash-table-put! ht v stx))
|
|
(cond
|
|
[(stx-pair? stx)
|
|
(loop (stx-car stx) (car v))
|
|
(loop (stx-cdr stx) (cdr v))]
|
|
[(stx-null? stx) null]
|
|
[(vector? (syntax-e stx))
|
|
(for-each
|
|
loop
|
|
(vector->list
|
|
(syntax-e stx))
|
|
(vector->list v))]
|
|
[(box? (syntax-e stx))
|
|
(loop (unbox (syntax-e stx))
|
|
(unbox v))]
|
|
[else (void)])))
|
|
v))
|
|
|
|
(define (dm-subst ht v)
|
|
(define cycle-ht (make-hash-table))
|
|
(let loop ([v v])
|
|
(if (hash-table-get cycle-ht v (lambda () #f))
|
|
v
|
|
(begin
|
|
(hash-table-put! cycle-ht v #t)
|
|
(let ([m (hash-table-get ht v (lambda () #f))])
|
|
(cond
|
|
[(syntax? m) m] ;; subst back!
|
|
[(pair? v) (cons (loop (car v))
|
|
(loop (cdr v)))]
|
|
[(vector? v) (list->vector
|
|
(map
|
|
loop
|
|
(vector->list v)))]
|
|
[(box? v) (box (loop (unbox v)))]
|
|
[else v])))))))
|
|
|
|
|
|
|
|
|