c23275fd21f9db5473ed448ffb90de9406c6e428
[bpt/guile.git] / module / slib / synrul.scm
1 ;;; "synrul.scm" Rule-based Syntactic Expanders -*-Scheme-*-
2 ;;; Copyright (c) 1989-91 Massachusetts Institute of Technology
3 ;;;
4 ;;; This material was developed by the Scheme project at the
5 ;;; Massachusetts Institute of Technology, Department of Electrical
6 ;;; Engineering and Computer Science. Permission to copy this
7 ;;; software, to redistribute it, and to use it for any purpose is
8 ;;; granted, subject to the following restrictions and understandings.
9 ;;;
10 ;;; 1. Any copy made of this software must include this copyright
11 ;;; notice in full.
12 ;;;
13 ;;; 2. Users of this software agree to make their best efforts (a) to
14 ;;; return to the MIT Scheme project any improvements or extensions
15 ;;; that they make, so that these may be included in future releases;
16 ;;; and (b) to inform MIT of noteworthy uses of this software.
17 ;;;
18 ;;; 3. All materials developed as a consequence of the use of this
19 ;;; software shall duly acknowledge such use, in accordance with the
20 ;;; usual standards of acknowledging credit in academic research.
21 ;;;
22 ;;; 4. MIT has made no warrantee or representation that the operation
23 ;;; of this software will be error-free, and MIT is under no
24 ;;; obligation to provide any services, by way of maintenance, update,
25 ;;; or otherwise.
26 ;;;
27 ;;; 5. In conjunction with products arising from the use of this
28 ;;; material, there shall be no use of the name of the Massachusetts
29 ;;; Institute of Technology nor of any adaptation thereof in any
30 ;;; advertising, promotional, or sales literature without prior
31 ;;; written consent from MIT in each case.
32
33 ;;;; Rule-based Syntactic Expanders
34
35 ;;; See "Syntactic Extensions in the Programming Language Lisp", by
36 ;;; Eugene Kohlbecker, Ph.D. dissertation, Indiana University, 1986.
37 ;;; See also "Macros That Work", by William Clinger and Jonathan Rees
38 ;;; (reference? POPL?). This implementation is derived from an
39 ;;; implementation by Kent Dybvig, and includes some ideas from
40 ;;; another implementation by Jonathan Rees.
41
42 ;;; The expansion of SYNTAX-RULES references the following keywords:
43 ;;; ER-TRANSFORMER LAMBDA IF BEGIN SET! QUOTE
44 ;;; and the following procedures:
45 ;;; CAR CDR NULL? PAIR? EQUAL? MAP LIST CONS APPEND
46 ;;; ILL-FORMED-SYNTAX
47 ;;; it also uses the anonymous keyword SYNTAX-QUOTE.
48
49 ;;; For testing.
50 ;;;(define (run-sr form)
51 ;;; (expand/syntax-rules form (lambda (x) x) eq?))
52
53 (define (make-syntax-rules-macrology)
54 (make-er-expander-macrology
55 (lambda (define-classifier base-environment)
56 base-environment ;ignore
57 (define-classifier 'SYNTAX-RULES expand/syntax-rules))))
58
59 (define (expand/syntax-rules form rename compare)
60 (if (syntax-match? '((* IDENTIFIER) + ((IDENTIFIER . DATUM) EXPRESSION))
61 (cdr form))
62 (let ((keywords (cadr form))
63 (clauses (cddr form)))
64 (if (let loop ((keywords keywords))
65 (and (pair? keywords)
66 (or (memq (car keywords) (cdr keywords))
67 (loop (cdr keywords)))))
68 (syntax-error "keywords list contains duplicates" keywords)
69 (let ((r-form (rename 'FORM))
70 (r-rename (rename 'RENAME))
71 (r-compare (rename 'COMPARE)))
72 `(,(rename 'ER-TRANSFORMER)
73 (,(rename 'LAMBDA)
74 (,r-form ,r-rename ,r-compare)
75 ,(let loop ((clauses clauses))
76 (if (null? clauses)
77 `(,(rename 'ILL-FORMED-SYNTAX) ,r-form)
78 (let ((pattern (caar clauses)))
79 (let ((sids
80 (parse-pattern rename compare keywords
81 pattern r-form)))
82 `(,(rename 'IF)
83 ,(generate-match rename compare keywords
84 r-rename r-compare
85 pattern r-form)
86 ,(generate-output rename compare r-rename
87 sids (cadar clauses)
88 syntax-error)
89 ,(loop (cdr clauses))))))))))))
90 (ill-formed-syntax form)))
91
92 (define (parse-pattern rename compare keywords pattern expression)
93 (let loop
94 ((pattern pattern)
95 (expression expression)
96 (sids '())
97 (control #f))
98 (cond ((identifier? pattern)
99 (if (memq pattern keywords)
100 sids
101 (cons (make-sid pattern expression control) sids)))
102 ((and (or (zero-or-more? pattern rename compare)
103 (at-least-one? pattern rename compare))
104 (null? (cddr pattern)))
105 (let ((variable ((make-name-generator) 'CONTROL)))
106 (loop (car pattern)
107 variable
108 sids
109 (make-sid variable expression control))))
110 ((pair? pattern)
111 (loop (car pattern)
112 `(,(rename 'CAR) ,expression)
113 (loop (cdr pattern)
114 `(,(rename 'CDR) ,expression)
115 sids
116 control)
117 control))
118 (else sids))))
119
120 (define (generate-match rename compare keywords r-rename r-compare
121 pattern expression)
122 (letrec
123 ((loop
124 (lambda (pattern expression)
125 (cond ((identifier? pattern)
126 (if (memq pattern keywords)
127 (let ((temp (rename 'TEMP)))
128 `((,(rename 'LAMBDA)
129 (,temp)
130 (,(rename 'IF)
131 (,(rename 'IDENTIFIER?) ,temp)
132 (,r-compare ,temp
133 (,r-rename ,(syntax-quote pattern)))
134 #f))
135 ,expression))
136 `#t))
137 ((and (zero-or-more? pattern rename compare)
138 (null? (cddr pattern)))
139 (do-list (car pattern) expression))
140 ((and (at-least-one? pattern rename compare)
141 (null? (cddr pattern)))
142 `(,(rename 'IF) (,(rename 'NULL?) ,expression)
143 #F
144 ,(do-list (car pattern) expression)))
145 ((pair? pattern)
146 (let ((generate-pair
147 (lambda (expression)
148 (conjunction
149 `(,(rename 'PAIR?) ,expression)
150 (conjunction
151 (loop (car pattern)
152 `(,(rename 'CAR) ,expression))
153 (loop (cdr pattern)
154 `(,(rename 'CDR) ,expression)))))))
155 (if (identifier? expression)
156 (generate-pair expression)
157 (let ((temp (rename 'TEMP)))
158 `((,(rename 'LAMBDA) (,temp) ,(generate-pair temp))
159 ,expression)))))
160 ((null? pattern)
161 `(,(rename 'NULL?) ,expression))
162 (else
163 `(,(rename 'EQUAL?) ,expression
164 (,(rename 'QUOTE) ,pattern))))))
165 (do-list
166 (lambda (pattern expression)
167 (let ((r-loop (rename 'LOOP))
168 (r-l (rename 'L))
169 (r-lambda (rename 'LAMBDA)))
170 `(((,r-lambda
171 (,r-loop)
172 (,(rename 'BEGIN)
173 (,(rename 'SET!)
174 ,r-loop
175 (,r-lambda
176 (,r-l)
177 (,(rename 'IF)
178 (,(rename 'NULL?) ,r-l)
179 #T
180 ,(conjunction
181 `(,(rename 'PAIR?) ,r-l)
182 (conjunction (loop pattern `(,(rename 'CAR) ,r-l))
183 `(,r-loop (,(rename 'CDR) ,r-l)))))))
184 ,r-loop))
185 #F)
186 ,expression))))
187 (conjunction
188 (lambda (predicate consequent)
189 (cond ((eq? predicate #T) consequent)
190 ((eq? consequent #T) predicate)
191 (else `(,(rename 'IF) ,predicate ,consequent #F))))))
192 (loop pattern expression)))
193
194 (define (generate-output rename compare r-rename sids template syntax-error)
195 (let loop ((template template) (ellipses '()))
196 (cond ((identifier? template)
197 (let ((sid
198 (let loop ((sids sids))
199 (and (not (null? sids))
200 (if (eq? (sid-name (car sids)) template)
201 (car sids)
202 (loop (cdr sids)))))))
203 (if sid
204 (begin
205 (add-control! sid ellipses syntax-error)
206 (sid-expression sid))
207 `(,r-rename ,(syntax-quote template)))))
208 ((or (zero-or-more? template rename compare)
209 (at-least-one? template rename compare))
210 (optimized-append rename compare
211 (let ((ellipsis (make-ellipsis '())))
212 (generate-ellipsis rename
213 ellipsis
214 (loop (car template)
215 (cons ellipsis
216 ellipses))))
217 (loop (cddr template) ellipses)))
218 ((pair? template)
219 (optimized-cons rename compare
220 (loop (car template) ellipses)
221 (loop (cdr template) ellipses)))
222 (else
223 `(,(rename 'QUOTE) ,template)))))
224
225 (define (add-control! sid ellipses syntax-error)
226 (let loop ((sid sid) (ellipses ellipses))
227 (let ((control (sid-control sid)))
228 (cond (control
229 (if (null? ellipses)
230 (syntax-error "missing ellipsis in expansion" #f)
231 (let ((sids (ellipsis-sids (car ellipses))))
232 (cond ((not (memq control sids))
233 (set-ellipsis-sids! (car ellipses)
234 (cons control sids)))
235 ((not (eq? control (car sids)))
236 (syntax-error "illegal control/ellipsis combination"
237 control sids)))))
238 (loop control (cdr ellipses)))
239 ((not (null? ellipses))
240 (syntax-error "extra ellipsis in expansion" #f))))))
241
242 (define (generate-ellipsis rename ellipsis body)
243 (let ((sids (ellipsis-sids ellipsis)))
244 (let ((name (sid-name (car sids)))
245 (expression (sid-expression (car sids))))
246 (cond ((and (null? (cdr sids))
247 (eq? body name))
248 expression)
249 ((and (null? (cdr sids))
250 (pair? body)
251 (pair? (cdr body))
252 (eq? (cadr body) name)
253 (null? (cddr body)))
254 `(,(rename 'MAP) ,(car body) ,expression))
255 (else
256 `(,(rename 'MAP) (,(rename 'LAMBDA) ,(map sid-name sids) ,body)
257 ,@(map sid-expression sids)))))))
258
259 (define (zero-or-more? pattern rename compare)
260 (and (pair? pattern)
261 (pair? (cdr pattern))
262 (identifier? (cadr pattern))
263 (compare (cadr pattern) (rename '...))))
264
265 (define (at-least-one? pattern rename compare)
266 ;;; (and (pair? pattern)
267 ;;; (pair? (cdr pattern))
268 ;;; (identifier? (cadr pattern))
269 ;;; (compare (cadr pattern) (rename '+)))
270 pattern rename compare ;ignore
271 #f)
272
273 (define (optimized-cons rename compare a d)
274 (cond ((and (pair? d)
275 (compare (car d) (rename 'QUOTE))
276 (pair? (cdr d))
277 (null? (cadr d))
278 (null? (cddr d)))
279 `(,(rename 'LIST) ,a))
280 ((and (pair? d)
281 (compare (car d) (rename 'LIST))
282 (list? (cdr d)))
283 `(,(car d) ,a ,@(cdr d)))
284 (else
285 `(,(rename 'CONS) ,a ,d))))
286
287 (define (optimized-append rename compare x y)
288 (if (and (pair? y)
289 (compare (car y) (rename 'QUOTE))
290 (pair? (cdr y))
291 (null? (cadr y))
292 (null? (cddr y)))
293 x
294 `(,(rename 'APPEND) ,x ,y)))
295
296 (define sid-type
297 (make-record-type "sid" '(NAME EXPRESSION CONTROL OUTPUT-EXPRESSION)))
298
299 (define make-sid
300 (record-constructor sid-type '(NAME EXPRESSION CONTROL)))
301
302 (define sid-name
303 (record-accessor sid-type 'NAME))
304
305 (define sid-expression
306 (record-accessor sid-type 'EXPRESSION))
307
308 (define sid-control
309 (record-accessor sid-type 'CONTROL))
310
311 (define sid-output-expression
312 (record-accessor sid-type 'OUTPUT-EXPRESSION))
313
314 (define set-sid-output-expression!
315 (record-modifier sid-type 'OUTPUT-EXPRESSION))
316
317 (define ellipsis-type
318 (make-record-type "ellipsis" '(SIDS)))
319
320 (define make-ellipsis
321 (record-constructor ellipsis-type '(SIDS)))
322
323 (define ellipsis-sids
324 (record-accessor ellipsis-type 'SIDS))
325
326 (define set-ellipsis-sids!
327 (record-modifier ellipsis-type 'SIDS))