diff options
| author | Richard M. Stallman | 1994-03-06 19:39:10 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1994-03-06 19:39:10 +0000 |
| commit | 41ea659a7f62f5eed5f5306ce1c44f3c5de6f2b5 (patch) | |
| tree | 9a12a4d93f2312f273f63759f3b6f1f55b5681c7 | |
| parent | 0dba5606aac933d8b51c06e55ca764152d2f5c75 (diff) | |
| download | emacs-41ea659a7f62f5eed5f5306ce1c44f3c5de6f2b5.tar.gz emacs-41ea659a7f62f5eed5f5306ce1c44f3c5de6f2b5.zip | |
Complete rewrite by Sladkey.
| -rw-r--r-- | lisp/emacs-lisp/backquote.el | 525 |
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 | ||
| 70 | a 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. | ||
| 100 | Note that this is very slow in interpreted code, but fast if you compile. | ||
| 101 | FORM is one or more nested lists, which are `almost quoted': | ||
| 102 | They 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 | |||
| 106 | However, certain special lists are not copied. They specify substitution. | ||
| 107 | Lists that look like (, EXP) are evaluated and the result is substituted. | ||
| 108 | (` a (, (+ x 5))) == (list 'a (+ x 5)) | ||
| 109 | |||
| 110 | Elements of the form (,@ EXP) are evaluated and then all the elements | ||
| 111 | of the result are substituted. This result must be a list; it may | ||
| 112 | be `nil'. | ||
| 113 | |||
| 114 | As an example, a simple macro `push' could be written: | ||
| 115 | (defmacro push (v l) | ||
| 116 | (` (setq (, l) (cons (,@ (list v l)))))) | ||
| 117 | or as | ||
| 118 | (defmacro push (v l) | ||
| 119 | (` (setq (, l) (cons (, v) (, l))))) | ||
| 120 | |||
| 121 | LIMITATIONS: \"dotted lists\" are not allowed in FORM. | ||
| 122 | The ultimate cdr of each list scanned by ` must be `nil'. | ||
| 123 | \(This does not apply to constants inside expressions to be substituted.) | ||
| 124 | |||
| 125 | Substitution elements are not allowed as the cdr | ||
| 126 | of a cons cell. For example, (` (A . (, B))) does not work. | ||
| 127 | Instead, write (` (A (,@ B))). | ||
| 128 | |||
| 129 | You cannot construct vectors, only lists. Vectors are treated as | ||
| 130 | constants. | ||
| 131 | |||
| 132 | BEWARE BEWARE BEWARE | ||
| 133 | Inclusion of (,ATOM) rather than (, ATOM) | ||
| 134 | or of (,@ATOM) rather than (,@ ATOM) | ||
| 135 | will 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. | ||
| 153 | See 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 | |||
| 53 | For 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 | |||
| 67 | For 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 | |||
| 98 | The whole structure acts as if it were quoted except for certain | ||
| 99 | places where expressions are evaluated and inserted or spliced in. | ||
| 100 | |||
| 101 | For example: | ||
| 102 | |||
| 103 | b => (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 | |||
| 108 | Vectors work just like lists. Nested backquotes are permitted. | ||
| 109 | |||
| 110 | Variables: backquote-backquote-symbol, backquote-unquote-symbol, | ||
| 111 | backquote-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 | ||