usual.scm 12 KB

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