Annotation of 43BSD/ucb/lisp/lisplib/macros.l, revision 1.1.1.1

1.1       root        1: (setq rcs-macros-
                      2:    "$Header: macros.l,v 1.6 83/11/09 07:09:42 jkf Exp $")
                      3: 
                      4: ;; macros.l                            -[Wed Nov  9 07:09:26 1983 by jkf]-
                      5: ;;
                      6: ;;  The file contains the common macros for Franz lisp.
                      7: ;; contents:
                      8: ;;     defmacro
                      9: ;;     setf
                     10: ;;     defsetf
                     11: ;;     push
                     12: ;;     pop
                     13: ;;     let
                     14: ;;     let*
                     15: ;;     caseq
                     16: ;;     listify
                     17: ;;     include-if
                     18: ;;     includef-if
                     19: ;;     defvar
                     20: 
                     21: 
                     22: (declare (macros t))
                     23: 
                     24: ;; defmacro
                     25: (declare (special defmacrooptlist protect-list protect-evform))
                     26: 
                     27: ;--- defmacro - name - name of macro being defined
                     28: ;            - pattrn - formal arguments plus other fun stuff
                     29: ;            - body   - body of the macro
                     30: ; This is an intellegent macro creator.  The pattern may contain
                     31: ; symbols which are formal paramters, lists which show how the
                     32: ; actual paramters will appear in the args, and these key words
                     33: ;  &rest name  - the rest of the args (or nil if there are no other args)
                     34: ;               is bound to name
                     35: ;  &optional name - bind the next arg to name if it exists, otherwise
                     36: ;                  bind it to nil
                     37: ;  &optional (name init) - bind the next arg to name if it exists, otherwise
                     38: ;                  bind it to init evaluted. (the evaluation is done left
                     39: ;                  to right for optional forms)
                     40: ;  &optional (name init given) - bind the next arg to name and given to t
                     41: ;                  if the arg exists, else bind name to the value of
                     42: ;                  init and given to nil.
                     43: ;  &aux name
                     44: ;  &aux (name init)
                     45: ;
                     46: ; Method of operation:
                     47: ;  the list returned from defmcrosrc has the form ((cxxr name) ...)
                     48: ;      where cxxr is the loc of the macro arg and name is it formal name
                     49: ;  defmcrooptlist has the form ((initv cxxr name) ...)
                     50: ; which is use for &optional args with an initial value.
                     51: ;  here cxxr looks like cdd..dr which will test of the arg exists.
                     52: ;
                     53: ; the variable defmacro-for-compiling determines if the defmacro forms
                     54: ; will be compiled. If it is t, then we return (progn 'compile (def xx..))
                     55: ; to insure that it is compiled
                     56: ;
                     57: (declare (special defmacro-for-compiling))
                     58: (cond ((null (boundp 'defmacro-for-compiling))   ; insure it has a value
                     59:        (setq defmacro-for-compiling nil)))
                     60: 
                     61: (def defmacro
                     62:   (macro (args)
                     63:     ((lambda 
                     64:        (tmp tmp2 defmacrooptlist body protect-evform protect-list gutz)
                     65:        (setq tmp (defmcrosrch (caddr args) '(d r) nil)
                     66:             body
                     67:             `(def ,(cadr args)
                     68:                   (macro (defmacroarg)
                     69:                     ((lambda ,(mapcar 'cdr tmp)
                     70:                              ,@(mapcar 
                     71:                                   '(lambda (arg)
                     72:                                      `(cond ((setq ,(caddr arg)
                     73:                                                    (,(cadr arg) 
                     74:                                                      defmacroarg))
                     75:                                              ,@(cond ((setq tmp2 (cadddr arg))
                     76:                                                       `((setq ,tmp2 t))))
                     77:                                              (setq ,(caddr arg)
                     78:                                                    (car ,(caddr arg))))
                     79:                                             (t (setq ,(caddr arg)
                     80:                                                      ,(car arg)))))
                     81:                                        defmacrooptlist)
                     82:                              ,@(cond (protect-evform 
                     83:                                       (setq gutz 
                     84:                                             (eval `((lambda ,(mapcar 'cdr tmp)
                     85:                                                             ,@(cdddr args))
                     86:                                                     ,@(mapcar
                     87:                                                        '(lambda (x) `',(cdr x))
                     88:                                                        tmp))))
                     89:                                       (ncons 
                     90:                                        `(cond (,protect-evform
                     91:                                                      (copy
                     92:                                                         `((lambda ,',(mapcar 'cdr tmp)
                     93:                                                              ,',gutz)
                     94:                                                           ,,@(mapcar 'cdr tmp))))
                     95:                                               (t ,@(cdddr args)))))
                     96:                                      (t (cdddr args))))
                     97:                      ,@(mapcar '(lambda (arg) 
                     98:                                         (cond ((dtpr (car arg))
                     99:                                                (caar arg))
                    100:                                               ((car arg)
                    101:                                                `(,(car arg) defmacroarg))))
                    102:                               tmp)))))
                    103:       (cond (defmacro-for-compiling `(progn 'compile ,body))
                    104:            (t body)))
                    105: 
                    106:      nil nil nil nil nil nil nil)))
                    107: 
                    108: (def defmcrosrch
                    109:   (lambda (pat form sofar)
                    110:          (cond ((null pat) sofar)
                    111:                ((atom pat) (cons (cons (concatl `(c ,@form)) pat)
                    112:                                  sofar))
                    113:                ((memq (car pat) '(&rest &body))
                    114:                 (append (defmcrosrch (cadr pat) form nil)
                    115:                         (defmcrosrch (cddr pat) form sofar)))
                    116:                ((eq (car pat) '&optional)
                    117:                 (defmcrooption (cdr pat) form sofar))
                    118:                ((eq (car pat) '&protect)
                    119:                 (setq protect-list (cond ((atom (cadr pat))
                    120:                                           (ncons (cadr pat)))
                    121:                                          (t (cadr pat)))
                    122:                       protect-evform (cons 'or (mapcar '(lambda (x)
                    123:                                                                 `(dtpr ,x))
                    124:                                                        protect-list)))
                    125:                 (defmcrosrch (cddr pat) form sofar))
                    126:                ((eq (car pat) '&aux)
                    127:                 (mapcar '(lambda (frm)
                    128:                                  (cond ((atom frm) `((nil) . ,frm))
                    129:                                        (t `((,(cadr frm)) . ,(car frm)))))
                    130:                         (cdr pat)))
                    131:                (t (append (defmcrosrch (car pat) (cons 'a form) nil)
                    132:                           (defmcrosrch (cdr pat) (cons 'd form) sofar))))))
                    133: 
                    134: (def defmcrooption
                    135:   (lambda (pat form sofar)
                    136:     ((lambda (tmp tmp2)
                    137:          (cond ((null pat) sofar)
                    138:                ((memq (car pat) '(&rest &body))
                    139:                 (defmcrosrch (cadr pat) form sofar))
                    140:                (t (cond ((atom (car pat))
                    141:                          (setq tmp (car pat)))
                    142:                         (t (setq tmp (caar pat))
                    143:                            (setq defmacrooptlist 
                    144:                                  `((,(cadar pat) 
                    145:                                        ,(concatl `(c ,@form))
                    146:                                        ,tmp
                    147:                                        ,(setq tmp2 (caddar pat)))
                    148:                                    . ,defmacrooptlist))))
                    149:                   (defmcrooption 
                    150:                        (cdr pat) 
                    151:                        (cons 'd form) 
                    152:                        `( (,(concatl `(ca ,@form)) . ,tmp)
                    153:                           ,@(cond (tmp2 `((nil . ,tmp2))))
                    154:                          . ,sofar)))))
                    155:      nil nil)))
                    156: 
                    157: 
                    158: ;--- lambdacvt :: new lambda converter.
                    159: ;
                    160: ; - input is  a lambda body beginning with the argument list.
                    161: ;
                    162: ; vrbls   :: list of (name n) where n is the arg number for name
                    163: ; optlist :: list of (name n defval pred) where optional variable name is
                    164: ;           (arg n) [if it exists], initval is the value if it doesn't
                    165: ;           exist,  pred is set to non nil if the arg exists
                    166: ; auxlist :: list of (name initial-value) for auxillary variables. (&aux)
                    167: ; restform :: (name n) where args n to #args should be consed and assigned
                    168: ;              to name.
                    169: ;
                    170: ;; strategy:
                    171: ;  Until the compiler can compiler lexprs better, we try to avoid creating
                    172: ; a lexpr.  A lexpr is only required if &optional or &rest forms
                    173: ; appear.
                    174: ;   Formal parameters which come after &aux are bound and evaluated in a let*
                    175: ; surrounding the body.  The parameter after a &rest is put in the let*
                    176: ; too, with an init form which is a complex do loop.  The parameters
                    177: ; after &optional are put in the lambda expression just below the lexpr.
                    178: ;
                    179: (defun lambdacvt (exp)
                    180:    (prog (vrbls optlist auxlist restform vbl fl-type optcode mainvar
                    181:          minargs maxargs)
                    182:       (do ((reallist (car exp) (cdr reallist))
                    183:           (count 1 (1+ count)))
                    184:          ((null reallist))
                    185:          (setq vbl (car reallist))
                    186:          (cond ((memq vbl '(&rest &body))
                    187:                 (setq fl-type '&rest count (1- count)))
                    188:                ((eq '&aux vbl)
                    189:                 (setq fl-type '&aux count (1- count)))
                    190:                ((eq '&optional vbl)
                    191:                 (setq fl-type '&optional count (1- count)))
                    192:                ((null fl-type)          ; just a variable
                    193:                 (setq vrbls (cons (list vbl count) vrbls)))
                    194:                ((eq fl-type '&rest)
                    195:                 (cond (restform (error "Too many &rest parameters " vbl)))
                    196:                 (setq restform (list vbl count)))
                    197:                ((eq fl-type '&aux)
                    198:                 (cond ((atom vbl)
                    199:                        (setq auxlist (cons (list vbl nil) auxlist)))
                    200:                       (t (setq auxlist (cons (list (car vbl) (cadr vbl))
                    201:                                              auxlist)))))
                    202:                ((eq fl-type '&optional)
                    203:                 (cond ((atom vbl)
                    204:                        (setq optlist
                    205:                              (cons (list vbl count) optlist)))
                    206:                       (t (setq optlist
                    207:                                (cons (cons (car vbl)
                    208:                                            (cons count
                    209:                                                  (cdr vbl)))
                    210:                                      optlist)))))))
                    211: 
                    212:       ;; arguments are collected in reverse order, but set them straight
                    213:       (setq vrbls (nreverse vrbls)
                    214:            optlist (nreverse optlist)
                    215:            auxlist (nreverse auxlist)
                    216:            minargs (length vrbls)
                    217:            maxargs (cond (restform nil)
                    218:                          (t (+ (length optlist) minargs))))
                    219: 
                    220:       ;; we must covert to a lexpr if there are &optional or &rest forms
                    221:       (cond ((or optlist restform) (setq mainvar (gensym))))
                    222:       
                    223:       ; generate optionals code
                    224:       (cond (optlist
                    225:               (setq optcode
                    226:                     (mapcar '(lambda (x)
                    227:                                 `(cond ((> ,(cadr x) ,mainvar)
                    228:                                         (setq ,(car x) ,(caddr x)))
                    229:                                        (t (setq ,(car x)
                    230:                                                  (arg ,(cadr x)))
                    231:                                           ,(cond ((cdddr x)
                    232:                                                   `(setq ,(cadddr x) t))))))
                    233:                             optlist))))
                    234: 
                    235:       ;; do the rest forms
                    236:       (cond (restform
                    237:               (let ((dumind (gensym))
                    238:                     (dumcol (gensym)))
                    239:                  (setq restform
                    240:                        `((,(car restform)
                    241:                            (do ((,dumind ,mainvar (1- ,dumind))
                    242:                                 (,dumcol nil (cons (arg ,dumind) ,dumcol)))
                    243:                                ((< ,dumind ,(cadr restform)) ,dumcol))))))))
                    244:       
                    245:       ;; calculate body
                    246:       (let (body)
                    247:         (setq body (cond ((or auxlist restform)
                    248:                             `((let* ,(append restform auxlist)
                    249:                                  ,@(cdr exp))))
                    250:                          (t (cdr exp))))
                    251:         (cond ((null mainvar)          ; no &optional or &rest
                    252:                (return `(lambda ,(mapcar 'car vrbls)
                    253:                            (declare (*args ,minargs ,maxargs))
                    254:                            ,@body)))
                    255:               (t (return
                    256:                     `(lexpr (,mainvar)
                    257:                         (declare (*args ,minargs ,maxargs))
                    258:                         ((lambda
                    259:                             ,(nconc
                    260:                                 (mapcar 'car vrbls)
                    261:                                 (mapcan '(lambda (x)   ; may be two vrbls
                    262:                                             (cons (car x)
                    263:                                                   (cond ((cdddr x) ;pred?
                    264:                                                          (ncons
                    265:                                                             (cadddr x))))))
                    266:                                         optlist))
                    267:                             ,@optcode ,@body)
                    268:                          ,@(nconc (mapcar '(lambda (x) `(arg ,(cadr x)))
                    269:                                           vrbls)
                    270:                                   (mapcan '(lambda (x)
                    271:                                               (cond ((cdddr x)
                    272:                                                      (list nil nil))
                    273:                                                     (t (list nil))))
                    274:                                           optlist))))))))))
                    275: 
                    276: ;--- defcmacro :: like defmacro but result ends up under cmacro ind
                    277: ;
                    278: (def defcmacro
                    279:    (macro (args)
                    280:        (let ((name (concat (cadr args) "::cmacro:" (gensym))))
                    281:           `(eval-when (compile load eval)
                    282:                    (defmacro ,name ,@(cddr args))
                    283:                    (putprop ',(cadr args) (getd ',name) 'cmacro)
                    284:                    (remob ',name)))))
                    285: 
                    286: ;;; --- setf macro
                    287: ;
                    288: ;(setf (cadr x) 3) --> (rplaca (cdr x) 3)
                    289: 
                    290: (defmacro setf (expr val &rest rest)
                    291:          (cond ((atom expr)
                    292:                 (or (symbolp expr)
                    293:                     (error '|-- setf can't handle this.| expr))
                    294:                 `(setq ,expr ,val))
                    295:                (t
                    296:                 (do ((y)
                    297:                      (tmp))
                    298:                     (nil)
                    299:                     (and (dtpr (car expr))
                    300:                          (setq tmp
                    301:                                (setf-record-package-access-check expr val))
                    302:                          (return tmp))
                    303:                     (or (symbolp (car expr))
                    304:                         (error '|-- setf can't handle this.| expr))
                    305:                     (and (setq y (get (car expr) 'setf-expand))
                    306:                          (return (apply y `(,expr ,val ,@rest))))
                    307:                     (or (setf-check-cad+r (car expr))
                    308:                         (and
                    309:                            (or (setq y (get (car expr) 'cmacro))
                    310:                                (setq y (getd (car expr))))
                    311:                            (or (and (dtpr y)
                    312:                                     (eq (car y) 'macro))
                    313:                                (and (bcdp y)
                    314:                                     (eq (getdisc y) 'macro)))
                    315:                            (setq expr (apply y expr)))
                    316:                         (error '|-- setf can't handle this.| expr))))))
                    317: 
                    318: (defun setf-check-cad+r (name)
                    319:    ;; invert all c{ad}+r combinations
                    320:    (if (eq (getcharn name 1) #/c)
                    321:       then (let ((letters (nreverse (cdr (exploden name)))))
                    322:              (if (eq (car letters) #/r)
                    323:                 then (do ((xx (cdr letters) (cdr xx)))
                    324:                          ((null xx)
                    325:                           ;; form is c{ad}+r, setf form is
                    326:                           ;; (rplac<first a or d> (c<rest of a's + d's>r x))
                    327:                           (setq letters (nreverse letters))
                    328:                           (eval
                    329:                              `(defsetf ,name (e v)
                    330:                                  (list
                    331:                                     ',(concat "rplac" (ascii (car letters)))
                    332:                                      (list
                    333:                                         ',(implode `(#/c ,@(cdr letters)))
                    334:                                         (cadr e))
                    335:                                      v)))
                    336:                           t)
                    337:                          (if (not (memq (car xx) '(#/a #/d)))
                    338:                              then (return nil)))))))
                    339: 
                    340: (defun setf-record-package-access-check (form val)
                    341:    ;; When the record package is given the 'access-check' flag,
                    342:    ;; the access macros it generates have this form:
                    343:    ;; ((lambda (defrecord-acma)
                    344:    ;;    (cond (...)
                    345:    ;;          (t (access-form))))
                    346:    ;;   res)
                    347:    ;; To invert this, we make a copy of the form and replace the
                    348:    ;; access-form with (setf (access-form) val)
                    349:    ;;
                    350:    ;; we return nil if the form passed isn't a recognized form
                    351:    ;;
                    352:    (cond ((and (dtpr form)
                    353:               (dtpr (car form))
                    354:               (eq 'lambda (car (car form)))
                    355:               (dtpr (cadr (car form)))
                    356:               (eq (car (cadr (car form)))
                    357:                   'defrecord-acma))
                    358:          ((lambda (newform acc)
                    359:              ; newform is a copy of the given form, so we can
                    360:              ; clobber it
                    361:              ; locate the second clause of the cond
                    362:              (setq acc (cadr   ;; right the 't'
                    363:                          (caddr  ;; second cond clause
                    364:                            (caddr  ;; cond is third thing in lambda
                    365:                               (car newform)))))
                    366:              (rplaca (cdaddaddar newform) (list 'setf acc val))
                    367:              newform)
                    368:           (copy form) nil))
                    369:         (t nil)))
                    370:                      
                    371: (defmacro defsetf (name vars &rest body)
                    372:          `(eval-when 
                    373:            (compile load eval)
                    374:            (defun (,name setf-expand) ,vars . ,body)))
                    375: 
                    376: ;--- other setf's for car's and cdr's are generated automatically
                    377: ;
                    378: (defsetf car (e v) `(rplaca ,(cadr e) ,v))
                    379: (defsetf caar (e v) `(rplaca (car ,(cadr e)) ,v))
                    380: (defsetf cadr (e v) `(rplaca (cdr ,(cadr e)) ,v))
                    381: (defsetf cdr (e v) `(rplacd ,(cadr e) ,v))
                    382: (defsetf cdar (e v) `(rplacd (car ,(cadr e)) ,v))
                    383: (defsetf cddr (e v) `(rplacd (cdr ,(cadr e)) ,v))
                    384: (defsetf cxr (e v) `(rplacx ,(cadr e) ,(caddr e) ,v))
                    385: 
                    386: (defsetf vref (e v) `(vset ,(cadr e) ,(caddr e) ,v))
                    387: (defsetf vrefi-byte (e v) `(vseti-byte ,(cadr e) ,(caddr e) ,v))
                    388: (defsetf vrefi-word (e v) `(vseti-word ,(cadr e) ,(caddr e) ,v))
                    389: (defsetf vrefi-long (e v) `(vseti-long ,(cadr e) ,(caddr e) ,v))
                    390: 
                    391: (defsetf nth (e v) `(rplaca (nthcdr ,(cadr e) ,(caddr e)) ,v))
                    392: (defsetf nthelem (e v) `(rplaca (nthcdr (1- ,(cadr e)) ,(caddr e)) ,v))
                    393: (defsetf nthcdr (e v) `(rplacd (nthcdr (1- ,(cadr e)) ,(caddr e)) ,v))
                    394: 
                    395: (defsetf arraycall (e v) `(store ,e ,v))
                    396: (defsetf get (e v) `(putprop ,(cadr e) ,v ,(caddr e)))
                    397: 
                    398: (defsetf plist (e v) `(setplist ,(cadr e) ,v))
                    399: 
                    400: (defsetf symeval (e v) `(set ,(cadr e) ,v))
                    401: 
                    402: (defsetf arg (e v) `(setarg ,(cadr e) ,v))
                    403: 
                    404: (defsetf args (e v) `(args ,(cadr e) ,v))
                    405: 
                    406: 
                    407: (defmacro push (object list) `(setf ,list (cons ,object ,list)))
                    408: 
                    409: ; this relies on the fact that setf returns the value stored.
                    410: (defmacro pop (list &optional (into nil into-p))
                    411:   (cond (into-p `(prog1 (setf ,into (car ,list))
                    412:                         (setf ,list (cdr ,list))))
                    413:         (t `(prog1 (car ,list)
                    414:                    (setf ,list (cdr ,list))))))
                    415: 
                    416: ; let for franz (with destructuring)
                    417: ;--- let
                    418: ;      - binds - binding forms
                    419: ;      - . body - forms to execute
                    420: ; the binding forms may have these forms
                    421: ;   a  local variable a, initially nil
                    422: ;  (a x)  local variable a, x is evaled and a gets its value initially
                    423: ;  ((a . (b . c)) x)   three local variables, a,b and c which are given
                    424: ;                      values corresponding to the location in the value
                    425: ;                      of x.  Any structure is allowed here. 
                    426: ;
                    427: (defmacro let (binds &rest body &aux vrbls vals destrs newgen)
                    428:   (mapc '(lambda (form)
                    429:                (cond ((atom form)
                    430:                       (setq vrbls (cons form vrbls)
                    431:                             vals  (cons nil vals)))
                    432:                      ((atom (car form))
                    433:                       (setq vrbls (cons (car form) vrbls)
                    434:                             vals  (cons (cadr form) vals)))
                    435:                      (t (setq newgen (gensym)
                    436:                               destrs `((,newgen ,@(de-compose (car form) '(r)))
                    437:                                        ,@destrs)
                    438:                               vrbls  (cons newgen vrbls)
                    439:                               vals   (cons (cadr form) vals)))))
                    440:        binds)
                    441: 
                    442:   (mapc '(lambda (frm)
                    443:                (do ((ll (cdr frm) (cdr ll)))
                    444:                    ((null ll))
                    445:                    (setq vrbls (cons (cdar ll) vrbls)
                    446:                          vals  (cons nil vals))))
                    447:        destrs)
                    448: 
                    449:   (setq vals (nreverse vals)
                    450:        vrbls (nreverse vrbls)
                    451:        destrs (nreverse destrs))
                    452:   `((lambda ,vrbls
                    453:            ,@(mapcan '(lambda (frm)
                    454:                               (mapcar '(lambda (vrb)
                    455:                                                `(setq ,(cdr vrb) (,(car vrb)
                    456:                                                                  ,(car frm))))
                    457:                                       (cdr frm)))
                    458:                      destrs)
                    459:            ,@body)
                    460:     ,@vals))
                    461: 
                    462: ;--- de-compose
                    463: ;              form - pattern to de-compose
                    464: ;              sofar - the sequence of cxxr's needed to get to this part
                    465: ;                      of the pattern
                    466: ;  de-compose returns a list of this form
                    467: ;
                    468: ;      ((cxxr . a) (cyyr . b) ... )
                    469: ; which tells how to get to the value for a and b ..etc..
                    470: ;
                    471: (def de-compose 
                    472:   (lambda (form sofar)
                    473:          (cond ((null form ) nil)
                    474:                ((atom form) (ncons (cons (apply 'concat (cons 'c sofar))
                    475:                                          form)))
                    476:                (t (nconc (de-compose (car form) (cons 'a sofar))
                    477:                          (de-compose (cdr form) (cons 'd sofar)))))))
                    478: 
                    479: ;--- caseq
                    480: ; use is 
                    481: ;    (caseq expr
                    482: ;          (match1 do1)
                    483: ;          (match2 do2)
                    484: ;          (t  doifallelsefails))
                    485: ; the matchi can be atoms in which case an 'eq' test is done, or they
                    486: ; can be lists in which case a 'memq' test is done.
                    487: ;
                    488: 
                    489: (defmacro caseq (switch &body clauses &aux var code)
                    490:    (setq var (cond ((symbolp switch) switch) ((gensym 'Z))))
                    491:    (setq code
                    492:         `(cond . ,(mapcar '(lambda (clause)
                    493:                               (cons
                    494:                                  (let ((test (car clause)))
                    495:                                     (cond ((eq test t) t)
                    496:                                           ((dtpr test)
                    497:                                            `(memq ,var ',test))
                    498:                                           (t `(eq ,var ',test))))
                    499:                                  (cdr clause)))
                    500:                           clauses)))
                    501:    (cond ((symbolp switch) code)
                    502:         (`((lambda (,var) ,code) ,switch))))
                    503: 
                    504: ;--- selectq :: just like caseq
                    505: ; except 'otherwise' is recogized as equivalent to 't' as a key
                    506: ;
                    507: (defmacro selectq (key . forms)
                    508:          (setq forms
                    509:                (mapcar '(lambda (form) (if (eq (car form) 'otherwise)
                    510:                                             (cons t (cdr form)) form))
                    511:                        forms))
                    512:          `(caseq ,key . ,forms))
                    513: 
                    514: ;--- let*
                    515: ;      - binds  - binding forms (like let)
                    516: ;      - body   - forms to eval (like let)
                    517: ; this is the same as let, except forms are done in a left to right manner
                    518: ; in fact, all we do is generate nested lets
                    519: ;
                    520: (defmacro let* (binds &rest body)
                    521:   (do ((ll (reverse binds) (cdr ll)))
                    522:       ((null ll) (car body))
                    523:       (setq body `((let (,(car ll)) ,@body)))))
                    524: 
                    525: 
                    526:                   
                    527: ;--- listify : n  - integer
                    528: ;      returns a list of the first n args to the enclosing lexpr if
                    529: ; n is positive, else returns the last -n args to the lexpr if n is
                    530: ; negative.
                    531: ; returns nil if n is 0
                    532: ;
                    533: (def listify 
                    534:   (macro (lis)
                    535:         `(let ((n ,(cadr lis)))
                    536:               (cond ((eq n 0) nil)
                    537:                     ((minusp n)
                    538:                      (do ((i (arg nil)  (1- i))
                    539:                           (result nil (cons (arg i) result)))
                    540:                          ((<& i (+ (arg nil) n  1)) result) ))
                    541:                     (t (do ((i n  (1- i))
                    542:                             (result nil (cons (arg i) result)))
                    543:                            ((<& i 1) result) ))))))
                    544: 
                    545: ;--- include-if
                    546: ; form: (include-if <predicate> <filename>)
                    547: ;  will return (include <filename>) if <predicate> is non-nil
                    548: ;  This is useful at the beginning of a file to conditionally
                    549: ;  include a file based on whether it has already been included.
                    550: ;
                    551: (defmacro include-if (pred filename)
                    552:    (cond ((eval pred) `(include ,filename))))
                    553: 
                    554: ;--- includef-if
                    555: ; form: (includef-if <predicate> '<filename>)
                    556: ;  like the above except it includef's the file.
                    557: ;
                    558: (defmacro includef-if (pred filenameexpr)
                    559:    (cond ((eval pred) `(includef ,filenameexpr))))
                    560: 
                    561: ;--- if :: macro for doing conditionalization
                    562: ;
                    563: ;  This macro is compatible with both the crufty mit-version and
                    564: ; the keyword version at ucb.
                    565: ;
                    566: ;  simple summary:
                    567: ;   non-keyword use:
                    568: ;      (if a b) ==> (cond (a b))
                    569: ;      (if a b c d e ...) ==> (cond (a b) (t c d e ...))
                    570: ;   with keywords:
                    571: ;      (if a then b) ==> (cond (a b))
                    572: ;      (if a thenret) ==> (cond (a))
                    573: ;      (if a then b c d e) ==> (cond (a b c d e))
                    574: ;      (if a then b c  else d) ==> (cond (a b c) (t d))
                    575: ;      (if a then b c  elseif d  thenret  else g)
                    576: ;              ==> (cond (a b c) (d) (t g))
                    577: ;
                    578: ;   
                    579: ;
                    580: ;
                    581: ; In the syntax description below,
                    582: ;    optional parts are surrounded by [ and ],
                    583: ;    + means one or more instances.
                    584: ;    | means 'or'
                    585: ;    <expr> is an lisp expression which isn't a keyword
                    586: ;       The keywords are:  then, thenret, else, elseif.
                    587: ;    <pred> is also a lisp expression which isn't a keyword.
                    588: ; 
                    589: ; <if-stmt> ::=  <simple-if-stmt>
                    590: ;             | <keyword-if-stmt>
                    591: ; 
                    592: ; <simple-if-stmt> ::=  (if <pred> <expr>)
                    593: ;                    | (if <pred> <expr> <expr>)
                    594: ; 
                    595: ; <keyword-if-stmt> ::= (if <pred> <then-clause> [ <else-clause> ] )
                    596: ; 
                    597: ; <then-clause> ::=  then <expr>+
                    598: ;                 | thenret
                    599: ; 
                    600: ; <else-clause> ::=  else <expr>+
                    601: ;                 | elseif <pred> <then-clause> [ <else-clause> ]
                    602: ;
                    603: 
                    604: (declare (special if-keyword-list))
                    605: 
                    606: (eval-when (compile load eval)
                    607:    (setq if-keyword-list '(then thenret elseif else)))
                    608: 
                    609: ;--- if
                    610: ;
                    611: ;  the keyword if expression is parsed using a simple four state
                    612: ; automaton.  The expression is parsed in reverse.
                    613: ; States:
                    614: ;      init - have parsed a complete predicate,  then clause
                    615: ;      col  - have collected at least one non keyword in col
                    616: ;      then - have just seen a then, looking for a predicate
                    617: ;      compl - have just seen a predicate after an then, looking
                    618: ;              for elseif or if (i.e. end of forms).
                    619: ;
                    620: (defmacro if (&rest args)
                    621:    (let ((len (length args)))
                    622:       ;; first eliminate the non-keyword if macro cases
                    623:       (cond ((<& len 2)
                    624:             (error "if: not enough arguments " args))
                    625:            ((and (=& len 2)
                    626:                  (not (memq (cadr args) if-keyword-list)))
                    627:             `(cond (,(car args) ,(cadr args))))
                    628:            ; clause if there are not keywords (and len > 2)
                    629:            ((do ((xx args (cdr xx)))
                    630:                 ((null xx) t)
                    631:                 (cond ((memq (car xx) if-keyword-list)
                    632:                        (return nil))))
                    633:             `(cond (,(car args) ,(cadr args))
                    634:                    (t ,@(cddr args))))
                    635:            
                    636:            ;; must be an instance of a keyword if macro
                    637:            
                    638:            (t (do ((xx (reverse args) (cdr xx))
                    639:                    (state 'init)
                    640:                    (elseseen nil)
                    641:                    (totalcol nil)
                    642:                    (col nil))
                    643:                   ((null xx)
                    644:                    (cond ((eq state 'compl)
                    645:                           `(cond ,@totalcol))
                    646:                          (t (error "if: illegal form " args))))
                    647:                   (cond ((eq state 'init)
                    648:                          (cond ((memq (car xx) if-keyword-list)
                    649:                                 (cond ((eq (car xx) 'thenret)
                    650:                                        (setq col nil
                    651:                                              state 'then))
                    652:                                       (t (error "if: bad keyword "
                    653:                                                 (car xx) args))))
                    654:                                (t (setq state 'col
                    655:                                         col nil)
                    656:                                   (push (car xx) col))))
                    657:                         ((eq state 'col)
                    658:                          (cond ((memq (car xx) if-keyword-list)
                    659:                                 (cond ((eq (car xx) 'else)
                    660:                                        (cond (elseseen
                    661:                                                 (error
                    662:                                                    "if: multiples elses "
                    663:                                                    args)))
                    664:                                        (setq elseseen t)
                    665:                                        (setq state 'init)
                    666:                                        (push `(t ,@col) totalcol))
                    667:                                       ((eq (car xx) 'then)
                    668:                                        (setq state 'then))
                    669:                                       (t (error "if: bad keyword "
                    670:                                                 (car xx) args))))
                    671:                                (t (push (car xx) col))))
                    672:                         ((eq state 'then)
                    673:                          (cond ((memq (car xx) if-keyword-list)
                    674:                                 (error "if: keyword at the wrong place "
                    675:                                        (car xx) args))
                    676:                                (t (setq state 'compl)
                    677:                                   (push `(,(car xx) ,@col) totalcol))))
                    678:                         ((eq state 'compl)
                    679:                          (cond ((not (eq (car xx) 'elseif))
                    680:                                 (error "if: missing elseif clause " args)))
                    681:                          (setq state 'init))))))))
                    682: 
                    683: ;--- If :: the same as 'if' but defined for those programs that still
                    684: ;      use it.
                    685: ;
                    686: (putd 'If (getd 'if))
                    687: 
                    688: ;--- defvar :: a macro for declaring a variable special
                    689: ;  a variable declared special with defvar will be special when the
                    690: ; file containing the variable is compiled and also when the file
                    691: ; containing the defvar is loaded in.  Furthermore, you can specify
                    692: ; an default value for the variable. It will be set to that value
                    693: ; iff it is unbound
                    694: ;
                    695: (defmacro defvar (variable &optional (initial-value nil iv-p) documentation)
                    696:   (if iv-p
                    697:      then `(progn 'compile
                    698:                   (eval-when (eval compile load)
                    699:                          (eval '(liszt-declare (special ,variable))))
                    700:                   (or (boundp ',variable) (setq ,variable ,initial-value)))
                    701:      else `(eval-when (eval compile load)
                    702:                  (eval '(liszt-declare (special ,variable))))))
                    703: 
                    704: 
                    705: 
                    706: 
                    707: (defmacro list* (&rest forms)
                    708:          (cond ((null forms) nil)
                    709:                ((null (cdr forms)) (car forms))
                    710:                (t (construct-list* forms))))
                    711: 
                    712: (eval-when (load compile eval)
                    713:    (defun construct-list* (forms)
                    714:          (setq forms (reverse forms))
                    715:          (do ((forms (cddr forms) (cdr forms))
                    716:               (return-form `(cons ,(cadr forms) ,(car forms))
                    717:                             `(cons ,(car forms) ,return-form)))
                    718:              ((null forms) return-form))))
                    719: 
                    720: ;; (<= a b) --> (not (> a b))
                    721: ;; (<= a b c) --> (not (or (> a b) (> b c)))
                    722: ;; funny arglist to check for correct number of arguments.
                    723: 
                    724: 
                    725: (defmacro <= (arg1 arg2 &rest rest &aux result)
                    726:   (setq rest (list* arg1 arg2 rest))
                    727:   (do l rest (cdr l) (null (cdr l))
                    728:       (push `(> ,(car l) ,(cadr l)) result))
                    729:   (cond ((null (cdr result)) `(not ,(car result)))
                    730:        (t `(not (or . ,(nreverse result))))))
                    731: 
                    732: (defmacro <=& (x y)
                    733:    `(not (>& ,x ,y)))
                    734: 
                    735: ;; (>= a b) --> (not (< a b))
                    736: ;; (>= a b c) --> (not (or (< a b) (< b c)))
                    737: ;; funny arglist to check for correct number of arguments.
                    738: 
                    739: (defmacro >= (arg1 arg2 &rest rest &aux result)
                    740:   (setq rest (list* arg1 arg2 rest))
                    741:   (do l rest (cdr l) (null (cdr l))
                    742:       (push `(< ,(car l) ,(cadr l)) result))
                    743:   (cond ((null (cdr result)) `(not ,(car result)))
                    744:        (t `(not (or . ,(nreverse result))))))
                    745: 
                    746: 
                    747: (defmacro >=& (x y)
                    748:    `(not (<& ,x ,y)))

unix.superglobalmegacorp.com

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