repos
/
cl-unification
/ annotate_shade
summary
|
shortlog
|
log
|
tree
|
commit
|
commitdiff
|
headdiff
|
annotate
|
headblob
|
headfilediff
|
filehistory
normal
|
plain
|
shade
|
zebra
Minor changes (added COPYING information and other minutiae).
Annotate for file match-block.lisp
2007-11-09 mantoniotti
1
;;;; -*- Mode: Lisp -*-
13:43:20 '
2
'
3
;;;; match-block.lisp --
'
4
;;;; Various macros built on top of the unifier: MATCH, MATCHING and MATCH-CASE.
2004-11-17 mantoniotti
5
2011-04-02 mantoniotti
6
;;;; See file COPYING for copyright licensing information.
04:05:18 '
7
2004-11-17 mantoniotti
8
(in-package "UNIFY")
22:19:54 '
9
'
10
(defun clean-unify-var-name (v)
'
11
(assert (variablep v))
'
12
(intern (subseq (symbol-name v) 1)
'
13
(symbol-package v)))
'
14
2010-06-15 pix
15
(defmacro with-unification-variables ((&rest variables) environment &body body)
03:21:37 '
16
"Execute body with variables bound to their values in environment."
'
17
(flet ((variable-bindings (v)
'
18
`((,v (find-variable-value ',v ,environment))
'
19
(,(clean-unify-var-name v) ,v))))
'
20
`(let* ,(mapcan #'variable-bindings variables)
'
21
(declare (ignorable ,@(mapcar #'clean-unify-var-name variables)))
'
22
,@body)))
'
23
2010-02-04 pix
24
(defun %match-expander (template-munger clause-munger clauses
07:32:18 '
25
&key default named environment errorp error-form keyform)
'
26
"A rather hairy internal function which handles expansion for all the MATCH* macros.
2004-11-17 mantoniotti
27
2010-02-04 pix
28
template-munger should be either 'match or 'matchf, and will massage the
07:32:18 '
29
template into the proper form for that macro set.
'
30
'
31
clause-munger should be either 'cond, 'case, or 'nil. This affects the expected
'
32
syntax of items in clauses as follows:
'
33
'cond: { ((<template> <object>) &body) }+ default-clause
'
34
'case: { (<template> &body) }+ default-clause
'
35
'nil: { (<template> <object> &body) }+ default-clause
'
36
default-clause: [ (t &body) ]
'
37
'
38
clauses is a list of forms conforming to the syntax just described.
'
39
'
40
default is a single form to be executed if no other forms match.
'
41
named is the name for a surrounding block.
'
42
'
43
environment is a base environment object which template matches should extend.
'
44
The new environments created will share frames with this environment, though any
'
45
additional bindings will be in a new, unshared frame. environment defaults to
'
46
'(make-empty-environment).
'
47
'
48
errorp is a single form which will be evaluated to determine if error-form is
'
49
executed.
'
50
'
51
error-form is a form which is expected to generate an error (e.g., `(error
'
52
'unification-non-exhaustive)). It defaults to providing the error returned by
'
53
the last form which failed unification.
'
54
'
55
keyform should be used only for a clause-munger of 'case. It provides the form
'
56
to evaluate to produce the object for unification in -case macros.
'
57
'
58
*Interaction between default-clause, :errorp + :error-form, and :default
'
59
'
60
This function produces a giant COND form which ends one or more of these
'
61
assorted \"default\" clauses. They are produced in a very specific order:
'
62
1. errorp + error-form are tried first. Thus, if errorp is 't, neither the
'
63
default-clause in clauses will be reached, nor the :default clause. This is
'
64
essentially a hook to produce a pre-user default clause. (e.g., for
'
65
MATCH's :errorp)
'
66
2. The default-clause in clauses, if it exists, will be tried next. Because
'
67
clauses is expected to contain user-specified clauses, this is expected to be
'
68
the user-specified default clause.
'
69
3. Finally, the :default clause, if specified, will be tried. This is
'
70
essentially a hook to produce a post-user default clause. (e.g., for
'
71
-ECASE's error form)
'
72
"
'
73
(flet ((default-clause-p (clause) (member (first clause) '(t otherwise))))
'
74
(let ((match-environment (gensym "MATCH-ENV-"))
'
75
(base-environment (gensym "BASE-ENV-"))
'
76
(match-error (gensym "MATCH-ERR-"))
'
77
(case-keyform (gensym "KEYFORM-"))
'
78
(match-clauses (remove-if #'default-clause-p clauses))
'
79
(default-clauses (remove-if-not #'default-clause-p clauses)))
'
80
(when (or (and (< 1 (length default-clauses))
'
81
;; whether the default clause is the last one
'
82
(every #'eq clauses (append match-clauses default-clauses)))
'
83
;; :keyform only applies for 'case
'
84
(and keyform (not (eq clause-munger 'case))))
'
85
(error 'program-error))
'
86
(labels ((ensure-template (template)
'
87
(cond (;; Logical variables are special-cased.
'
88
(variablep template) `',template)
'
89
;; Same for lists (under matchf)
'
90
((and (eq 'matchf template-munger)
'
91
(listp template))
'
92
(make-instance 'list-template
'
93
:spec (cons 'list template)))
'
94
(t template)))
'
95
(expand-clause (clause)
'
96
(destructuring-bind (template object &rest body)
2010-02-07 pix
97
(munge-clause clause)
2010-02-04 pix
98
(let* ((template (ensure-template template))
07:32:18 '
99
(variables (collect-template-vars template)))
'
100
`((setf (values ,match-environment ,match-error)
'
101
(unify* ,template ,object (make-expanded-environment ,base-environment)))
2010-06-15 pix
102
(with-unification-variables ,variables ,match-environment
2010-02-04 pix
103
,@body)))))
07:32:18 '
104
(munge-clause (clause)
'
105
(ecase clause-munger
'
106
(cond (destructuring-bind (head . tail) clause
'
107
(if (consp head)
'
108
(list* (car head) (cadr head) tail)
'
109
clause)))
'
110
(case (list* (car clause) case-keyform (cdr clause)))
'
111
((nil) clause))))
'
112
`(block ,named
'
113
(let ((,match-environment nil)
'
114
(,match-error nil)
'
115
(,case-keyform ,keyform)
'
116
(,base-environment ,(if environment
'
117
`(make-shared-environment ,environment)
'
118
'(make-empty-environment))))
'
119
(declare (dynamic-extent ,match-environment ,base-environment)
'
120
(ignorable ,case-keyform))
'
121
(cond
2010-02-07 pix
122
,@(mapcar #'expand-clause match-clauses)
2010-02-04 pix
123
,@(when errorp `((,errorp ,(or error-form `(error ,match-error)))))
07:32:18 '
124
,@(when default-clauses `((t ,@(cdar default-clauses))))
'
125
,@(when default `((t ,default))))))))))
2010-01-12 pix
126
2010-02-05 pix
127
(defmacro %set-documentation ((&rest symbols) docstring)
03:21:40 '
128
`(eval-when (:load-toplevel :execute)
'
129
(mapcar (lambda (fn) (setf (documentation fn 'function) ,docstring))
'
130
',symbols)))
'
131
2004-11-17 mantoniotti
132
(defmacro match ((template object
22:19:54 '
133
&key
2010-02-04 pix
134
(named nil)
07:32:18 '
135
(match-named nil match-named-p)
'
136
(substitution nil)
2004-11-17 mantoniotti
137
(errorp t)
22:19:54 '
138
(error-value nil))
'
139
&body forms)
2010-02-04 pix
140
(when match-named-p
07:32:18 '
141
(warn ":match-named is deprecated. Use :named instead."))
'
142
(%match-expander 'match
'
143
'nil
'
144
`((,template ,object ,@forms))
'
145
:default error-value
'
146
:named (or named match-named)
'
147
:environment substitution
'
148
:errorp errorp))
2009-04-15 mantoniotti
149
10:16:24 '
150
(defmacro matchf ((template object
'
151
&key
2010-02-04 pix
152
(named nil)
07:32:18 '
153
(match-named nil match-named-p)
'
154
(substitution nil)
2009-04-15 mantoniotti
155
(errorp t)
10:16:24 '
156
(error-value nil))
'
157
&body forms)
2010-02-05 pix
158
(when match-named-p
03:21:40 '
159
(warn ":match-named is deprecated. Use :named instead."))
'
160
(%match-expander 'matchf
'
161
'nil
'
162
`((,template ,object ,@forms))
'
163
:default error-value
'
164
:named (or named match-named)
'
165
:environment substitution
'
166
:errorp errorp))
'
167
'
168
(%set-documentation
'
169
(match matchf)
'
170
"Sets up a lexical environment to evaluate FORMS after an unification.
2009-04-15 mantoniotti
171
2010-02-05 pix
172
MATCH and MATCHF unify a TEMPLATE and an OBJECT and then set up a lexical
2009-04-15 mantoniotti
173
environment where the variables present in the template are bound
10:16:24 '
174
lexically. Note that both variable names '?FOO' and 'FOO' are bound
'
175
for convenience.
'
176
'
177
MATCHF does not 'evaluate' TEMPLATE (note that using the #T syntax will
'
178
generate a template at read-time).
'
179
2010-02-05 pix
180
MATCH and MATCHF forms return the values returned by the evaluation of the
2009-04-15 mantoniotti
181
last of the FORMS.
10:16:24 '
182
'
183
If ERRORP is non-NIL (the default) then the form raises a
'
184
UNIFICATION-FAILURE, otherwise the result of evaluating ERROR-VALUE,
'
185
whose default is NIL is returned. (Note that UNIFICATION-FAILUREs
2010-02-05 pix
186
raising from the evaluation of FORMS will /not/ be caught and handled
2009-04-15 mantoniotti
187
according to ERRORP settings.)
10:16:24 '
188
2010-02-05 pix
189
A surrounding BLOCK named NAMED is set up around the matching code.")
2004-11-17 mantoniotti
190
22:19:54 '
191
'
192
'
193
(define-condition unification-non-exhaustive (unification-failure)
2010-02-04 pix
194
()
07:32:18 '
195
(:default-initargs
'
196
:format-control "Non exhaustive matching."))
'
197
2004-11-17 mantoniotti
198
2010-02-04 pix
199
(defmacro match-cond (&body clauses)
07:32:18 '
200
(%match-expander 'match 'cond clauses))
'
201
'
202
(defmacro matchf-cond (&body clauses)
'
203
(%match-expander 'matchf 'cond clauses))
2004-11-17 mantoniotti
204
22:19:54 '
205
(defmacro matching ((&key errorp
2010-02-04 pix
206
default-substitution
07:32:18 '
207
(named nil)
'
208
(matching-named nil matching-named-p))
2010-01-15 pix
209
&body match-clauses)
2010-02-04 pix
210
(when matching-named-p
07:32:18 '
211
(warn ":matching-named is deprecated. Use :named instead."))
'
212
(%match-expander 'match 'cond match-clauses
'
213
:errorp errorp
'
214
:error-form `(error 'unification-non-exhaustive)
'
215
:named (or named matching-named)
'
216
:environment default-substitution))
2004-11-17 mantoniotti
217
2010-02-05 pix
218
(%set-documentation
03:21:40 '
219
(match-cond matchf-cond matching)
'
220
"MATCH-COND, MATCHF-COND, and MATCHING set up a COND-like environment for
'
221
multiple template matching clauses.
2005-04-27 mantoniotti
222
2010-02-05 pix
223
Their syntax comprises a number of clauses of the form
2005-04-27 mantoniotti
224
<clause> ::= <regular-clause> | <default-clause>
2010-02-05 pix
225
<regular-clause> ::= ((<template> <form>) &body <forms>)
2005-04-27 mantoniotti
226
<default-clause> ::= (t &body <forms>)
20:41:56 '
227
| (otherwise &body <forms>)
'
228
<form> and <forms> are regular Common Lisp forms.
'
229
<template> is a unification template.
'
230
2010-02-05 pix
231
The full syntax is
03:21:40 '
232
match-cond <clauses>
'
233
matchf-cond <clauses>
'
234
matching (&key errorp default-substitution named) <clauses>
2005-04-27 mantoniotti
235
20:41:56 '
236
Each clause evaluates its forms in an environment where the variables
'
237
present in the template are bound lexically. Note that both variable
'
238
names '?FOO' and 'FOO' are bound for convenience.
'
239
2010-02-05 pix
240
The values returned by the macros are those of the last form in
2005-04-27 mantoniotti
241
the first clause that satisfies the match test.
20:41:56 '
242
'
243
If ERRORP is non-NIL then if none of the regular clauses matches, then
'
244
an error of type UNIFICATION-NON-EXAUSTIVE is signalled, regardless of
'
245
any default clause. Otherwise, the default clause behaves as a
2010-02-05 pix
246
standard COND default clause. The default value of ERRORP is NIL.
03:21:40 '
247
")
'
248
'
249
'
250
(defmacro match-case ((object &key errorp default-substitution named (match-case-named nil match-case-named-p))
'
251
&body clauses)
2010-02-04 pix
252
(when match-case-named-p
07:32:18 '
253
(warn ":match-case-named is deprecated. Use :named instead."))
'
254
(%match-expander 'match 'case clauses
'
255
:named (or named match-case-named)
'
256
:environment default-substitution
'
257
:errorp errorp
'
258
:error-form `(error 'unification-non-exhaustive)
'
259
:keyform object))
2005-04-27 mantoniotti
260
2010-02-04 pix
261
(defmacro match-ecase ((object &key default-substitution named)
07:32:18 '
262
&body clauses)
'
263
(%match-expander 'match 'case clauses
'
264
:named named
'
265
:environment default-substitution
'
266
:default `(error 'unification-non-exhaustive)
'
267
:keyform object))
2009-12-17 mantoniotti
268
2010-02-04 pix
269
(defmacro matchf-case ((object &key errorp default-substitution named (match-case-named nil match-case-named-p))
07:32:18 '
270
&body clauses)
'
271
(when match-case-named-p
'
272
(warn ":match-case-named is deprecated. Use :named instead."))
'
273
(%match-expander 'matchf 'case clauses
'
274
:named (or named match-case-named)
'
275
:environment default-substitution
'
276
:errorp errorp
'
277
:error-form `(error 'unification-non-exhaustive)
'
278
:keyform object))
'
279
'
280
(defmacro matchf-ecase ((object &key default-substitution named)
'
281
&body clauses)
'
282
(%match-expander 'matchf 'case clauses
'
283
:named named
'
284
:environment default-substitution
'
285
:default `(error 'unification-non-exhaustive)
'
286
:keyform object))
'
287
2010-02-05 pix
288
(%set-documentation
03:21:40 '
289
(match-case match-ecase matchf-case matchf-ecase)
'
290
"MATCH-CASE, MATCH-ECASE, MATCHF-CASE, and MATCHF-ECASE set up a CASE-like
'
291
environment for multiple template matching clauses.
'
292
'
293
Their syntax comprises a number of clauses of the form
'
294
<clause> ::= <regular-clause> | <default-clause>
'
295
<regular-clause> ::= (<template> &body <forms>)
'
296
<default-clause> ::= (t &body <forms>)
'
297
| (otherwise &body <forms>)
'
298
<form> and <forms> are regular Common Lisp forms.
'
299
<template> is a unification template.
'
300
'
301
The full syntax is
'
302
match-case (<object> &key default-substitution named errorp) <clauses>
'
303
match-ecase (<object> &key default-substitution named) <clauses>
'
304
matchf-case (<object> &key default-substitution named errorp) <clauses>
'
305
matchf-ecase (<object> &key default-substitution named) <clauses>
'
306
'
307
Each clause evaluates its forms in an environment where the variables
'
308
present in the template are bound lexically. Note that both variable
'
309
names '?FOO' and 'FOO' are bound for convenience.
'
310
'
311
The values returned by the macros are those of the last form in
'
312
the first clause that satisfies the match test.
'
313
'
314
MATCHF-ECASE and MATCHF-CASE behave like MATCH-ECASE and MATCH-CASE, but the
'
315
patterns are not evaluated (i.e., they rely on MATCHF instead of MATCH to
'
316
construct the macro expansion).
'
317
")
'
318
2009-12-17 mantoniotti
319
2007-11-09 mantoniotti
320
;;;;---------------------------------------------------------------------------
13:43:20 '
321
;;;; Testing.
'
322
'
323
#| Tests
'
324
'
325
(let ((n 42))
'
326
(matching ()
'
327
((0 n) 1)
'
328
((?x n) (* x (1- x)))))
'
329
'
330
'
331
(let ((n 42))
'
332
(match-case (n)
'
333
(0 1)
'
334
(?x (* x (1- x)))))
'
335
'
336
'
337
(let ((n 42))
'
338
(match-case (n)
'
339
(0 1)
'
340
(otherwise (* n (1- n)))))
'
341
'
342
(defun fatt (x)
'
343
(match-case (x :errorp t)
'
344
(0 1)
'
345
(#T(number ?n) (* ?n (fatt (1- n))))
'
346
))
'
347
'
348
|#
2005-04-27 mantoniotti
349
2007-11-09 mantoniotti
350
;;;; end of file -- math-blocks.lisp --