101 lines
3.9 KiB
Racket
101 lines
3.9 KiB
Racket
#lang racket/base
|
|
|
|
(provide quasitemplate-ddd
|
|
quasisubtemplate-ddd)
|
|
|
|
(require (rename-in stxparse-info/parse/experimental/template
|
|
[?? stxparse:??]
|
|
[?@ stxparse:?@])
|
|
subtemplate/ddd-forms
|
|
subtemplate/template-subscripts
|
|
(only-in racket/base [... …])
|
|
stxparse-info/parse
|
|
stxparse-info/case
|
|
(for-syntax racket/base
|
|
racket/list
|
|
racket/syntax
|
|
stxparse-info/parse
|
|
(only-in racket/base [... …])
|
|
phc-toolkit/untyped))
|
|
|
|
(define-for-syntax lifted (make-parameter #f))
|
|
|
|
(define-for-syntax (pre-parse-unsyntax tmpl depth escapes)
|
|
;; TODO: a nested quasisubtemplate should escape an unsyntax!
|
|
(define (ds e)
|
|
;; TODO: should preserve the shape of the original stx
|
|
;; (syntax list vs syntax pair)
|
|
(datum->syntax tmpl e tmpl tmpl))
|
|
(define-syntax-class ooo
|
|
(pattern {~and ooo {~literal ...}}))
|
|
(define (recur t) (pre-parse-unsyntax t depth escapes))
|
|
(define (stx-length stx) (length (syntax->list stx)))
|
|
(define (lift! e) (set-box! (lifted) (cons e (unbox (lifted)))))
|
|
(syntax-parse tmpl
|
|
#:literals (unsyntax unsyntax-splicing unquote unquote-splicing
|
|
quasitemplate ?? ?@)
|
|
[:id tmpl]
|
|
[({~and u unsyntax} (unquote e)) ;; full unquote with #,,
|
|
(ds `(,#'u ,#'e))]
|
|
[({~and u unsyntax-splicing} (unquote e)) ;; full unquote with #,@,
|
|
(ds `(,#'u ,#'e))]
|
|
[({~and u unsyntax} (unquote-splicing e)) ;; full unquote with #,,@
|
|
(ds `(,(datum->syntax #'here 'unsyntax-splicing #'u) ,#'e))]
|
|
[({~and u unsyntax} e)
|
|
#:when (= escapes 0)
|
|
(with-syntax ([tmp (generate-temporary #'e)]
|
|
[ooo* (map (λ (_) (quote-syntax …)) (range depth))])
|
|
(lift! #`(begin (define/with-syntax tmp (splice-append e)) . ooo*))
|
|
(ds `(,#'stxparse:?@ . ,(datum->syntax #'tmp #'tmp #'e))))]
|
|
[({~and u unsyntax-splicing} e)
|
|
#:when (= escapes 0)
|
|
(with-syntax ([tmp (generate-temporary #'e)]
|
|
[ooo* (map (λ (_) (quote-syntax …)) (range depth))])
|
|
(lift! #`(begin (define/with-syntax tmp (splice-append* e)) . ooo*))
|
|
#'(stxparse:?@ . tmp))]
|
|
[({~and u {~or unsyntax unsyntax-splicing}} e)
|
|
;; when escapes ≠ 0
|
|
(ds `(,#'u ,(pre-parse-unsyntax e depth (sub1 escapes))))]
|
|
[(quasitemplate t . opts)
|
|
(ds `(,#'quasitemplate ,(pre-parse-unsyntax #'t depth (add1 escapes))
|
|
. ,#'opts))]
|
|
[({~var mf (static template-metafunction? "template metafunction")} . args)
|
|
(ds `(,#'mf . ,(recur #'args)))]
|
|
[(:ooo t)
|
|
tmpl] ;; fully escaped, do not change
|
|
[(?? . args)
|
|
(ds `(,#'stxparse:?? . ,(recur #'args)))]
|
|
[(?@ . args)
|
|
(ds `(,#'stxparse:?@ . ,(recur #'args)))]
|
|
[(hd :ooo ...+ . tl)
|
|
(ds `(,(pre-parse-unsyntax #'hd (+ depth (stx-length #'(ooo …))) escapes)
|
|
,@(syntax->list #'(ooo ...))
|
|
. ,(recur #'tl)))]
|
|
[(hd . tl)
|
|
(ds `(,(recur #'hd) . ,(recur #'tl)))]
|
|
[#(t …)
|
|
(ds (list->vector (stx-map recur #'(t …))))]
|
|
[()
|
|
tmpl]))
|
|
|
|
(define-for-syntax ((quasi*template-ddd form) stx)
|
|
(syntax-case stx ()
|
|
[(_ tmpl . opts)
|
|
(parameterize ([lifted (box '())])
|
|
(let ([new-tmpl (pre-parse-unsyntax #'tmpl 0 0)])
|
|
(if (null? (unbox (lifted)))
|
|
(datum->syntax stx
|
|
`(,form ,new-tmpl . ,#'opts)
|
|
stx
|
|
stx)
|
|
(quasisyntax/top-loc stx
|
|
(let-values ()
|
|
#,@(unbox (lifted))
|
|
#,(datum->syntax stx
|
|
`(,form ,new-tmpl . ,#'opts)
|
|
stx
|
|
stx))))))]))
|
|
|
|
(define-syntax quasitemplate-ddd (quasi*template-ddd #'quasitemplate))
|
|
(define-syntax quasisubtemplate-ddd (quasi*template-ddd #'quasisubtemplate))
|