usual.scm 9.0 KB

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