Initial revision
[bpt/emacs.git] / lisp / emacs-lisp / backquote.el
CommitLineData
c440e42b
RS
1;; Copyright (C) 1985 Free Software Foundation, Inc.
2;; Written by Dick King (king@kestrel).
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20
21;;; This is a rudimentry backquote package written by D. King,
22 ;;; king@kestrel, on 8/31/85. (` x) is a macro
23 ;;; that expands to a form that produces x. (` (a b ..)) is
24 ;;; a macro that expands into a form that produces a list of what a b
25 ;;; etc. would have produced. Any element can be of the form
26 ;;; (, <form>) in which case the resulting form evaluates
27 ;;; <form> before putting it into place, or (,@ <form>), in which
28 ;;; case the evaluation of <form> is arranged for and each element
29 ;;; of the result (which must be a (possibly null) list) is inserted.
30;;; As an example, the immediately following macro push (v l) could
31 ;;; have been written
32;;; (defmacro push (v l)
33;;; (` (setq (, l) (cons (,@ (list v l))))))
34 ;;; although
35;;; (defmacro push (v l)
36;;; (` (setq (, l) (cons (, v) (, l)))))
37 ;;; is far more natural. The magic atoms ,
38 ;;; and ,@ are user-settable and list-valued. We recommend that
39 ;;; things never be removed from this list lest you break something
40 ;;; someone else wrote in the dim past that comes to be recompiled in
41 ;;; the distant future.
42
43;;; LIMITATIONS: tail consing is not handled correctly. Do not say
44 ;;; (` (a . (, b))) - say (` (a (,@ b)))
45 ;;; which works even if b is not list-valued.
46;;; No attempt is made to handle vectors. (` [a (, b) c]) doesn't work.
47;;; Sorry, you must say things like
48 ;;; (` (a (,@ 'b))) to get (a . b) and
49 ;;; (` ((, ',) c)) to get (, c) - [(` (a , b)) will work but is a bad habit]
50;;; I haven't taught it the joys of nconc.
51;;; (` atom) dies. (` (, atom)) or anything else is okay.
52
53;;; BEWARE BEWARE BEWARE
54 ;;; inclusion of (,atom) rather than (, atom) or (,@atom) rather than
55 ;;; (,@ atom) will result in errors that will show up very late.
56 ;;; This is so crunchy that I am considering including a check for
57 ;;; this or changing the syntax to ... ,(<form>). RMS: opinion?
58
59
60(provide 'backquote)
61
62;;; a raft of general-purpose macros follows. See the nearest
63 ;;; Commonlisp manual.
64(defmacro bq-push (v l)
65 "Pushes evaluated first form onto second unevaluated object
66a list-value atom"
67 (list 'setq l (list 'cons v l)))
68
69(defmacro bq-caar (l)
70 (list 'car (list 'car l)))
71
72(defmacro bq-cadr (l)
73 (list 'car (list 'cdr l)))
74
75(defmacro bq-cdar (l)
76 (list 'cdr (list 'car l)))
77
78
79;;; These two advertised variables control what characters are used to
80 ;;; unquote things. I have included , and ,@ as the unquote and
81 ;;; splice operators, respectively, to give users of MIT CADR machine
82 ;;; derivitive machines a warm, cosy feeling.
83
84(defconst backquote-unquote '(,)
85 "*A list of all objects that stimulate unquoting in `. Memq test.")
86
87
88(defconst backquote-splice '(,@)
89 "*A list of all objects that stimulate splicing in `. Memq test.")
90
91
92;;; This is the interface
7229064d 93;;;###autoload
c440e42b
RS
94(defmacro ` (form)
95 "(` FORM) is a macro that expands to code to construct FORM.
96Note that this is very slow in interpreted code, but fast if you compile.
97FORM is one or more nested lists, which are `almost quoted':
98They are copied recursively, with non-lists used unchanged in the copy.
99 (` a b) == (list 'a 'b) constructs a new list with two elements, `a' and `b'.
100 (` a (b c)) == (list 'a (list 'b 'c)) constructs two nested new lists.
101
102However, certain special lists are not copied. They specify substitution.
103Lists that look like (, EXP) are evaluated and the result is substituted.
104 (` a (, (+ x 5))) == (list 'a (+ x 5))
105
106Elements of the form (,@ EXP) are evaluated and then all the elements
107of the result are substituted. This result must be a list; it may
108be `nil'.
109
110As an example, a simple macro `push' could be written:
111 (defmacro push (v l)
112 (` (setq (, l) (cons (,@ (list v l))))))
113or as
114 (defmacro push (v l)
115 (` (setq (, l) (cons (, v) (, l)))))
116
117LIMITATIONS: \"dotted lists\" are not allowed in FORM.
118The ultimate cdr of each list scanned by ` must be `nil'.
119\(This does not apply to constants inside expressions to be substituted.)
120
121Substitution elements are not allowed as the cdr
122of a cons cell. For example, (` (A . (, B))) does not work.
123Instead, write (` (A (,@ B))).
124
125You cannot construct vectors, only lists. Vectors are treated as
126constants.
127
128BEWARE BEWARE BEWARE
129Inclusion of (,ATOM) rather than (, ATOM)
130or of (,@ATOM) rather than (,@ ATOM)
131will result in errors that will show up very late."
132 (bq-make-maker form))
133
134;;; We develop the method for building the desired list from
135 ;;; the end towards the beginning. The contract is that there be a
136 ;;; variable called state and a list called tailmaker, and that the form
137 ;;; (cons state tailmaker) deliver the goods. Exception - if the
138 ;;; state is quote the tailmaker is the form itself.
139;;; This function takes a form and returns what I will call a maker in
140 ;;; what follows. Evaluating the maker would produce the form,
141 ;;; properly evaluated according to , and ,@ rules.
142;;; I work backwards - it seemed a lot easier. The reason for this is
143 ;;; if I'm in some sort of a routine building a maker and I switch
144 ;;; gears, it seemed to me easier to jump into some other state and
145 ;;; glue what I've already done to the end, than to to prepare that
146 ;;; something and go back to put things together.
147(defun bq-make-maker (form)
148 "Given one argument, a `mostly quoted' object, produces a maker.
149See backquote.el for details"
150 (let ((tailmaker (quote nil)) (qc 0) (ec 0) (state nil))
151 (mapcar 'bq-iterative-list-builder (reverse form))
152 (and state
153 (cond ((eq state 'quote)
fcb764df 154 (list state (if (equal form tailmaker) form tailmaker)))
c440e42b
RS
155 ((= (length tailmaker) 1)
156 (funcall (bq-cadr (assq state bq-singles)) tailmaker))
157 (t (cons state tailmaker))))))
158
159;;; There are exceptions - we wouldn't want to call append of one
160 ;;; argument, for example.
161(defconst bq-singles '((quote bq-quotecar)
162 (append car)
163 (list bq-make-list)
164 (cons bq-id)))
165
166(defun bq-id (x) x)
167
168(defun bq-quotecar (x) (list 'quote (car x)))
169
170(defun bq-make-list (x) (cons 'list x))
171
172;;; fr debugging use only
173;(defun funcalll (a b) (funcall a b))
174;(defun funcalll (a b) (debug nil 'enter state tailmaker a b)
175; (let ((ans (funcall a b))) (debug nil 'leave state tailmaker)
176; ans))
177
178;;; Given a state/tailmaker pair that already knows how to make a
179 ;;; partial tail of the desired form, this function knows how to add
180 ;;; yet another element to the burgening list. There are four cases;
181 ;;; the next item is an atom (which will certainly be quoted); a
182 ;;; (, xxx), which will be evaluated and put into the list at the top
183 ;;; level; a (,@ xxx), which will be evaluated and spliced in, or
184 ;;; some other list, in which case we first compute the form's maker,
185 ;;; and then we either launch into the quoted case if the maker's
186 ;;; top level function is quote, or into the comma case if it isn't.
187;;; The fourth case reduces to one of the other three, so here we have
188 ;;; a choice of three ways to build tailmaker, and cit turns out we
189 ;;; use five possible values of state (although someday I'll add
190 ;;; nconcto the possible values of state).
191;;; This maintains the invariant that (cons state tailmaker) is the
192 ;;; maker for the elements of the tail we've eaten so far.
193(defun bq-iterative-list-builder (form)
194 "Called by `bq-make-maker'. Adds a new item form to tailmaker,
195changing state if need be, so tailmaker and state constitute a recipe
196for making the list so far."
197 (cond ((atom form)
198 (funcall (bq-cadr (assq state bq-quotefns)) form))
199 ((memq (car form) backquote-unquote)
200 (funcall (bq-cadr (assq state bq-evalfns)) (bq-cadr form)))
201 ((memq (car form) backquote-splice)
202 (funcall (bq-cadr (assq state bq-splicefns)) (bq-cadr form)))
203 (t
204 (let ((newform (bq-make-maker form)))
205 (if (and (listp newform) (eq (car newform) 'quote))
206 (funcall (bq-cadr (assq state bq-quotefns)) (bq-cadr newform))
207 (funcall (bq-cadr (assq state bq-evalfns)) newform))))
208 ))
209
210;;; We do a 2-d branch on the form of splicing and the old state.
211 ;;; Here's fifteen functions' names...
212(defconst bq-splicefns '((nil bq-splicenil)
213 (append bq-spliceappend)
214 (list bq-splicelist)
215 (quote bq-splicequote)
216 (cons bq-splicecons)))
217
218(defconst bq-evalfns '((nil bq-evalnil)
219 (append bq-evalappend)
220 (list bq-evallist)
221 (quote bq-evalquote)
222 (cons bq-evalcons)))
223
224(defconst bq-quotefns '((nil bq-quotenil)
225 (append bq-quoteappend)
226 (list bq-quotelist)
227 (quote bq-quotequote)
228 (cons bq-quotecons)))
229
230;;; The name of each function is
231 ;;; (concat 'bq- <type-of-element-addition> <old-state>)
232;;; I'll comment the non-obvious ones before the definitions...
233 ;;; In what follows, uppercase letters and form will always be
234 ;;; metavariables that don't need commas in backquotes, and I will
235 ;;; assume the existence of something like matches that takes a
236 ;;; backquote-like form and a value, binds metavariables and returns
237 ;;; t if the pattern match is successful, returns nil otherwise. I
238 ;;; will write such a goodie someday.
239
240;;; (setq tailmaker
241 ;;; (if (matches ((quote X) Y) tailmaker)
242 ;;; (` ((quote (form X)) Y))
243 ;;; (` ((list form (quote X)) Y))))
244 ;;; (setq state 'append)
245(defun bq-quotecons (form)
246 (if (and (listp (car tailmaker))
247 (eq (bq-caar tailmaker) 'quote))
248 (setq tailmaker
249 (list (list 'quote (list form (bq-cadr (car tailmaker))))
250 (bq-cadr tailmaker)))
251 (setq tailmaker
252 (list (list 'list
253 (list 'quote form)
254 (car tailmaker))
255 (bq-cadr tailmaker))))
256 (setq state 'append))
257
258(defun bq-quotequote (form)
259 (bq-push form tailmaker))
260
261;;; Could be improved to convert (list 'a 'b 'c .. 'w x)
262 ;;; to (append '(a b c .. w) x)
263 ;;; when there are enough elements
264(defun bq-quotelist (form)
265 (bq-push (list 'quote form) tailmaker))
266
267;;; (setq tailmaker
268 ;;; (if (matches ((quote X) (,@ Y)))
269 ;;; (` ((quote (, (cons form X))) (,@ Y)))))
270(defun bq-quoteappend (form)
271 (cond ((and (listp tailmaker)
272 (listp (car tailmaker))
273 (eq (bq-caar tailmaker) 'quote))
274 (rplaca (bq-cdar tailmaker)
275 (cons form (car (bq-cdar tailmaker)))))
276 (t (bq-push (list 'quote (list form)) tailmaker))))
277
278(defun bq-quotenil (form)
279 (setq tailmaker (list form))
280 (setq state 'quote))
281
282;;; (if (matches (X Y) tailmaker) ; it must
283 ;;; (` ((list form X) Y)))
284(defun bq-evalcons (form)
285 (setq tailmaker
286 (list (list 'list form (car tailmaker))
287 (bq-cadr tailmaker)))
288 (setq state 'append))
289
290;;; (if (matches (X Y Z (,@ W)))
291 ;;; (progn (setq state 'append)
292 ;;; (` ((list form) (quote (X Y Z (,@ W))))))
293 ;;; (progn (setq state 'list)
294 ;;; (list form 'X 'Y .. ))) ; quote each one there is
295(defun bq-evalquote (form)
296 (cond ((< (length tailmaker) 3)
297 (setq tailmaker
298 (cons form
299 (mapcar (function (lambda (x)
300 (list 'quote x)))
301 tailmaker)))
302 (setq state 'list))
303 (t
304 (setq tailmaker
305 (list (list 'list form)
306 (list 'quote tailmaker)))
307 (setq state 'append))))
308
309(defun bq-evallist (form)
310 (bq-push form tailmaker))
311
312;;; (cond ((matches ((list (,@ X)) (,@ Y)))
313 ;;; (` ((list form (,@ X)) (,@ Y))))
314 ;;; ((matches (X))
315 ;;; (` (form (,@ X))) (setq state 'cons))
316 ;;; ((matches ((,@ X)))
317 ;;; (` (form (,@ X)))))
318(defun bq-evalappend (form)
319 (cond ((and (listp tailmaker)
320 (listp (car tailmaker))
321 (eq (bq-caar tailmaker) 'list))
322 (rplacd (car tailmaker)
323 (cons form (bq-cdar tailmaker))))
324 ((= (length tailmaker) 1)
325 (setq tailmaker (cons form tailmaker)
326 state 'cons))
327 (t (bq-push (list 'list form) tailmaker))))
328
329(defun bq-evalnil (form)
330 (setq tailmaker (list form)
331 state 'list))
332
333;;; (if (matches (X Y)) ; it must
334 ;;; (progn (setq state 'append)
335 ;;; (` (form (cons X Y))))) ; couldn't think of anything clever
336(defun bq-splicecons (form)
337 (setq tailmaker
338 (list form
339 (list 'cons (car tailmaker) (bq-cadr tailmaker)))
340 state 'append))
341
342(defun bq-splicequote (form)
343 (setq tailmaker (list form (list 'quote tailmaker))
344 state 'append))
345
346(defun bq-splicelist (form)
347 (setq tailmaker (list form (cons 'list tailmaker))
348 state 'append))
349
350(defun bq-spliceappend (form)
351 (bq-push form tailmaker))
352
353(defun bq-splicenil (form)
354 (setq state 'append
355 tailmaker (list form)))