From: Andreas Rottmann Subject: [PATCH] Add support for `quasisyntax' --- module/ice-9/boot-9.scm | 117 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 117 insertions(+), 0 deletions(-) diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm index 36a463a..31ebfe0 100644 --- a/module/ice-9/boot-9.scm +++ b/module/ice-9/boot-9.scm @@ -308,6 +308,123 @@ (syntax-rules () ((_ exp) (make-promise (lambda () exp))))) +;; Quasisyntax in terms of syntax-case. +;; +;; Code taken from +;; ; +;; Copyright (c) 2006 Andre van Tonder +;; Copyright statement at http://srfi.schemers.org/srfi-process.html +;; +;;========================================================= +;; +;; To make nested unquote-splicing behave in a useful way, +;; the R5RS-compatible extension of quasiquote in appendix B +;; of the following paper is here ported to quasisyntax: +;; +;; 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) + + ;; Expand returns a list 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 unsyntax unsyntax-splicing) + ((quasisyntax e) + (with-syntax (((k _) x) ;; original identifier must be copied + ((e* reps) (expand (syntax e) (+ level 1)))) + (syntax ((k e*) reps)))) + ((unsyntax e) + (= level 0) + (with-syntax (((t) (generate-temporaries '(t)))) + (syntax (t ((t e)))))) + (((unsyntax e ...) . r) + (= level 0) + (with-syntax (((r* (rep ...)) (expand (syntax r) 0)) + ((t ...) (generate-temporaries (syntax (e ...))))) + (syntax ((t ... . r*) + ((t e) ... rep ...))))) + (((unsyntax-splicing e ...) . r) + (= level 0) + (with-syntax (((r* (rep ...)) (expand (syntax r) 0)) + ((t ...) (generate-temporaries (syntax (e ...))))) + (with-syntax ((((t ...) ...) (syntax ((t (... ...)) ...)))) + (syntax ((t ... ... . r*) + (((t ...) e) ... rep ...)))))) + ((k . r) + (and (> level 0) + (identifier? (syntax k)) + (or (free-identifier=? (syntax k) (syntax unsyntax)) + (free-identifier=? (syntax k) (syntax unsyntax-splicing)))) + (with-syntax (((r* reps) (expand (syntax r) (- level 1)))) + (syntax ((k . r*) reps)))) + ((h . t) + (with-syntax (((h* (rep1 ...)) (expand (syntax h) level)) + ((t* (rep2 ...)) (expand (syntax t) level))) + (syntax ((h* . t*) + (rep1 ... rep2 ...))))) + (#(e ...) + (with-syntax ((((e* ...) reps) + (expand (vector->list (syntax #(e ...))) level))) + (syntax (#(e* ...) reps)))) + (other + (syntax (other ()))))) + + (syntax-case e () + ((_ template) + (with-syntax (((template* replacements) (expand (syntax template) 0))) + (syntax + (with-syntax replacements (syntax template*)))))))) + +(define-syntax unsyntax + (lambda (e) + (syntax-violation 'unsyntax "Invalid expression" e))) + +(define-syntax unsyntax-splicing + (lambda (e) + (syntax-violation 'unsyntax "Invalid expression" e))) ;;; {Defmacros} -- tg: (74deff3..) t/quasisyntax (depends on: master)