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