1
0
mirror of synced 2026-01-12 00:42:56 +00:00
Interlisp.medley/clos/macros.lisp
2021-03-08 21:12:00 -08:00

356 lines
13 KiB
Common Lisp

;;;-*- Package: CLOS; Syntax: Common-Lisp; Base: 10 -*-
;;; File converted on 26-Mar-91 10:27:21 from source macros
;;;. Original source {dsk}<usr>local>users>welch>lisp>clos>rev4>il-format>macros.;3 created 19-Feb-91 13:51:21
;;;. Copyright (c) 1991 Venue
(in-package "CLOS")
;;;Macros global variable
;;; definitions, and other random support stuff used by the rest of the system. For simplicity (not
;;; having to use eval-when a lot), this file must be loaded before it can be compiled.
(in-package 'clos)
(proclaim '(declaration values arglist indentation class variable-rebinding clos-fast-call))
;;; Age old functions which CommonLisp cleaned-up away. They probably exist in other packages in
;;; all CommonLisp implementations, but I will leave it to the compiler to optimize into calls to
;;; them. Common Lisp BUG: Some Common Lisps define these in the Lisp package which causes all sorts
;;; of lossage. Common Lisp should explictly specify which symbols appear in the Lisp package.
(eval-when (compile load eval)
(defmacro memq (item list)
`(member ,item ,list :test #'eq))
(defmacro assq (item list)
`(assoc ,item ,list :test #'eq))
(defmacro rassq (item list)
`(rassoc ,item ,list :test #'eq))
(defmacro delq (item list)
`(delete ,item ,list :test #'eq))
(defmacro posq (item list)
`(position ,item ,list :test #'eq))
(defmacro neq (x y)
`(not (eq ,x ,y)))
(defun make-caxr (n form)
(if (< n 4)
`(,(nth n '(car cadr caddr cadddr))
,form)
(make-caxr (- n 4)
`(cddddr ,form))))
(defun make-cdxr (n form)
(cond ((zerop n)
form)
((< n 5)
`(,(nth n '(identity cdr cddr cdddr cddddr))
,form))
(t (make-cdxr (- n 4)
`(cddddr ,form))))))
(defun zero (&rest ignore)
(declare (ignore ignore))
0)
(defun make-plist (keys vals)
(if (null vals)
nil
(list* (car keys)
(car vals)
(make-plist (cdr keys)
(cdr vals)))))
(defun remtail (list tail)
(if (eq list tail)
nil
(cons (car list)
(remtail (cdr list)
tail))))
;;; ONCE-ONLY does the same thing as it does in zetalisp. I should have just lifted it from there
;;; but I am honest. Not only that but this one is written in Common Lisp. I feel a lot like
;;; bootstrapping, or maybe more like rebuilding Rome.
(defmacro once-only (vars &body body)
(let ((gensym-var (gensym))
(run-time-vars (gensym))
(run-time-vals (gensym))
(expand-time-val-forms nil))
(dolist (var vars)
(push `(if (or (symbolp ,var)
(numberp ,var)
(and (listp ,var)
(member (car ,var)
''function)))
,var
(let ((,gensym-var (gensym)))
(push ,gensym-var ,run-time-vars)
(push ,var ,run-time-vals)
,gensym-var))
expand-time-val-forms))
`(let* (,run-time-vars ,run-time-vals (wrapped-body (let ,(mapcar #'list vars
(reverse
expand-time-val-forms
))
,@body)))
`(let ,(mapcar #'list (reverse ,run-time-vars)
(reverse ,run-time-vals))
,wrapped-body))))
(eval-when
(compile load eval)
(defun extract-declarations (body &optional environment)
(declare (values documentation declarations body))
(let (documentation declarations form)
(when (and (stringp (car body))
(cdr body))
(setq documentation (pop body)))
(block outer
(loop (when (null body)
(return-from outer nil))
(setq form (car body))
(when (block inner
(loop (cond ((not (listp form))
(return-from outer nil))
((eq (car form)
'declare)
(return-from inner 't))
(t (multiple-value-bind
(newform macrop)
(macroexpand-1 form environment)
(if (or (not (eq newform form))
macrop)
(setq form newform)
(return-from outer nil)))))))
(pop body)
(dolist (declaration (cdr form))
(push declaration declarations)))))
(values documentation (and declarations `((declare ,.(nreverse declarations))))
body))))
(defvar *keyword-package* (find-package 'keyword))
(defun make-keyword (symbol)
(intern (symbol-name symbol)
*keyword-package*))
(eval-when (compile load eval)
(defun string-append (&rest strings)
(setq strings (copy-list strings))
; The explorer can't even rplaca an
; &rest arg?
(do ((string-loc strings (cdr string-loc)))
((null string-loc)
(apply #'concatenate 'string strings))
(rplaca string-loc (string (car string-loc))))))
(defun symbol-append (sym1 sym2 &optional (package *package*))
(intern (string-append sym1 sym2)
package))
(defmacro check-member (place list &key (test #'eql)
(pretty-name place))
(once-only (place list)
`(or (member ,place ,list :test ,test)
(error "The value of ~A, ~S is not one of ~S." ',pretty-name ,place ,list))))
(defmacro alist-entry (alist key make-entry-fn)
(once-only (alist key)
`(or (assq ,key ,alist)
(progn (setf ,alist (cons (,make-entry-fn ,key)
,alist))
(car ,alist)))))
(defmacro collecting-once (&key initial-value)
`(let* ((head ,initial-value)
(tail ,(and initial-value `(last head))))
(values #'(lambda (value)
(if (null head)
(setq head (setq tail (list value)))
(unless (memq value head)
(setq tail (cdr (rplacd tail (list value)))))))
#'(lambda nil head))))
(defmacro doplist ((key val)
plist &body body &environment env)
(multiple-value-bind (doc decls bod)
(extract-declarations body env)
(declare (ignore doc))
`(let ((.plist-tail. ,plist)
,key
,val)
,@decls
(loop (when (null .plist-tail.)
(return nil))
(setq ,key (pop .plist-tail.))
(when (null .plist-tail.)
(error "Malformed plist in doplist, odd number of elements."))
(setq ,val (pop .plist-tail.))
(progn ,@bod)))))
(defmacro if* (condition true &rest false)
`(if ,condition
,true
(progn ,@false)))
;;
;;; printing-random-thing
;;
;;; Similar to printing-random-object in the lisp machine but much simpler and machine independent.
(defmacro printing-random-thing ((thing stream)
&body body)
(once-only (stream)
`(progn (format ,stream "#<")
,@body
(format ,stream " ")
(printing-random-thing-internal ,thing ,stream)
(format ,stream ">"))))
(defun printing-random-thing-internal (thing stream)
(let ((*print-base* 8))
(princ (il:\\hiloc thing)
stream)
(princ "," stream)
(princ (il:\\loloc thing)
stream)))
;;
;;;
;;
(defun capitalize-words (string &optional (dashes-p t))
(let ((string (copy-seq (string string))))
(declare (string string))
(do* ((flag t flag)
(length (length string)
length)
(char nil char)
(i 0 (+ i 1)))
((= i length)
string)
(setq char (elt string i))
(cond ((both-case-p char)
(if flag
(and (setq flag (lower-case-p char))
(setf (elt string i)
(char-upcase char)))
(and (not flag)
(setf (elt string i)
(char-downcase char))))
(setq flag nil))
((char-equal char #\-)
(setq flag t)
(unless dashes-p
(setf (elt string i)
#\Space)))
(t (setq flag nil))))))
;;; FIND-CLASS This is documented in the CLOS specification.
(defvar *find-class* (make-hash-table :test #'eq))
(defun legal-class-name-p (x)
(and (symbolp x)
(not (keywordp x))))
(defun find-class (symbol &optional (errorp t)
environment)
(declare (ignore environment))
(or (gethash symbol *find-class*)
(cond ((null errorp)
nil)
((legal-class-name-p symbol)
(error "No class named: ~S." symbol))
(t (error "~S is not a legal class name." symbol)))))
(defsetf find-class (symbol &optional (errorp t)
environment)
(new-value)
(declare (ignore errorp environment))
`(|SETF CLOS FIND-CLASS| ,new-value ,symbol))
(defun |SETF CLOS FIND-CLASS| (new-value symbol)
(if (legal-class-name-p symbol)
(setf (gethash symbol *find-class*)
new-value)
(error "~S is not a legal class name." symbol)))
(defun find-wrapper (symbol)
(class-wrapper (find-class symbol)))
(defmacro gathering1 (gatherer &body body)
`(gathering ((.gathering1. ,gatherer))
(macrolet ((gather1 (x)
`(gather ,x .gathering1.)))
,@body)))
;;;
(defmacro vectorizing (&key (size 0))
`(let* ((limit ,size)
(result (make-array limit))
(index 0))
(values #'(lambda (value)
(if (= index limit)
(error "vectorizing more elements than promised.")
(progn (setf (svref result index)
value)
(incf index)
value)))
#'(lambda nil result))))
;;; These are augmented definitions of list-elements and list-tails from iterate.lisp. These
;;; versions provide the extra :by keyword which can be used to specify the step function through
;;; the list.
(defmacro *list-elements (list &key (by #'cdr))
`(let ((tail ,list))
#'(lambda (finish)
(if (endp tail)
(funcall finish)
(prog1 (car tail)
(setq tail (funcall ,by tail)))))))
(defmacro *list-tails (list &key (by #'cdr))
`(let ((tail ,list))
#'(lambda (finish)
(prog1 (if (endp tail)
(funcall finish)
tail)
(setq tail (funcall ,by tail))))))