Annotation of 43BSDReno/contrib/emacs-18.55/lisp/backquote.el, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.