quasisyntax.scm 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. ;; Quasisyntax in terms of syntax-case.
  2. ;;
  3. ;; Code taken from
  4. ;; <http://www.het.brown.edu/people/andre/macros/index.html>;
  5. ;; Copyright (c) 2006 Andre van Tonder. All Rights Reserved.
  6. ;;
  7. ;; Permission is hereby granted, free of charge, to any person
  8. ;; obtaining a copy of this software and associated documentation
  9. ;; files (the "Software"), to deal in the Software without
  10. ;; restriction, including without limitation the rights to use, copy,
  11. ;; modify, merge, publish, distribute, sublicense, and/or sell copies
  12. ;; of the Software, and to permit persons to whom the Software is
  13. ;; furnished to do so, subject to the following conditions:
  14. ;;
  15. ;; The above copyright notice and this permission notice shall be
  16. ;; included in all copies or substantial portions of the Software.
  17. ;;
  18. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19. ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. ;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21. ;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  22. ;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  23. ;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  24. ;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  25. ;; SOFTWARE.
  26. ;;=========================================================
  27. ;;
  28. ;; To make nested unquote-splicing behave in a useful way,
  29. ;; the R5RS-compatible extension of quasiquote in appendix B
  30. ;; of the following paper is here ported to quasisyntax:
  31. ;;
  32. ;; Alan Bawden - Quasiquotation in Lisp
  33. ;; http://citeseer.ist.psu.edu/bawden99quasiquotation.html
  34. ;;
  35. ;; The algorithm converts a quasisyntax expression to an
  36. ;; equivalent with-syntax expression.
  37. ;; For example:
  38. ;;
  39. ;; (quasisyntax (set! #,a #,b))
  40. ;; ==> (with-syntax ((t0 a)
  41. ;; (t1 b))
  42. ;; (syntax (set! t0 t1)))
  43. ;;
  44. ;; (quasisyntax (list #,@args))
  45. ;; ==> (with-syntax (((t ...) args))
  46. ;; (syntax (list t ...)))
  47. ;;
  48. ;; Note that quasisyntax is expanded first, before any
  49. ;; ellipses act. For example:
  50. ;;
  51. ;; (quasisyntax (f ((b #,a) ...))
  52. ;; ==> (with-syntax ((t a))
  53. ;; (syntax (f ((b t) ...))))
  54. ;;
  55. ;; so that
  56. ;;
  57. ;; (let-syntax ((test-ellipses-over-unsyntax
  58. ;; (lambda (e)
  59. ;; (let ((a (syntax a)))
  60. ;; (with-syntax (((b ...) (syntax (1 2 3))))
  61. ;; (quasisyntax
  62. ;; (quote ((b #,a) ...))))))))
  63. ;; (test-ellipses-over-unsyntax))
  64. ;;
  65. ;; ==> ((1 a) (2 a) (3 a))
  66. (define-syntax quasisyntax
  67. (lambda (e)
  68. ;; Expand returns a list of the form
  69. ;; [template[t/e, ...] (replacement ...)]
  70. ;; Here template[t/e ...] denotes the original template
  71. ;; with unquoted expressions e replaced by fresh
  72. ;; variables t, followed by the appropriate ellipses
  73. ;; if e is also spliced.
  74. ;; The second part of the return value is the list of
  75. ;; replacements, each of the form (t e) if e is just
  76. ;; unquoted, or ((t ...) e) if e is also spliced.
  77. ;; This will be the list of bindings of the resulting
  78. ;; with-syntax expression.
  79. (define (expand x level)
  80. (syntax-case x (quasisyntax unsyntax unsyntax-splicing)
  81. ((quasisyntax e)
  82. (with-syntax (((k _) x) ;; original identifier must be copied
  83. ((e* reps) (expand (syntax e) (+ level 1))))
  84. (syntax ((k e*) reps))))
  85. ((unsyntax e)
  86. (= level 0)
  87. (with-syntax (((t) (generate-temporaries '(t))))
  88. (syntax (t ((t e))))))
  89. (((unsyntax e ...) . r)
  90. (= level 0)
  91. (with-syntax (((r* (rep ...)) (expand (syntax r) 0))
  92. ((t ...) (generate-temporaries (syntax (e ...)))))
  93. (syntax ((t ... . r*)
  94. ((t e) ... rep ...)))))
  95. (((unsyntax-splicing e ...) . r)
  96. (= level 0)
  97. (with-syntax (((r* (rep ...)) (expand (syntax r) 0))
  98. ((t ...) (generate-temporaries (syntax (e ...)))))
  99. (with-syntax ((((t ...) ...) (syntax ((t (... ...)) ...))))
  100. (syntax ((t ... ... . r*)
  101. (((t ...) e) ... rep ...))))))
  102. ((k . r)
  103. (and (> level 0)
  104. (identifier? (syntax k))
  105. (or (free-identifier=? (syntax k) (syntax unsyntax))
  106. (free-identifier=? (syntax k) (syntax unsyntax-splicing))))
  107. (with-syntax (((r* reps) (expand (syntax r) (- level 1))))
  108. (syntax ((k . r*) reps))))
  109. ((h . t)
  110. (with-syntax (((h* (rep1 ...)) (expand (syntax h) level))
  111. ((t* (rep2 ...)) (expand (syntax t) level)))
  112. (syntax ((h* . t*)
  113. (rep1 ... rep2 ...)))))
  114. (#(e ...)
  115. (with-syntax ((((e* ...) reps)
  116. (expand (vector->list (syntax #(e ...))) level)))
  117. (syntax (#(e* ...) reps))))
  118. (other
  119. (syntax (other ())))))
  120. (syntax-case e ()
  121. ((_ template)
  122. (with-syntax (((template* replacements) (expand (syntax template) 0)))
  123. (syntax
  124. (with-syntax replacements (syntax template*))))))))
  125. (define-syntax unsyntax
  126. (lambda (e)
  127. (syntax-violation 'unsyntax "Invalid expression" e)))
  128. (define-syntax unsyntax-splicing
  129. (lambda (e)
  130. (syntax-violation 'unsyntax "Invalid expression" e)))