nendo 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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)))))