usual.scm 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
  2. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  3. ; This is file usual.scm.
  4. ;;;; Macro expanders for the standard macros
  5. (define the-usual-transforms (make-table))
  6. (define (define-usual-macro name proc aux-names)
  7. (table-set! the-usual-transforms
  8. name
  9. (cons proc aux-names)))
  10. (define (usual-transform name)
  11. (or (table-ref the-usual-transforms name)
  12. (call-error "no such transform" usual-transform name)))
  13. ; Ordinarily we would write #f instead of ,#f below. However, it is
  14. ; useful (although decreasingly so) to be able compile Scheme 48
  15. ; images using a Scheme system that does not distinguish #f from ().
  16. ; In this case, the cross-compiler treats the expression #f (= ()) as
  17. ; boolean false, and any () (= #f) in a quoted constant as the empty
  18. ; list. If we were to write `(if ... #f) then this would be seen in
  19. ; the *target* system as `(if ... ()), which would be a syntax error.
  20. (define-usual-macro 'and
  21. (lambda (exp r c)
  22. (let ((conjuncts (cdr exp)))
  23. (cond ((null? conjuncts) `#t)
  24. ((null? (cdr conjuncts)) (car conjuncts))
  25. (else `(,(r 'if) ,(car conjuncts)
  26. (,(r 'and) ,@(cdr conjuncts))
  27. ,#f)))))
  28. '(if and))
  29. ; Tortuously crafted so as to avoid the need for an (unspecific)
  30. ; procedure. Unspecific values come from IF forms.
  31. (define-usual-macro 'cond
  32. (lambda (exp r c)
  33. (let ((clauses (cdr exp)))
  34. (if (or (null? clauses)
  35. (not (every list? clauses)))
  36. exp
  37. (car (let recur ((clauses clauses))
  38. (if (null? clauses)
  39. '()
  40. (list
  41. (let ((clause (car clauses))
  42. (more (recur (cdr clauses))))
  43. (cond ((c (car clause) (r 'else))
  44. ;; (if (not (null? more)) ...error...)
  45. `(,(r 'begin) ,@(cdr clause)))
  46. ((null? (cdr clause))
  47. `(,(r 'or) ,(car clause)
  48. ,@more))
  49. ((c (cadr clause) (r '=>))
  50. (let ((temp (r 'temp)))
  51. (if (null? (cddr clause))
  52. exp
  53. `(,(r 'let)
  54. ((,temp ,(car clause)))
  55. (,(r 'if) ,temp
  56. (,(caddr clause) ,temp)
  57. ,@more)))))
  58. (else
  59. `(,(r 'if) ,(car clause)
  60. (,(r 'begin) ,@(cdr clause))
  61. ,@more)))))))))))
  62. '(or cond begin let if begin))
  63. (define-usual-macro 'do
  64. (lambda (exp r c)
  65. (if (and (pair? (cdr exp))
  66. (pair? (cddr exp)))
  67. (let ((specs (cadr exp))
  68. (end (caddr exp))
  69. (body (cdddr exp))
  70. (%loop (r 'loop))
  71. (%letrec (r 'letrec))
  72. (%lambda (r 'lambda))
  73. (%cond (r 'cond)))
  74. (if (and (list? specs)
  75. (every do-spec? specs)
  76. (list? end))
  77. `(,%letrec ((,%loop
  78. (,%lambda ,(map car specs)
  79. (,%cond ,end
  80. (else ,@body
  81. (,%loop
  82. ,@(map (lambda (spec)
  83. (if (null? (cddr spec))
  84. (car spec)
  85. (caddr spec)))
  86. specs)))))))
  87. (,%loop ,@(map cadr specs)))
  88. exp))
  89. exp))
  90. '(letrec lambda cond))
  91. (define (do-spec? s)
  92. (and (pair? s)
  93. (name? (car s))
  94. (pair? (cdr s))
  95. (let ((rest (cddr s)))
  96. (or (null? rest)
  97. (and (pair? rest)
  98. (null? (cdr rest)))))))
  99. (define-usual-macro 'let
  100. (lambda (exp r c)
  101. (if (pair? (cdr exp))
  102. (let ((specs (cadr exp))
  103. (body (cddr exp))
  104. (%lambda (r 'lambda)))
  105. (if (name? specs)
  106. (let ((tag specs)
  107. (specs (car body))
  108. (body (cdr body))
  109. (%letrec (r 'letrec)))
  110. (if (specs? specs)
  111. `((,%letrec ((,tag (,%lambda ,(map car specs) ,@body)))
  112. ,tag)
  113. ,@(map cadr specs))
  114. exp))
  115. (if (specs? specs)
  116. `((,%lambda ,(map car specs) ,@body)
  117. ,@(map cadr specs))
  118. exp)))
  119. exp))
  120. '(lambda letrec))
  121. (define-usual-macro 'let*
  122. (lambda (exp r c)
  123. (if (pair? (cdr exp))
  124. (let ((specs (cadr exp))
  125. (body (cddr exp)))
  126. (if (specs? specs)
  127. (if (or (null? specs)
  128. (null? (cdr specs)))
  129. `(,(r 'let) ,specs ,@body)
  130. `(,(r 'let) (,(car specs))
  131. (,(r 'let*) ,(cdr specs) ,@body)))
  132. exp))
  133. exp))
  134. '(let let*))
  135. (define (specs? x)
  136. (or (null? x)
  137. (and (pair? x)
  138. (let ((s (car x)))
  139. (and (pair? s)
  140. (name? (car s))
  141. (pair? (cdr s))
  142. (null? (cddr s))))
  143. (specs? (cdr x)))))
  144. (define-usual-macro 'or
  145. (lambda (exp r c)
  146. (let ((disjuncts (cdr exp)))
  147. (cond ((null? disjuncts)
  148. #f) ;not '#f
  149. ((not (pair? disjuncts))
  150. exp)
  151. ((null? (cdr disjuncts))
  152. (car disjuncts))
  153. (else
  154. (let ((temp (r 'temp)))
  155. `(,(r 'let) ((,temp ,(car disjuncts)))
  156. (,(r 'if) ,temp
  157. ,temp
  158. (,(r 'or) ,@(cdr disjuncts)))))))))
  159. '(let if or))
  160. ; CASE needs auxiliary MEMV.
  161. (define-usual-macro 'case
  162. (lambda (exp r c)
  163. (if (and (list? (cdr exp))
  164. (every (lambda (clause)
  165. (case-clause? clause c (r 'else)))
  166. (cddr exp)))
  167. (let ((key (cadr exp))
  168. (clauses (cddr exp))
  169. (temp (r 'temp))
  170. (%eqv? (r 'eqv?))
  171. (%eq? (r 'eq?)) ;+++ hack for symbols
  172. (%memv (r 'memv))
  173. (%quote (r 'quote))
  174. (%else (r 'else)))
  175. `(,(r 'let)
  176. ((,temp ,key))
  177. (,(r 'cond)
  178. ,@(map (lambda (clause)
  179. `(,(cond ((c (car clause) %else)
  180. (car clause))
  181. ((null? (car clause))
  182. #f)
  183. ((null? (cdar clause)) ;+++
  184. `(,(if (symbol? (caar clauses)) %eq? %eqv?)
  185. ,temp
  186. (,%quote ,(caar clause))))
  187. (else
  188. `(,%memv ,temp (,%quote ,(car clause)))))
  189. ,@(cdr clause)))
  190. clauses))))
  191. exp))
  192. '(let cond eqv? eq? memv quote))
  193. (define (case-clause? c compare %else)
  194. (and (list? c)
  195. (let ((head (car c)))
  196. (or (null? head)
  197. (compare head %else)
  198. (list? head)))))
  199. ; Quasiquote
  200. (define-usual-macro 'quasiquote
  201. (lambda (exp r c)
  202. (define %quote (r 'quote))
  203. (define %quasiquote (r 'quasiquote))
  204. (define %unquote (r 'unquote))
  205. (define %unquote-splicing (r 'unquote-splicing))
  206. (define %append (r 'append))
  207. (define %cons (r 'cons))
  208. (define %list->vector (r 'list->vector))
  209. (define (expand-quasiquote x level)
  210. (descend-quasiquote x level finalize-quasiquote))
  211. (define (finalize-quasiquote mode arg)
  212. (cond ((eq? mode 'quote) `(,%quote ,arg))
  213. ((eq? mode 'unquote) arg)
  214. ((eq? mode 'unquote-splicing)
  215. (syntax-error ",@ in invalid context" arg))
  216. (else `(,mode ,@arg))))
  217. (define (descend-quasiquote x level return)
  218. (cond ((vector? x)
  219. (descend-quasiquote-vector x level return))
  220. ((not (pair? x))
  221. (return 'quote x))
  222. ((interesting-to-quasiquote? x %quasiquote)
  223. (descend-quasiquote-pair x (+ level 1) return))
  224. ((interesting-to-quasiquote? x %unquote)
  225. (cond ((= level 0)
  226. (return 'unquote (cadr x)))
  227. (else
  228. (descend-quasiquote-pair x (- level 1) return))))
  229. ((interesting-to-quasiquote? x %unquote-splicing)
  230. (cond ((= level 0)
  231. (return 'unquote-splicing (cadr x)))
  232. (else
  233. (descend-quasiquote-pair x (- level 1) return))))
  234. (else
  235. (descend-quasiquote-pair x level return))))
  236. (define (descend-quasiquote-pair x level return)
  237. (descend-quasiquote (car x) level
  238. (lambda (car-mode car-arg)
  239. (descend-quasiquote (cdr x) level
  240. (lambda (cdr-mode cdr-arg)
  241. (cond ((and (eq? car-mode 'quote)
  242. (eq? cdr-mode 'quote))
  243. (return 'quote x))
  244. ((eq? car-mode 'unquote-splicing)
  245. ;; (,@mumble ...)
  246. (cond ((and (eq? cdr-mode 'quote) (null? cdr-arg))
  247. (return 'unquote
  248. car-arg))
  249. (else
  250. (return %append
  251. (list car-arg (finalize-quasiquote
  252. cdr-mode cdr-arg))))))
  253. (else
  254. (return %cons
  255. (list (finalize-quasiquote car-mode car-arg)
  256. (finalize-quasiquote cdr-mode cdr-arg))))))))))
  257. (define (descend-quasiquote-vector x level return)
  258. (descend-quasiquote (vector->list x) level
  259. (lambda (mode arg)
  260. (case mode
  261. ((quote) (return 'quote x))
  262. (else (return %list->vector
  263. (list (finalize-quasiquote mode arg))))))))
  264. (define (interesting-to-quasiquote? x marker)
  265. (and (pair? x)
  266. (c (car x) marker)))
  267. (if (and (pair? (cdr exp))
  268. (null? (cddr exp)))
  269. (expand-quasiquote (cadr exp) 0)
  270. exp))
  271. '(append cons list->vector quasiquote unquote unquote-splicing))
  272. ;(define (tst e)
  273. ; (let ((probe (usual-transform (car e))))
  274. ; ((car probe) e (lambda (x) x) eq?)))