Defining quasisyntax in terms of syntax-case
Andre van Tonder
(30 Jun 2006 02:30 UTC)
|
Re: Defining quasisyntax in terms of syntax-case Andre van Tonder (30 Jun 2006 11:25 UTC)
|
Re: Defining quasisyntax in terms of syntax-case
David Feuer
(30 Jun 2006 11:43 UTC)
|
Re: Defining quasisyntax in terms of syntax-case
Andre van Tonder
(30 Jun 2006 13:56 UTC)
|
Re: Defining quasisyntax in terms of syntax-case
Andre van Tonder
(30 Jun 2006 19:06 UTC)
|
Here is more correct and much more concise definition. A quasisyntax expression is simply converted to a with-syntax expression that performs the appropriate substitutions. It runs on Petite. I've been careful to port Bawden's extension of the R5RS quasiquote semantics, which I suspect agrees with the definition used for quasiquote in Chez, to quasisyntax. Andre ;;;========================================================= ;;; ;;; Quasisyntax in terms of SRFI-93 syntax-case. ;;; Andre van Tonder ;;; ;;;========================================================= ;;; ;;; To make nested unquote-splicing behave in a useful way, ;;; the R5RS-compatible extension to quasiquote in appendix B ;;; of the following paper is used: ;;; ;;; Alan Bawden - Quasiquotation in Lisp ;;; http://citeseer.ist.psu.edu/bawden99quasiquotation.html ;;; ;;; The algorithm converts a quasisyntax expression to an ;;; equivalent with-syntax expression. ;;; For example: ;;; ;;; (quasisyntax (set! ,a ,b)) ;;; ==> (with-syntax ((t0 a) ;;; (t1 b)) ;;; (syntax (set! t0 t1))) ;;; ;;; (quasisyntax (list ,@args)) ;;; ==> (with-syntax (((t ...) args)) ;;; (syntax (list t ...))) ;;; ;;; Note that quasisyntax is expanded first, before any ;;; ellipses act. For example: ;;; ;;; (quasisyntax (f ((b ,a) ...)) ;;; ==> (with-syntax ((t a)) ;;; (syntax (f ((b t) ...)))) ;;; ;;; so that ;;; ;;; (let-syntax ((test-ellipses-over-unsyntax ;;; (lambda (e) ;;; (let ((a (syntax a))) ;;; (with-syntax (((b ...) (syntax (1 2 3)))) ;;; (quasisyntax ;;; (quote ((b ,a) ...)))))))) ;;; (test-ellipses-over-unsyntax)) ;;; ;;; ==> ((1 a) (2 a) (3 a)) (define-syntax quasisyntax (lambda (e) (define (expand-quasisyntax x) ;; Expand returns a syntax object of the form ;; (template[t/e, ...] (replacement ...)) ;; Here template[t/e ...] denotes the original template ;; with unquoted expressions e replaced by fresh ;; variables t, followed by the appropriate ellipses ;; if e is also spliced. ;; The second part of the return value is the list of ;; replacements, each of the form (t e) if e is just ;; unquoted, or ((t ...) e) if e is also spliced. ;; This will be the list of bindings of the resulting ;; with-syntax expression. (define (expand x level) (syntax-case x (quasisyntax unquote unquote-splicing) ((quasisyntax e) (with-syntax (((k _) x) ; Original must be copied ((rest bs) (expand (syntax e) (+ level 1)))) (syntax ((k . rest) bs)))) ((unquote e) (= level 0) (with-syntax (((t) (generate-temporaries '(t)))) (syntax (t (t e))))) (((unquote e ...) . r) (= level 0) (with-syntax (((rest (b ...)) (expand (syntax r) 0)) ((t ...) (generate-temporaries (syntax (e ...))))) (syntax ((t ... . rest) ((t e) ... b ...))))) (((unquote-splicing e ...) . r) (= level 0) (with-syntax (((rest (b ...)) (expand (syntax r) 0)) ((t ...) (generate-temporaries (syntax (e ...))))) (with-syntax ((((t ...) ...) (syntax ((t (... ...)) ...)))) (syntax ((t ... ... . rest) (((t ...) e) ...)))))) ((k . r) (and (> level 0) (or (free-identifier=? (syntax k) (syntax unquote)) (free-identifier=? (syntax k) (syntax unquote-splicing)))) (with-syntax (((rest bs) (expand (syntax r) (- level 1)))) (syntax ((k . rest) bs)))) ((h . t) (with-syntax (((head (b1 ...)) (expand (syntax h) level)) ((tail (b2 ...)) (expand (syntax t) level))) (syntax ((head . tail) (b1 ... b2 ...))))) (() (syntax (() ()))) (id (identifier? (syntax id)) (syntax (id ()))) (#(e ...) (with-syntax ((((e* ...) bs) (expand (vector->list (syntax #(e ...)) level)))) (syntax (#(e* ...) bs)))) (other (syntax (other ()))))) (with-syntax (((template bindings) (expand x 0))) (syntax (with-syntax bindings (syntax template))))) (syntax-case e () ((k template) (expand-quasisyntax (syntax template)))))) ;;;============================================================= ;;; ;;; Tests ;;; ;;;============================================================== (define-syntax swap! (lambda (e) (syntax-case e () ((_ a b) (let ((a (syntax a)) (b (syntax b))) (quasisyntax (let ((temp ,a)) (set! ,a ,b) (set! ,b temp)))))))) (let ((temp 1) (set! 2)) (swap! set! temp) (values temp set!)) ;==> 2 1 (define-syntax case (lambda (x) (syntax-case x () ((_ e c1 c2 ...) (quasisyntax (let ((t e)) ,(let f ((c1 (syntax c1)) (cmore (syntax (c2 ...)))) (if (null? cmore) (syntax-case c1 (else) ((else e1 e2 ...) (syntax (begin e1 e2 ...))) (((k ...) e1 e2 ...) (syntax (if (memv t '(k ...)) (begin e1 e2 ...))))) (syntax-case c1 () (((k ...) e1 e2 ...) (quasisyntax (if (memv t '(k ...)) (begin e1 e2 ...) ,(f (car cmore) (cdr cmore)))))))))))))) (case 'a ((b c) 'no) ((d a) 'yes)) (define-syntax let-in-order (lambda (form) (syntax-case form () ((_ ((i e) ...) e0 e1 ...) (let f ((ies (syntax ((i e) ...))) (its (syntax ()))) (syntax-case ies () (() (quasisyntax (let ,its e0 e1 ...))) (((i e) . ies) (with-syntax (((t) (generate-temporaries '(t)))) (quasisyntax (let ((t e)) ,(f (syntax ies) (quasisyntax ((i t) ,@its))))))))))))) (let-in-order ((x 1) (y 2)) (+ x y)) ;==> 3 (let-syntax ((test-ellipses-over-unsyntax (lambda (e) (let ((a (syntax a))) (with-syntax (((b ...) (syntax (1 2 3)))) (quasisyntax (quote ((b ,a) ...)))))))) (test-ellipses-over-unsyntax)) ;==> ((1 a) (2 a) (3 a))