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