nendo 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,672 @@
1
+ ;;;-*- mode: nendo; syntax: scheme -*-;;
2
+ ;;;
3
+ ;;;; match.scm -- portable hygienic pattern matcher
4
+ ;;
5
+ ;; This code is written by Alex Shinn and placed in the
6
+ ;; Public Domain. All warranties are disclaimed.
7
+
8
+ ;; This is a full superset of the popular MATCH package by Andrew
9
+ ;; Wright, written in fully portable SYNTAX-RULES (R5RS only, breaks
10
+ ;; in R6RS SYNTAX-RULES), and thus preserving hygiene.
11
+
12
+ ;; This is a simple generative pattern matcher - each pattern is
13
+ ;; expanded into the required tests, calling a failure continuation if
14
+ ;; the tests fail. This makes the logic easy to follow and extend,
15
+ ;; but produces sub-optimal code in cases where you have many similar
16
+ ;; clauses due to repeating the same tests. Nonetheless a smart
17
+ ;; compiler should be able to remove the redundant tests. For
18
+ ;; MATCH-LET and DESTRUCTURING-BIND type uses there is no performance
19
+ ;; hit.
20
+
21
+ ;; The original version was written on 2006/11/29 and described in the
22
+ ;; following Usenet post:
23
+ ;; http://groups.google.com/group/comp.lang.scheme/msg/0941234de7112ffd
24
+ ;; and is still available at
25
+ ;; http://synthcode.com/scheme/match-simple.scm
26
+ ;; It's just 80 lines for the core MATCH, and an extra 40 lines for
27
+ ;; MATCH-LET, MATCH-LAMBDA and other syntactic sugar.
28
+ ;;
29
+ ;; A variant of this file which uses COND-EXPAND in a few places for
30
+ ;; performance can be found at
31
+ ;; http://synthcode.com/scheme/match-cond-expand.scm
32
+ ;;
33
+ ;; 2009/11/25 - adding `***' tree search patterns
34
+ ;; 2008/03/20 - fixing bug where (a ...) matched non-lists
35
+ ;; 2008/03/15 - removing redundant check in vector patterns
36
+ ;; 2008/03/06 - you can use `...' portably now (thanks to Taylor Campbell)
37
+ ;; 2007/09/04 - fixing quasiquote patterns
38
+ ;; 2007/07/21 - allowing ellipse patterns in non-final list positions
39
+ ;; 2007/04/10 - fixing potential hygiene issue in match-check-ellipse
40
+ ;; (thanks to Taylor Campbell)
41
+ ;; 2007/04/08 - clean up, commenting
42
+ ;; 2006/12/24 - bugfixes
43
+ ;; 2006/12/01 - non-linear patterns, shared variables in OR, get!/set!
44
+
45
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
46
+ ;; force compile-time syntax errors with useful messages
47
+
48
+ (define-syntax match-syntax-error
49
+ (syntax-rules ()
50
+ ((_) (match-syntax-error "invalid match-syntax-error usage"))))
51
+
52
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
53
+
54
+ ;; The basic interface. MATCH just performs some basic syntax
55
+ ;; validation, binds the match expression to a temporary variable `v',
56
+ ;; and passes it on to MATCH-NEXT. It's a constant throughout the
57
+ ;; code below that the binding `v' is a direct variable reference, not
58
+ ;; an expression.
59
+
60
+ (define-syntax match
61
+ (syntax-rules ()
62
+ ((match)
63
+ (match-syntax-error "missing match expression"))
64
+ ((match atom)
65
+ (match-syntax-error "no match clauses"))
66
+ ((match (app ...) (pat . body) ...)
67
+ (let ((v (app ...)))
68
+ (match-next v ((app ...) (set! (app ...))) (pat . body) ...)))
69
+ ((match #(vec ...) (pat . body) ...)
70
+ (let ((v #(vec ...)))
71
+ (match-next v (v (set! v)) (pat . body) ...)))
72
+ ((match atom (pat . body) ...)
73
+ (match-next atom (atom (set! atom)) (pat . body) ...))
74
+ ))
75
+
76
+ ;; MATCH-NEXT passes each clause to MATCH-ONE in turn with its failure
77
+ ;; thunk, which is expanded by recursing MATCH-NEXT on the remaining
78
+ ;; clauses. `g+s' is a list of two elements, the get! and set!
79
+ ;; expressions respectively.
80
+
81
+ (define-syntax match-next
82
+ (syntax-rules (=>)
83
+ ;; no more clauses, the match failed
84
+ ((match-next v g+s)
85
+ (error "Error: match: no matching pattern"))
86
+ ;; named failure continuation
87
+ ((match-next v g+s (pat (=> failure) . body) . rest)
88
+ (let ((failure (lambda () (match-next v g+s . rest))))
89
+ ;; match-one analyzes the pattern for us
90
+ (match-one v pat g+s (match-drop-ids (begin . body)) (failure) ())))
91
+ ;; anonymous failure continuation, give it a dummy name
92
+ ((match-next v g+s (pat . body) . rest)
93
+ (match-next v g+s (pat (=> failure) . body) . rest))))
94
+
95
+ ;; MATCH-ONE first checks for ellipse patterns, otherwise passes on to
96
+ ;; MATCH-TWO.
97
+
98
+ (define-syntax match-one
99
+ (syntax-rules ()
100
+ ;; If it's a list of two or more values, check to see if the
101
+ ;; second one is an ellipse and handle accordingly, otherwise go
102
+ ;; to MATCH-TWO.
103
+ ((match-one v (p q . r) g+s sk fk i)
104
+ (match-check-ellipse
105
+ q
106
+ (match-extract-vars p (match-gen-ellipses v p r g+s sk fk i) i ())
107
+ (match-two v (p q . r) g+s sk fk i)))
108
+ ;; Go directly to MATCH-TWO.
109
+ ((match-one . x)
110
+ (match-two . x))))
111
+
112
+ ;; This is the guts of the pattern matcher. We are passed a lot of
113
+ ;; information in the form:
114
+ ;;
115
+ ;; (match-two var pattern getter setter success-k fail-k (ids ...))
116
+ ;;
117
+ ;; usually abbreviated
118
+ ;;
119
+ ;; (match-two v p g+s sk fk i)
120
+ ;;
121
+ ;; where VAR is the symbol name of the current variable we are
122
+ ;; matching, PATTERN is the current pattern, getter and setter are the
123
+ ;; corresponding accessors (e.g. CAR and SET-CAR! of the pair holding
124
+ ;; VAR), SUCCESS-K is the success continuation, FAIL-K is the failure
125
+ ;; continuation (which is just a thunk call and is thus safe to expand
126
+ ;; multiple times) and IDS are the list of identifiers bound in the
127
+ ;; pattern so far.
128
+
129
+ (define-syntax match-two
130
+ (syntax-rules (_ ___ *** quote quasiquote ? $ = and or not set! get!)
131
+ ((match-two v () g+s (sk ...) fk i)
132
+ (if (null? v) (sk ... i) fk))
133
+ ((match-two v (quote p) g+s (sk ...) fk i)
134
+ (if (equal? v 'p) (sk ... i) fk))
135
+ ((match-two v (quasiquote p) . x)
136
+ (match-quasiquote v p . x))
137
+ ((match-two v (and) g+s (sk ...) fk i) (sk ... i))
138
+ ((match-two v (and p q ...) g+s sk fk i)
139
+ (match-one v p g+s (match-one v (and q ...) g+s sk fk) fk i))
140
+ ((match-two v (or) g+s sk fk i) fk)
141
+ ((match-two v (or p) . x)
142
+ (match-one v p . x))
143
+ ((match-two v (or p ...) g+s sk fk i)
144
+ (match-extract-vars (or p ...) (match-gen-or v (p ...) g+s sk fk i) i ()))
145
+ ((match-two v (not p) g+s (sk ...) fk i)
146
+ (match-one v p g+s (match-drop-ids fk) (sk ... i) i))
147
+ ((match-two v (get! getter) (g s) (sk ...) fk i)
148
+ (let ((getter (lambda () g))) (sk ... i)))
149
+ ((match-two v (set! setter) (g (s ...)) (sk ...) fk i)
150
+ (let ((setter (lambda (x) (s ... x)))) (sk ... i)))
151
+ ((match-two v (? pred . p) g+s sk fk i)
152
+ (if (pred v) (match-one v (and . p) g+s sk fk i) fk))
153
+ ((match-two v (= proc p) . x)
154
+ (let ((w (proc v))) (match-one w p . x)))
155
+ ((match-two v (p ___ . r) g+s sk fk i)
156
+ (match-extract-vars p (match-gen-ellipses v p r g+s sk fk i) i ()))
157
+ ((match-two v (p) g+s sk fk i)
158
+ (if (and (pair? v) (null? (cdr v)))
159
+ (let ((w (car v)))
160
+ (match-one w p ((car v) (set-car! v)) sk fk i))
161
+ fk))
162
+ ((match-two v (p *** q) g+s sk fk i)
163
+ (match-extract-vars p (match-gen-search v p q g+s sk fk i) i ()))
164
+ ((match-two v (p *** . q) g+s sk fk i)
165
+ (match-syntax-error "invalid use of ***" (p *** . q)))
166
+ ((match-two v (p . q) g+s sk fk i)
167
+ (if (pair? v)
168
+ (let ((w (car v)) (x (cdr v)))
169
+ (match-one w p ((car v) (set-car! v))
170
+ (match-one x q ((cdr v) (set-cdr! v)) sk fk)
171
+ fk
172
+ i))
173
+ fk))
174
+ ((match-two v #(p ...) g+s . x)
175
+ (match-vector v 0 () (p ...) . x))
176
+ ((match-two v _ g+s (sk ...) fk i) (sk ... i))
177
+ ;; Not a pair or vector or special literal, test to see if it's a
178
+ ;; new symbol, in which case we just bind it, or if it's an
179
+ ;; already bound symbol or some other literal, in which case we
180
+ ;; compare it with EQUAL?.
181
+ ((match-two v x g+s (sk ...) fk (id ...))
182
+ (let-syntax
183
+ ((new-sym?
184
+ (syntax-rules (id ...)
185
+ ((new-sym? x sk2 fk2) sk2)
186
+ ((new-sym? y sk2 fk2) fk2))))
187
+ (new-sym? random-sym-to-match
188
+ (let ((x v)) (sk ... (id ... x)))
189
+ (if (equal? v x) (sk ... (id ...)) fk))))
190
+ ))
191
+
192
+ ;; QUASIQUOTE patterns
193
+
194
+ (define-syntax match-quasiquote
195
+ (syntax-rules (unquote unquote-splicing quasiquote)
196
+ ((_ v (unquote p) g+s sk fk i)
197
+ (match-one v p g+s sk fk i))
198
+ ((_ v ((unquote-splicing p) . rest) g+s sk fk i)
199
+ (if (pair? v)
200
+ (match-one v
201
+ (p . tmp)
202
+ (match-quasiquote tmp rest g+s sk fk)
203
+ fk
204
+ i)
205
+ fk))
206
+ ((_ v (quasiquote p) g+s sk fk i . depth)
207
+ (match-quasiquote v p g+s sk fk i #f . depth))
208
+ ((_ v (unquote p) g+s sk fk i x . depth)
209
+ (match-quasiquote v p g+s sk fk i . depth))
210
+ ((_ v (unquote-splicing p) g+s sk fk i x . depth)
211
+ (match-quasiquote v p g+s sk fk i . depth))
212
+ ((_ v (p . q) g+s sk fk i . depth)
213
+ (if (pair? v)
214
+ (let ((w (car v)) (x (cdr v)))
215
+ (match-quasiquote
216
+ w p g+s
217
+ (match-quasiquote-step x q g+s sk fk depth)
218
+ fk i . depth))
219
+ fk))
220
+ ((_ v #(elt ...) g+s sk fk i . depth)
221
+ (if (vector? v)
222
+ (let ((ls (vector->list v)))
223
+ (match-quasiquote ls (elt ...) g+s sk fk i . depth))
224
+ fk))
225
+ ((_ v x g+s sk fk i . depth)
226
+ (match-one v 'x g+s sk fk i))))
227
+
228
+ (define-syntax match-quasiquote-step
229
+ (syntax-rules ()
230
+ ((match-quasiquote-step x q g+s sk fk depth i)
231
+ (match-quasiquote x q g+s sk fk i . depth))))
232
+
233
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
234
+ ;; Utilities
235
+
236
+ ;; Takes two values and just expands into the first.
237
+ (define-syntax match-drop-ids
238
+ (syntax-rules ()
239
+ ((_ expr ids ...) expr)))
240
+
241
+ (define-syntax match-drop-first-arg
242
+ (syntax-rules ()
243
+ ((_ arg expr) expr)))
244
+
245
+ ;; To expand an OR group we try each clause in succession, passing the
246
+ ;; first that succeeds to the success continuation. On failure for
247
+ ;; any clause, we just try the next clause, finally resorting to the
248
+ ;; failure continuation fk if all clauses fail. The only trick is
249
+ ;; that we want to unify the identifiers, so that the success
250
+ ;; continuation can refer to a variable from any of the OR clauses.
251
+
252
+ (define-syntax match-gen-or
253
+ (syntax-rules ()
254
+ ((_ v p g+s (sk ...) fk (i ...) ((id id-ls) ...))
255
+ (let ((sk2 (lambda (id ...) (sk ... (i ... id ...)))))
256
+ (match-gen-or-step v p g+s (match-drop-ids (sk2 id ...)) fk (i ...))))))
257
+
258
+ (define-syntax match-gen-or-step
259
+ (syntax-rules ()
260
+ ((_ v () g+s sk fk . x)
261
+ ;; no OR clauses, call the failure continuation
262
+ fk)
263
+ ((_ v (p) . x)
264
+ ;; last (or only) OR clause, just expand normally
265
+ (match-one v p . x))
266
+ ((_ v (p . q) g+s sk fk i)
267
+ ;; match one and try the remaining on failure
268
+ (match-one v p g+s sk (match-gen-or-step v q g+s sk fk i) i))
269
+ ))
270
+
271
+ ;; We match a pattern (p ...) by matching the pattern p in a loop on
272
+ ;; each element of the variable, accumulating the bound ids into lists.
273
+
274
+ ;; Look at the body of the simple case - it's just a named let loop,
275
+ ;; matching each element in turn to the same pattern. The only trick
276
+ ;; is that we want to keep track of the lists of each extracted id, so
277
+ ;; when the loop recurses we cons the ids onto their respective list
278
+ ;; variables, and on success we bind the ids (what the user input and
279
+ ;; expects to see in the success body) to the reversed accumulated
280
+ ;; list IDs.
281
+
282
+ (define-syntax match-gen-ellipses
283
+ (syntax-rules ()
284
+ ((_ v p () g+s (sk ...) fk i ((id id-ls) ...))
285
+ (match-check-identifier p
286
+ ;; simplest case equivalent to (p ...), just bind the list
287
+ (let ((p v))
288
+ (if (list? p)
289
+ (sk ... i)
290
+ fk))
291
+ ;; simple case, match all elements of the list
292
+ (let loop ((ls v) (id-ls '()) ...)
293
+ (cond
294
+ ((null? ls)
295
+ (let ((id (reverse id-ls)) ...) (sk ... i)))
296
+ ((pair? ls)
297
+ (let ((w (car ls)))
298
+ (match-one w p ((car ls) (set-car! ls))
299
+ (match-drop-ids (loop (cdr ls) (cons id id-ls) ...))
300
+ fk i)))
301
+ (else
302
+ fk)))))
303
+ ((_ v p r g+s (sk ...) fk i ((id id-ls) ...))
304
+ ;; general case, trailing patterns to match, keep track of the
305
+ ;; remaining list length so we don't need any backtracking
306
+ (match-verify-no-ellipses
307
+ r
308
+ (let* ((tail-len (length 'r))
309
+ (ls v)
310
+ (len (length ls)))
311
+ (if (< len tail-len)
312
+ fk
313
+ (let loop ((ls ls) (n len) (id-ls '()) ...)
314
+ (cond
315
+ ((= n tail-len)
316
+ (let ((id (reverse id-ls)) ...)
317
+ (match-one ls r (#f #f) (sk ... i) fk i)))
318
+ ((pair? ls)
319
+ (let ((w (car ls)))
320
+ (match-one w p ((car ls) (set-car! ls))
321
+ (match-drop-ids
322
+ (loop (cdr ls) (- n 1) (cons id id-ls) ...))
323
+ fk
324
+ i)))
325
+ (else
326
+ fk)))))))))
327
+
328
+ ;; This is just a safety check. Although unlike syntax-rules we allow
329
+ ;; trailing patterns after an ellipses, we explicitly disable multiple
330
+ ;; ellipses at the same level. This is because in the general case
331
+ ;; such patterns are exponential in the number of ellipses, and we
332
+ ;; don't want to make it easy to construct very expensive operations
333
+ ;; with simple looking patterns. For example, it would be O(n^2) for
334
+ ;; patterns like (a ... b ...) because we must consider every trailing
335
+ ;; element for every possible break for the leading "a ...".
336
+
337
+ (define-syntax match-verify-no-ellipses
338
+ (syntax-rules ()
339
+ ((_ (x . y) sk)
340
+ (match-check-ellipse
341
+ x
342
+ (match-syntax-error
343
+ "multiple ellipse patterns not allowed at same level")
344
+ (match-verify-no-ellipses y sk)))
345
+ ((_ () sk)
346
+ sk)
347
+ ((_ x sk)
348
+ (match-syntax-error "dotted tail not allowed after ellipse" x))))
349
+
350
+ ;; Matching a tree search pattern is only slightly more complicated.
351
+ ;; Here we allow patterns of the form
352
+ ;;
353
+ ;; (x *** y)
354
+ ;;
355
+ ;; to represent the pattern y located somewhere in a tree where the
356
+ ;; path from the current object to y can be seen as a list of the form
357
+ ;; (X ...). Y can immediately match the current object in which case
358
+ ;; the path is the empty list. In a sense it's a 2-dimensional
359
+ ;; version of the ... pattern.
360
+ ;;
361
+ ;; As a common case the pattern (_ *** y) can be used to search for Y
362
+ ;; anywhere in a tree, regardless of the path used.
363
+ ;;
364
+ ;; To implement the search, we use two recursive procedures. TRY
365
+ ;; attempts to match Y once, and on success it calls the normal SK on
366
+ ;; the accumulated list ids as in MATCH-GEN-ELLIPSES. On failure, we
367
+ ;; call NEXT which first checks if the current value is a list
368
+ ;; beginning with X, then calls TRY on each remaining element of the
369
+ ;; list. Since TRY will recursively call NEXT again on failure, this
370
+ ;; effects a full depth-first search.
371
+ ;;
372
+ ;; The failure continuation throughout is a jump to the next step in
373
+ ;; the tree search, initialized with the original failure continuation
374
+ ;; FK.
375
+
376
+ (define-syntax match-gen-search
377
+ (syntax-rules ()
378
+ ((match-gen-search v p q g+s sk fk i ((id id-ls) ...))
379
+ (letrec ((try (lambda (w fail id-ls ...)
380
+ (match-one w q g+s
381
+ (match-drop-ids
382
+ (let ((id (reverse id-ls)) ...)
383
+ sk))
384
+ (next w fail id-ls ...) i)))
385
+ (next (lambda (w fail id-ls ...)
386
+ (if (not (pair? w))
387
+ (fail)
388
+ (let ((u (car w)))
389
+ (match-one
390
+ u p ((car w) (set-car! w))
391
+ (match-drop-ids
392
+ ;; accumulate the head variables from
393
+ ;; the p pattern, and loop over the tail
394
+ (let ((id-ls (cons id id-ls)) ...)
395
+ (let lp ((ls (cdr w)))
396
+ (if (pair? ls)
397
+ (try (car ls)
398
+ (lambda () (lp (cdr ls)))
399
+ id-ls ...)
400
+ (fail)))))
401
+ (fail) i))))))
402
+ ;; the initial id-ls binding here is a dummy to get the right
403
+ ;; number of '()s
404
+ (let ((id-ls '()) ...)
405
+ (try v (lambda () fk) id-ls ...))))))
406
+
407
+ ;; Vector patterns are just more of the same, with the slight
408
+ ;; exception that we pass around the current vector index being
409
+ ;; matched.
410
+
411
+ (define-syntax match-vector
412
+ (syntax-rules (___)
413
+ ((_ v n pats (p q) . x)
414
+ (match-check-ellipse q
415
+ (match-gen-vector-ellipses v n pats p . x)
416
+ (match-vector-two v n pats (p q) . x)))
417
+ ((_ v n pats (p ___) sk fk i)
418
+ (match-gen-vector-ellipses v n pats p sk fk i))
419
+ ((_ . x)
420
+ (match-vector-two . x))))
421
+
422
+ ;; Check the exact vector length, then check each element in turn.
423
+
424
+ (define-syntax match-vector-two
425
+ (syntax-rules ()
426
+ ((_ v n ((pat index) ...) () sk fk i)
427
+ (if (vector? v)
428
+ (let ((len (vector-length v)))
429
+ (if (= len n)
430
+ (match-vector-step v ((pat index) ...) sk fk i)
431
+ fk))
432
+ fk))
433
+ ((_ v n (pats ...) (p . q) . x)
434
+ (match-vector v (+ n 1) (pats ... (p n)) q . x))))
435
+
436
+ (define-syntax match-vector-step
437
+ (syntax-rules ()
438
+ ((_ v () (sk ...) fk i) (sk ... i))
439
+ ((_ v ((pat index) . rest) sk fk i)
440
+ (let ((w (vector-ref v index)))
441
+ (match-one w pat ((vector-ref v index) (vector-set! v index))
442
+ (match-vector-step v rest sk fk)
443
+ fk i)))))
444
+
445
+ ;; With a vector ellipse pattern we first check to see if the vector
446
+ ;; length is at least the required length.
447
+
448
+ (define-syntax match-gen-vector-ellipses
449
+ (syntax-rules ()
450
+ ((_ v n ((pat index) ...) p sk fk i)
451
+ (if (vector? v)
452
+ (let ((len (vector-length v)))
453
+ (if (>= len n)
454
+ (match-vector-step v ((pat index) ...)
455
+ (match-vector-tail v p n len sk fk)
456
+ fk i)
457
+ fk))
458
+ fk))))
459
+
460
+ (define-syntax match-vector-tail
461
+ (syntax-rules ()
462
+ ((_ v p n len sk fk i)
463
+ (match-extract-vars p (match-vector-tail-two v p n len sk fk i) i ()))))
464
+
465
+ (define-syntax match-vector-tail-two
466
+ (syntax-rules ()
467
+ ((_ v p n len (sk ...) fk i ((id id-ls) ...))
468
+ (let loop ((j n) (id-ls '()) ...)
469
+ (if (>= j len)
470
+ (let ((id (reverse id-ls)) ...) (sk ... i))
471
+ (let ((w (vector-ref v j)))
472
+ (match-one w p ((vector-ref v j) (vetor-set! v j))
473
+ (match-drop-ids (loop (+ j 1) (cons id id-ls) ...))
474
+ fk i)))))))
475
+
476
+ ;; Extract all identifiers in a pattern. A little more complicated
477
+ ;; than just looking for symbols, we need to ignore special keywords
478
+ ;; and non-pattern forms (such as the predicate expression in ?
479
+ ;; patterns), and also ignore previously bound identifiers.
480
+ ;;
481
+ ;; Calls the continuation with all new vars as a list of the form
482
+ ;; ((orig-var tmp-name) ...), where tmp-name can be used to uniquely
483
+ ;; pair with the original variable (e.g. it's used in the ellipse
484
+ ;; generation for list variables).
485
+ ;;
486
+ ;; (match-extract-vars pattern continuation (ids ...) (new-vars ...))
487
+
488
+ (define-syntax match-extract-vars
489
+ (syntax-rules (_ ___ *** ? $ = quote quasiquote and or not get! set!)
490
+ ((match-extract-vars (? pred . p) . x)
491
+ (match-extract-vars p . x))
492
+ ((match-extract-vars ($ rec . p) . x)
493
+ (match-extract-vars p . x))
494
+ ((match-extract-vars (= proc p) . x)
495
+ (match-extract-vars p . x))
496
+ ((match-extract-vars (quote x) (k ...) i v)
497
+ (k ... v))
498
+ ((match-extract-vars (quasiquote x) k i v)
499
+ (match-extract-quasiquote-vars x k i v (#t)))
500
+ ((match-extract-vars (and . p) . x)
501
+ (match-extract-vars p . x))
502
+ ((match-extract-vars (or . p) . x)
503
+ (match-extract-vars p . x))
504
+ ((match-extract-vars (not . p) . x)
505
+ (match-extract-vars p . x))
506
+ ;; A non-keyword pair, expand the CAR with a continuation to
507
+ ;; expand the CDR.
508
+ ((match-extract-vars (p q . r) k i v)
509
+ (match-check-ellipse
510
+ q
511
+ (match-extract-vars (p . r) k i v)
512
+ (match-extract-vars p (match-extract-vars-step (q . r) k i v) i ())))
513
+ ((match-extract-vars (p . q) k i v)
514
+ (match-extract-vars p (match-extract-vars-step q k i v) i ()))
515
+ ((match-extract-vars #(p ...) . x)
516
+ (match-extract-vars (p ...) . x))
517
+ ((match-extract-vars _ (k ...) i v) (k ... v))
518
+ ((match-extract-vars ___ (k ...) i v) (k ... v))
519
+ ((match-extract-vars *** (k ...) i v) (k ... v))
520
+ ;; This is the main part, the only place where we might add a new
521
+ ;; var if it's an unbound symbol.
522
+ ((match-extract-vars p (k ...) (i ...) v)
523
+ (let-syntax
524
+ ((new-sym?
525
+ (syntax-rules (i ...)
526
+ ((new-sym? p sk fk) sk)
527
+ ((new-sym? x sk fk) fk))))
528
+ (new-sym? random-sym-to-match
529
+ (k ... ((p p-ls) . v))
530
+ (k ... v))))
531
+ ))
532
+
533
+ ;; Stepper used in the above so it can expand the CAR and CDR
534
+ ;; separately.
535
+
536
+ (define-syntax match-extract-vars-step
537
+ (syntax-rules ()
538
+ ((_ p k i v ((v2 v2-ls) ...))
539
+ (match-extract-vars p k (v2 ... . i) ((v2 v2-ls) ... . v)))
540
+ ))
541
+
542
+ (define-syntax match-extract-quasiquote-vars
543
+ (syntax-rules (quasiquote unquote unquote-splicing)
544
+ ((match-extract-quasiquote-vars (quasiquote x) k i v d)
545
+ (match-extract-quasiquote-vars x k i v (#t . d)))
546
+ ((match-extract-quasiquote-vars (unquote-splicing x) k i v d)
547
+ (match-extract-quasiquote-vars (unquote x) k i v d))
548
+ ((match-extract-quasiquote-vars (unquote x) k i v (#t))
549
+ (match-extract-vars x k i v))
550
+ ((match-extract-quasiquote-vars (unquote x) k i v (#t . d))
551
+ (match-extract-quasiquote-vars x k i v d))
552
+ ((match-extract-quasiquote-vars (x . y) k i v (#t . d))
553
+ (match-extract-quasiquote-vars
554
+ x
555
+ (match-extract-quasiquote-vars-step y k i v d) i ()))
556
+ ((match-extract-quasiquote-vars #(x ...) k i v (#t . d))
557
+ (match-extract-quasiquote-vars (x ...) k i v d))
558
+ ((match-extract-quasiquote-vars x (k ...) i v (#t . d))
559
+ (k ... v))
560
+ ))
561
+
562
+ (define-syntax match-extract-quasiquote-vars-step
563
+ (syntax-rules ()
564
+ ((_ x k i v d ((v2 v2-ls) ...))
565
+ (match-extract-quasiquote-vars x k (v2 ... . i) ((v2 v2-ls) ... . v) d))
566
+ ))
567
+
568
+
569
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
570
+ ;; Gimme some sugar baby.
571
+
572
+ (define-syntax match-lambda
573
+ (syntax-rules ()
574
+ ((_ clause ...) (lambda (expr) (match expr clause ...)))))
575
+
576
+ (define-syntax match-lambda*
577
+ (syntax-rules ()
578
+ ((_ clause ...) (lambda expr (match expr clause ...)))))
579
+
580
+ (define-syntax match-let
581
+ (syntax-rules ()
582
+ ((_ (vars ...) . body)
583
+ (match-let/helper let () () (vars ...) . body))
584
+ ((_ loop . rest)
585
+ (match-named-let loop () . rest))))
586
+
587
+ (define-syntax match-letrec
588
+ (syntax-rules ()
589
+ ((_ vars . body) (match-let/helper letrec () () vars . body))))
590
+
591
+ (define-syntax match-let/helper
592
+ (syntax-rules ()
593
+ ((_ let ((var expr) ...) () () . body)
594
+ (let ((var expr) ...) . body))
595
+ ((_ let ((var expr) ...) ((pat tmp) ...) () . body)
596
+ (let ((var expr) ...)
597
+ (match-let* ((pat tmp) ...)
598
+ . body)))
599
+ ((_ let (v ...) (p ...) (((a . b) expr) . rest) . body)
600
+ (match-let/helper
601
+ let (v ... (tmp expr)) (p ... ((a . b) tmp)) rest . body))
602
+ ((_ let (v ...) (p ...) ((#(a ...) expr) . rest) . body)
603
+ (match-let/helper
604
+ let (v ... (tmp expr)) (p ... (#(a ...) tmp)) rest . body))
605
+ ((_ let (v ...) (p ...) ((a expr) . rest) . body)
606
+ (match-let/helper let (v ... (a expr)) (p ...) rest . body))))
607
+
608
+ (define-syntax match-named-let
609
+ (syntax-rules ()
610
+ ((_ loop ((pat expr var) ...) () . body)
611
+ (let loop ((var expr) ...)
612
+ (match-let ((pat var) ...)
613
+ . body)))
614
+ ((_ loop (v ...) ((pat expr) . rest) . body)
615
+ (match-named-let loop (v ... (pat expr tmp)) rest . body))))
616
+
617
+ (define-syntax match-let*
618
+ (syntax-rules ()
619
+ ((_ () . body)
620
+ (begin . body))
621
+ ((_ ((pat expr) . rest) . body)
622
+ (match expr (pat (match-let* rest . body))))))
623
+
624
+
625
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
626
+ ;; Otherwise COND-EXPANDed bits.
627
+
628
+ ;; This *should* work, but doesn't :(
629
+ ;; (define-syntax match-check-ellipse
630
+ ;; (syntax-rules (...)
631
+ ;; ((_ ... sk fk) sk)
632
+ ;; ((_ x sk fk) fk)))
633
+
634
+ ;; This is a little more complicated, and introduces a new let-syntax,
635
+ ;; but should work portably in any R[56]RS Scheme. Taylor Campbell
636
+ ;; originally came up with the idea.
637
+ (define-syntax match-check-ellipse
638
+ (syntax-rules ()
639
+ ;; these two aren't necessary but provide fast-case failures
640
+ ((match-check-ellipse (a . b) success-k failure-k) failure-k)
641
+ ((match-check-ellipse #(a ...) success-k failure-k) failure-k)
642
+ ;; matching an atom
643
+ ((match-check-ellipse id success-k failure-k)
644
+ (let-syntax ((ellipse? (syntax-rules ()
645
+ ;; iff `id' is `...' here then this will
646
+ ;; match a list of any length
647
+ ((ellipse? (foo id) sk fk) sk)
648
+ ((ellipse? other sk fk) fk))))
649
+ ;; this list of three elements will only many the (foo id) list
650
+ ;; above if `id' is `...'
651
+ (ellipse? (a b c) success-k failure-k)))))
652
+
653
+
654
+ ;; This is portable but can be more efficient with non-portable
655
+ ;; extensions. This trick was originally discovered by Oleg Kiselyov.
656
+
657
+ (define-syntax match-check-identifier
658
+ (syntax-rules ()
659
+ ;; fast-case failures, lists and vectors are not identifiers
660
+ ((_ (x . y) success-k failure-k) failure-k)
661
+ ((_ #(x ...) success-k failure-k) failure-k)
662
+ ;; x is an atom
663
+ ((_ x success-k failure-k)
664
+ (let-syntax
665
+ ((sym?
666
+ (syntax-rules ()
667
+ ;; if the symbol `abracadabra' matches x, then x is a
668
+ ;; symbol
669
+ ((sym? x sk fk) sk)
670
+ ;; otherwise x is a non-symbol datum
671
+ ((sym? y sk fk) fk))))
672
+ (sym? abracadabra success-k failure-k)))))