Mercurial > emacs
changeset 1553:6b409871cc4a
* cl.el: New version - 3.0 - from Cesar Quiroz.
author | Jim Blandy <jimb@redhat.com> |
---|---|
date | Sat, 07 Nov 1992 06:11:16 +0000 |
parents | f2901040a07b |
children | 5af75a1a9a24 |
files | lisp/=cl.el |
diffstat | 1 files changed, 359 insertions(+), 242 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/=cl.el Sat Nov 07 06:10:53 1992 +0000 +++ b/lisp/=cl.el Sat Nov 07 06:11:16 1992 +0000 @@ -1,11 +1,10 @@ -;;; cl.el --- Common-Lisp extensions for GNU Emacs Lisp. - -;; Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc. +;; Common-Lisp extensions for GNU Emacs Lisp. +;; Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc. ;; Author: Cesar Quiroz <quiroz@cs.rochester.edu> ;; Keywords: extensions -(defvar cl-version "2.0 beta 29 October 1989") +(defvar cl-version "3.0 beta 01 November 1992") ;; This file is part of GNU Emacs. @@ -24,6 +23,29 @@ ;; file named COPYING. Among other things, the copyright notice ;; and this notice must be preserved on all copies. +;;; Notes from Rob Austein on his mods +;; yaya:/usr/u/sra/cl/cl.el, 5-May-1991 16:01:34, sra +;; +;; Slightly hacked copy of cl.el 2.0 beta 27. +;; +;; Various minor performance improvements: +;; a) Don't use MAPCAR when we're going to discard its results. +;; b) Make various macros a little more clever about optimizing +;; generated code in common cases. +;; c) Fix DEFSETF to expand to the right code at compile-time. +;; d) Make various macros cleverer about generating reasonable +;; code when compiled, particularly forms like DEFSTRUCT which +;; are usually used at top-level and thus are only compiled if +;; you use Hallvard Furuseth's hacked bytecomp.el. +;; +;; New features: GETF, REMF, and REMPROP. +;; +;; Notes: +;; 1) I'm sceptical about the FBOUNDP checks in SETF. Why should +;; the SETF expansion fail because the SETF method isn't defined +;; at compile time? Lisp is going to check for a binding at run-time +;; anyway, so maybe we should just assume the user's right here. + ;;; Commentary: ;;;; These are extensions to Emacs Lisp that provide some form of @@ -47,6 +69,9 @@ ;;;; the files are concatenated together one cannot ensure that ;;;; declaration always precedes use. ;;;; +;;;; Bug reports, suggestions and comments, +;;;; to quiroz@cs.rochester.edu + ;;;; GLOBAL ;;;; This file provides utilities and declarations that are global @@ -64,29 +89,23 @@ ;;; Code: -(defmacro psetq (&rest body) - "(psetq {var value }...) => nil -Like setq, but all the values are computed before any assignment is made." - (let ((length (length body))) - (cond ((/= (% length 2) 0) - (error "psetq needs an even number of arguments, %d given" - length)) - ((null body) - '()) - (t - (list 'prog1 nil - (let ((setqs '()) - (bodyforms (reverse body))) - (while bodyforms - (let* ((value (car bodyforms)) - (place (cadr bodyforms))) - (setq bodyforms (cddr bodyforms)) - (if (null setqs) - (setq setqs (list 'setq place value)) - (setq setqs (list 'setq place - (list 'prog1 value - setqs)))))) - setqs)))))) +;;; This version is due to Hallvard Furuseth (hallvard@ifi.uio.no, 6 Jul 91) +(defmacro psetq (&rest args) + "(psetq {VARIABLE VALUE}...): In parallel, set each VARIABLE to its VALUE. +All the VALUEs are evaluated, and then all the VARIABLEs are set. +Aside from order of evaluation, this is the same as `setq'." + ;; check there is a reasonable number of forms + (if (/= (% (length args) 2) 0) + (error "Odd number of arguments to `psetq'")) + (setq args (copy-sequence args)) ;for safety below + (prog1 (cons 'setq args) + (while (progn (if (not (symbolp (car args))) + (error "`psetq' expected a symbol, found '%s'." + (prin1-to-string (car args)))) + (cdr (cdr args))) + (setcdr args (list (list 'prog1 (nth 1 args) + (cons 'setq + (setq args (cdr (cdr args)))))))))) ;;; utilities ;;; @@ -111,8 +130,8 @@ (defun zip-lists (evens odds) "Merge two lists EVENS and ODDS, taking elts from each list alternatingly. EVENS and ODDS are two lists. ZIP-LISTS constructs a new list, whose -even numbered elements (0,2,...) come from EVENS and whose odd numbered -elements (1,3,...) come from ODDS. +even numbered elements (0,2,...) come from EVENS and whose odd +numbered elements (1,3,...) come from ODDS. The construction stops when the shorter list is exhausted." (do* ((p0 evens (cdr p0)) (p1 odds (cdr p1)) @@ -164,9 +183,11 @@ ;;; larger lists. The fourth pass could be eliminated. ;;; 10 dec 1986. Emacs Lisp has no REMPROP, so I just eliminated the ;;; 4th pass. +;;; +;;; [22 April 1991, sra] REMPROP now in library, so restored 4th pass. (defun duplicate-symbols-p (list) "Find all symbols appearing more than once in LIST. -Return a list of all such duplicates; nil if there are no duplicates." +Return a list of all such duplicates; `nil' if there are no duplicates." (let ((duplicates '()) ;result built here (propname (gensym)) ;we use a fresh property ) @@ -184,8 +205,9 @@ (dolist (x list) (if (> (get x propname) 1) (setq duplicates (cons x duplicates)))) - ;; pass 4: unmark. eliminated. - ;; (dolist (x list) (remprop x propname)) + ;; pass 4: unmark. + (dolist (x list) + (remprop x propname)) ;; return result duplicates)) @@ -203,14 +225,14 @@ (defmacro defkeyword (x &optional docstring) "Make symbol X a keyword (symbol whose value is itself). -Optional second arg DOCSTRING is a documentation string for it." +Optional second argument is a documentation string for it." (cond ((symbolp x) (list 'defconst x (list 'quote x) docstring)) (t (error "`%s' is not a symbol" (prin1-to-string x))))) (defun keywordp (sym) - "Return t if SYM is a keyword." + "t if SYM is a keyword." (if (and (symbolp sym) (char-equal (aref (symbol-name sym) 0) ?\:)) ;; looks like one, make sure value is right (set sym sym) @@ -232,17 +254,17 @@ ;;; (defvar *gentemp-index* 0 - "Integer used by `gentemp' to produce new names.") + "Integer used by gentemp to produce new names.") (defvar *gentemp-prefix* "T$$_" - "Names generated by `gentemp begin' with this string by default.") + "Names generated by gentemp begin with this string by default.") (defun gentemp (&optional prefix oblist) "Generate a fresh interned symbol. -There are two optional arguments, PREFIX and OBLIST. PREFIX is the string -that begins the new name, OBLIST is the obarray used to search for old -names. The defaults are just right, YOU SHOULD NEVER NEED THESE ARGUMENTS -IN YOUR OWN CODE." +There are 2 optional arguments, PREFIX and OBLIST. PREFIX is the +string that begins the new name, OBLIST is the obarray used to search for +old names. The defaults are just right, YOU SHOULD NEVER NEED THESE +ARGUMENTS IN YOUR OWN CODE." (if (null prefix) (setq prefix *gentemp-prefix*)) (if (null oblist) @@ -257,15 +279,16 @@ newsymbol)) (defvar *gensym-index* 0 - "Integer used by `gensym' to produce new names.") + "Integer used by gensym to produce new names.") (defvar *gensym-prefix* "G$$_" - "Names generated by `gensym' begin with this string by default.") + "Names generated by gensym begin with this string by default.") (defun gensym (&optional prefix) "Generate a fresh uninterned symbol. -Optional arg PREFIX is the string that begins the new name. Most people -take just the default, except when debugging needs suggest otherwise." +There is an optional argument, PREFIX. PREFIX is the +string that begins the new name. Most people take just the default, +except when debugging needs suggest otherwise." (if (null prefix) (setq prefix *gensym-prefix*)) (let ((newsymbol nil) @@ -289,10 +312,10 @@ ;;;; (quiroz@cs.rochester.edu) ;;; indentation info -(put 'case 'lisp-indent-function 1) -(put 'ecase 'lisp-indent-function 1) -(put 'when 'lisp-indent-function 1) -(put 'unless 'lisp-indent-function 1) +(put 'case 'lisp-indent-hook 1) +(put 'ecase 'lisp-indent-hook 1) +(put 'when 'lisp-indent-hook 1) +(put 'unless 'lisp-indent-hook 1) ;;; WHEN and UNLESS ;;; These two forms are simplified ifs, with a single branch. @@ -408,29 +431,26 @@ ;;;; (quiroz@cs.rochester.edu) ;;; some lisp-indentation information -(put 'do 'lisp-indent-function 2) -(put 'do* 'lisp-indent-function 2) -(put 'dolist 'lisp-indent-function 1) -(put 'dotimes 'lisp-indent-function 1) -(put 'do-symbols 'lisp-indent-function 1) -(put 'do-all-symbols 'lisp-indent-function 1) +(put 'do 'lisp-indent-hook 2) +(put 'do* 'lisp-indent-hook 2) +(put 'dolist 'lisp-indent-hook 1) +(put 'dotimes 'lisp-indent-hook 1) +(put 'do-symbols 'lisp-indent-hook 1) +(put 'do-all-symbols 'lisp-indent-hook 1) (defmacro do (stepforms endforms &rest body) - "(do STEPFORMS ENDFORMS . BODY): Iterate BODY, stepping some local -variables. STEPFORMS must be a list of symbols or lists. In the second -case, the lists must start with a symbol and contain up to two more forms. -In the STEPFORMS, a symbol is the same as a (symbol). The other two forms + "(do STEPFORMS ENDFORMS . BODY): Iterate BODY, stepping some local variables. +STEPFORMS must be a list of symbols or lists. In the second case, the +lists must start with a symbol and contain up to two more forms. In +the STEPFORMS, a symbol is the same as a (symbol). The other 2 forms are the initial value (def. NIL) and the form to step (def. itself). - The values used by initialization and stepping are computed in parallel. -The ENDFORMS are a list (CONDITION . ENDBODY). If the CONDITION evaluates -to true in any iteration, ENDBODY is evaluated and the last form in it is -returned. - -The BODY (which may be empty) is evaluated at every iteration, with the -symbols of the STEPFORMS bound to the initial or stepped values." - +The ENDFORMS are a list (CONDITION . ENDBODY). If the CONDITION +evaluates to true in any iteration, ENDBODY is evaluated and the last +form in it is returned. +The BODY (which may be empty) is evaluated at every iteration, with +the symbols of the STEPFORMS bound to the initial or stepped values." ;; check the syntax of the macro (and (check-do-stepforms stepforms) (check-do-endforms endforms)) @@ -448,16 +468,13 @@ (defmacro do* (stepforms endforms &rest body) "`do*' is to `do' as `let*' is to `let'. STEPFORMS must be a list of symbols or lists. In the second case, the -lists must start with a symbol and contain up to two more forms. In the -STEPFORMS, a symbol is the same as a (symbol). The other two forms are -the initial value (def. NIL) and the form to step (def. itself). - +lists must start with a symbol and contain up to two more forms. In +the STEPFORMS, a symbol is the same as a (symbol). The other 2 forms +are the initial value (def. NIL) and the form to step (def. itself). Initializations and steppings are done in the sequence they are written. - -The ENDFORMS are a list (CONDITION . ENDBODY). If the CONDITION evaluates -to true in any iteration, ENDBODY is evaluated and the last form in it is -returned. - +The ENDFORMS are a list (CONDITION . ENDBODY). If the CONDITION +evaluates to true in any iteration, ENDBODY is evaluated and the last +form in it is returned. The BODY (which may be empty) is evaluated at every iteration, with the symbols of the STEPFORMS bound to the initial or stepped values." ;; check the syntax of the macro @@ -501,8 +518,7 @@ (defun extract-do-inits (forms) "Returns a list of the initializations (for do) in FORMS -(a stepforms, see the do macro). -FORMS is assumed syntactically valid." +--a stepforms, see the do macro--. FORMS is assumed syntactically valid." (mapcar (function (lambda (entry) @@ -516,15 +532,17 @@ ;;; DO*. The writing of PSETQ has made it largely unnecessary. (defun extract-do-steps (forms) - "EXTRACT-DO-STEPS FORMS => an s-expr. -FORMS is the stepforms part of a DO macro (q.v.). This function constructs -an s-expression that does the stepping at the end of an iteration." + "EXTRACT-DO-STEPS FORMS => an s-expr +FORMS is the stepforms part of a DO macro (q.v.). This function +constructs an s-expression that does the stepping at the end of an +iteration." (list (cons 'psetq (select-stepping-forms forms)))) (defun extract-do*-steps (forms) - "EXTRACT-DO*-STEPS FORMS => an s-expr. -FORMS is the stepforms part of a DO* macro (q.v.). This function constructs -an s-expression that does the stepping at the end of an iteration." + "EXTRACT-DO*-STEPS FORMS => an s-expr +FORMS is the stepforms part of a DO* macro (q.v.). This function +constructs an s-expression that does the stepping at the end of an +iteration." (list (cons 'setq (select-stepping-forms forms)))) (defun select-stepping-forms (forms) @@ -546,8 +564,8 @@ (defmacro dolist (stepform &rest body) "(dolist (VAR LIST [RESULTFORM]) . BODY): do BODY for each elt of LIST. -The RESULTFORM defaults to nil. The VAR is bound to successive elements -of the value of LIST and remains bound (to the nil value) when the +The RESULTFORM defaults to nil. The VAR is bound to successive +elements of the value of LIST and remains bound (to the nil value) when the RESULTFORM is evaluated." ;; check sanity (cond @@ -563,23 +581,27 @@ ;; generate code (let* ((var (car stepform)) (listform (cadr stepform)) - (resultform (caddr stepform))) - (list 'progn - (list 'mapcar - (list 'function - (cons 'lambda (cons (list var) body))) - listform) - (list 'let - (list (list var nil)) - resultform)))) + (resultform (caddr stepform)) + (listsym (gentemp))) + (nconc + (list 'let (list var (list listsym listform)) + (nconc + (list 'while listsym + (list 'setq + var (list 'car listsym) + listsym (list 'cdr listsym))) + body)) + (and resultform + (cons (list 'setq var nil) + (list resultform)))))) (defmacro dotimes (stepform &rest body) - "(dotimes (VAR COUNTFORM [RESULTFORM]) . BODY): Repeat BODY, counting in VAR. + "(dotimes (VAR COUNTFORM [RESULTFORM]) . BODY): Repeat BODY, counting in VAR. The COUNTFORM should return a positive integer. The VAR is bound to -successive integers from 0 to COUNTFORM - 1 and the BODY is repeated for +successive integers from 0 to COUNTFORM-1 and the BODY is repeated for each of them. At the end, the RESULTFORM is evaluated and its value -returned. During this last evaluation, the VAR is still bound, and its -value is the number of times the iteration occurred. An omitted RESULTFORM +returned. During this last evaluation, the VAR is still bound, and its +value is the number of times the iteration occurred. An omitted RESULTFORM defaults to nil." ;; check sanity (cond @@ -596,14 +618,16 @@ (let* ((var (car stepform)) (countform (cadr stepform)) (resultform (caddr stepform)) - (newsym (gentemp))) + (testsym (if (consp countform) (gentemp) countform))) + (nconc (list - 'let* (list (list newsym countform)) - (list* - 'do* - (list (list var 0 (list '+ var 1))) - (list (list '>= var newsym) resultform) - body)))) + 'let (cons (list var -1) + (and (not (eq countform testsym)) + (list (list testsym countform)))) + (nconc + (list 'while (list '< (list 'setq var (list '1+ var)) testsym)) + body)) + (and resultform (list resultform))))) (defmacro do-symbols (stepform &rest body) "(do_symbols (VAR [OBARRAY [RESULTFORM]]) . BODY) @@ -671,11 +695,6 @@ ;;;; Cesar Quiroz @ UofR DofCSc - Dec. 1986 ;;;; (quiroz@cs.rochester.edu) - - -;;; To make these faster, we define them using defsubst. This directs the -;;; compiler to open-code these functions. - ;;; Synonyms for list functions (defsubst first (x) "Synonym for `car'" @@ -721,7 +740,7 @@ "Synonym for `cdr'" (cdr x)) -(defun endp (x) +(defsubst endp (x) "t if X is nil, nil if X is a cons; error otherwise." (if (listp x) (null x) @@ -758,18 +777,20 @@ "Return a new list like LIST but sans the last N elements. N defaults to 1. If the list doesn't have N elements, nil is returned." (if (null n) (setq n 1)) - (reverse (nthcdr n (reverse list)))) + (nreverse (nthcdr n (reverse list)))) ;optim. due to macrakis@osf.org +;;; This version due to Aaron Larson (alarson@src.honeywell.com, 26 Jul 91) (defun list* (arg &rest others) "Return a new list containing the first arguments consed onto the last arg. Thus, (list* 1 2 3 '(a b)) returns (1 2 3 a b)." (if (null others) arg - (let* ((allargs (cons arg others)) - (front (butlast allargs)) - (back (last allargs))) - (rplacd (last front) (car back)) - front))) + (let* ((others (cons arg (copy-sequence others))) + (a others)) + (while (cdr (cdr a)) + (setq a (cdr a))) + (setcdr a (car (cdr a))) + others))) (defun adjoin (item list) "Return a list which contains ITEM but is otherwise like LIST. @@ -790,8 +811,8 @@ ;;; The popular c[ad]*r functions and other list accessors. -;;; To implement this efficiently, we define them using defsubst, -;;; which directs the compiler to open-code these functions. +;;; To implement this efficiently, a new byte compile handler is used to +;;; generate the minimal code, saving one function call. (defsubst caar (X) "Return the car of the car of X." @@ -907,25 +928,26 @@ ;;; some inverses of the accessors are needed for setf purposes -(defun setnth (n list newval) +(defsubst setnth (n list newval) "Set (nth N LIST) to NEWVAL. Returns NEWVAL." (rplaca (nthcdr n list) newval)) (defun setnthcdr (n list newval) "(setnthcdr N LIST NEWVAL) => NEWVAL As a side effect, sets the Nth cdr of LIST to NEWVAL." - (cond ((< n 0) - (error "N must be 0 or greater, not %d" n)) - ((= n 0) - (rplaca list (car newval)) - (rplacd list (cdr newval)) - newval) - (t - (rplacd (nthcdr (- n 1) list) newval)))) + (when (< n 0) + (error "N must be 0 or greater, not %d" n)) + (while (> n 0) + (setq list (cdr list) + n (- n 1))) + ;; here only if (zerop n) + (rplaca list (car newval)) + (rplacd list (cdr newval)) + newval) ;;; A-lists machinery -(defun acons (key item alist) +(defsubst acons (key item alist) "Return a new alist with KEY paired with ITEM; otherwise like ALIST. Does not copy ALIST." (cons (cons key item) alist)) @@ -945,6 +967,7 @@ ((endp kptr) result) (setq result (acons key item result)))) +;;;; end of cl-lists.el ;;;; SEQUENCES ;;;; Emacs Lisp provides many of the 'sequences' functionality of @@ -952,18 +975,19 @@ ;;;; -(defkeyword :test "Used to designate positive (selection) tests.") -(defkeyword :test-not "Used to designate negative (rejection) tests.") -(defkeyword :key "Used to designate component extractions.") -(defkeyword :predicate "Used to define matching of sequence components.") -(defkeyword :start "Inclusive low index in sequence") -(defkeyword :end "Exclusive high index in sequence") -(defkeyword :start1 "Inclusive low index in first of two sequences.") -(defkeyword :start2 "Inclusive low index in second of two sequences.") -(defkeyword :end1 "Exclusive high index in first of two sequences.") -(defkeyword :end2 "Exclusive high index in second of two sequences.") -(defkeyword :count "Number of elements to affect.") -(defkeyword :from-end "T when counting backwards.") +(defkeyword :test "Used to designate positive (selection) tests.") +(defkeyword :test-not "Used to designate negative (rejection) tests.") +(defkeyword :key "Used to designate component extractions.") +(defkeyword :predicate "Used to define matching of sequence components.") +(defkeyword :start "Inclusive low index in sequence") +(defkeyword :end "Exclusive high index in sequence") +(defkeyword :start1 "Inclusive low index in first of two sequences.") +(defkeyword :start2 "Inclusive low index in second of two sequences.") +(defkeyword :end1 "Exclusive high index in first of two sequences.") +(defkeyword :end2 "Exclusive high index in second of two sequences.") +(defkeyword :count "Number of elements to affect.") +(defkeyword :from-end "T when counting backwards.") +(defkeyword :initial-value "For the syntax of #'reduce") (defun some (pred seq &rest moreseqs) "Test PREDICATE on each element of SEQUENCE; is it ever non-nil? @@ -1195,7 +1219,7 @@ predicate under :predicate in KLIST." (let ((predicate (extract-from-klist klist :predicate)) (keyfn (extract-from-klist klist :key 'identity))) - (funcall predicate item (funcall keyfn elt)))) + (funcall predicate (funcall keyfn item)))) (defun elt-satisfies-if-not-p (item klist) "(elt-satisfies-if-not-p ITEM KLIST) => t or nil @@ -1204,7 +1228,7 @@ the predicate under :predicate in KLIST." (let ((predicate (extract-from-klist klist :predicate)) (keyfn (extract-from-klist klist :key 'identity))) - (not (funcall predicate item (funcall keyfn elt))))) + (not (funcall predicate (funcall keyfn item))))) (defun elts-match-under-klist-p (e1 e2 klist) "(elts-match-under-klist-p E1 E2 KLIST) => t or nil @@ -1313,7 +1337,7 @@ allow-other-keys))) (nreverse forms))) body)))) -(put 'with-keyword-args 'lisp-indent-function 1) +(put 'with-keyword-args 'lisp-indent-hook 1) ;;; REDUCE @@ -1394,14 +1418,15 @@ (defun member (item list &rest kargs) "Look for ITEM in LIST; return first tail of LIST the car of whose first -cons cell tests the same as ITEM. Admits arguments :key, :test, and :test-not." +cons cell tests the same as ITEM. Admits arguments :key, :test, and +:test-not." (if (null kargs) ;treat this fast for efficiency (memq item list) (let* ((klist (build-klist kargs '(:test :test-not :key))) (test (extract-from-klist klist :test)) (testnot (extract-from-klist klist :test-not)) (key (extract-from-klist klist :key 'identity))) - ;; another workaround allegledly for speed + ;; another workaround allegedly for speed, BLAH (if (and (or (eq test 'eq) (eq test 'eql) (eq test (symbol-function 'eq)) (eq test (symbol-function 'eql))) @@ -1448,11 +1473,11 @@ ;;;; (quiroz@cs.rochester.edu) ;;; Lisp indentation information -(put 'multiple-value-bind 'lisp-indent-function 2) -(put 'multiple-value-setq 'lisp-indent-function 2) -(put 'multiple-value-list 'lisp-indent-function nil) -(put 'multiple-value-call 'lisp-indent-function 1) -(put 'multiple-value-prog1 'lisp-indent-function 1) +(put 'multiple-value-bind 'lisp-indent-hook 2) +(put 'multiple-value-setq 'lisp-indent-hook 2) +(put 'multiple-value-list 'lisp-indent-hook nil) +(put 'multiple-value-call 'lisp-indent-hook 1) +(put 'multiple-value-prog1 'lisp-indent-hook 1) ;;; Global state of the package is kept here (defvar *mvalues-values* nil @@ -1478,7 +1503,7 @@ (car *mvalues-values*)) (defun values-list (&optional val-forms) - "Produce multiple values (zero or mode). Each element of LIST is one value. + "Produce multiple values (zero or more). Each element of LIST is one value. This is equivalent to (apply 'values LIST)." (cond ((nlistp val-forms) (error "Argument to values-list must be a list, not `%s'" @@ -1589,29 +1614,29 @@ ;;;; (quiroz@cs.rochester.edu) -(defun plusp (number) +(defsubst plusp (number) "True if NUMBER is strictly greater than zero." (> number 0)) -(defun minusp (number) +(defsubst minusp (number) "True if NUMBER is strictly less than zero." (< number 0)) -(defun oddp (number) +(defsubst oddp (number) "True if INTEGER is not divisible by 2." (/= (% number 2) 0)) -(defun evenp (number) +(defsubst evenp (number) "True if INTEGER is divisible by 2." (= (% number 2) 0)) -(defun abs (number) +(defsubst abs (number) "Return the absolute value of NUMBER." (if (< number 0) (- number) number)) -(defun signum (number) +(defsubst signum (number) "Return -1, 0 or 1 according to the sign of NUMBER." (cond ((< number 0) -1) @@ -1701,59 +1726,56 @@ (defun floor (number &optional divisor) "Divide DIVIDEND by DIVISOR, rounding toward minus infinity. DIVISOR defaults to 1. The remainder is produced as a second value." - (cond - ((and (null divisor) ; trivial case - (numberp number)) - (values number 0)) - (t ; do the division - (multiple-value-bind - (q r s) - (safe-idiv number divisor) - (cond ((zerop s) - (values 0 0)) - ((plusp s) - (values q r)) - (t ;opposite-signs case - (if (zerop r) - (values (- q) 0) - (let ((q (- (+ q 1)))) - (values q (- number (* q divisor))))))))))) + (cond ((and (null divisor) ; trivial case + (numberp number)) + (values number 0)) + (t ; do the division + (multiple-value-bind + (q r s) + (safe-idiv number divisor) + (cond ((zerop s) + (values 0 0)) + ((plusp s) + (values q r)) + (t ;opposite-signs case + (if (zerop r) + (values (- q) 0) + (let ((q (- (+ q 1)))) + (values q (- number (* q divisor))))))))))) (defun ceiling (number &optional divisor) "Divide DIVIDEND by DIVISOR, rounding toward plus infinity. DIVISOR defaults to 1. The remainder is produced as a second value." - (cond - ((and (null divisor) ; trivial case - (numberp number)) - (values number 0)) - (t ; do the division - (multiple-value-bind - (q r s) - (safe-idiv number divisor) - (cond ((zerop s) - (values 0 0)) - ((plusp s) - (values (+ q 1) (- r divisor))) - (t - (values (- q) (+ number (* q divisor))))))))) + (cond ((and (null divisor) ; trivial case + (numberp number)) + (values number 0)) + (t ; do the division + (multiple-value-bind + (q r s) + (safe-idiv number divisor) + (cond ((zerop s) + (values 0 0)) + ((plusp s) + (values (+ q 1) (- r divisor))) + (t + (values (- q) (+ number (* q divisor))))))))) (defun truncate (number &optional divisor) "Divide DIVIDEND by DIVISOR, rounding toward zero. DIVISOR defaults to 1. The remainder is produced as a second value." - (cond - ((and (null divisor) ; trivial case - (numberp number)) - (values number 0)) - (t ; do the division - (multiple-value-bind - (q r s) - (safe-idiv number divisor) - (cond ((zerop s) - (values 0 0)) - ((plusp s) ;same as floor - (values q r)) - (t ;same as ceiling - (values (- q) (+ number (* q divisor))))))))) + (cond ((and (null divisor) ; trivial case + (numberp number)) + (values number 0)) + (t ; do the division + (multiple-value-bind + (q r s) + (safe-idiv number divisor) + (cond ((zerop s) + (values 0 0)) + ((plusp s) ;same as floor + (values q r)) + (t ;same as ceiling + (values (- q) (+ number (* q divisor))))))))) (defun round (number &optional divisor) "Divide DIVIDEND by DIVISOR, rounding to nearest integer. @@ -1778,18 +1800,25 @@ (setq r (- number (* q divisor))) (values q r)))))) +;;; These two functions access the implementation-dependent representation of +;;; the multiple value returns. + (defun mod (number divisor) "Return remainder of X by Y (rounding quotient toward minus infinity). -That is, the remainder goes with the quotient produced by `floor'." - (multiple-value-bind (q r) (floor number divisor) - r)) +That is, the remainder goes with the quotient produced by `floor'. +Emacs Lisp hint: +If you know that both arguments are positive, use `%' instead for speed." + (floor number divisor) + (cadr *mvalues-values*)) (defun rem (number divisor) "Return remainder of X by Y (rounding quotient toward zero). -That is, the remainder goes with the quotient produced by `truncate'." - (multiple-value-bind (q r) (truncate number divisor) - r)) - +That is, the remainder goes with the quotient produced by `truncate'. +Emacs Lisp hint: +If you know that both arguments are positive, use `%' instead for speed." + (truncate number divisor) + (cadr *mvalues-values*)) + ;;; internal utilities ;;; ;;; safe-idiv performs an integer division with positive numbers only. @@ -1801,16 +1830,14 @@ (defun safe-idiv (a b) "SAFE-IDIV A B => Q R S -Q=|A|/|B|, R is the rest, S is the sign of A/B." - (unless (and (numberp a) (numberp b)) - (error "arguments to `safe-idiv' must be numbers")) - (when (zerop b) - (error "cannot divide %d by zero" a)) - (let* ((absa (abs a)) - (absb (abs b)) - (q (/ absa absb)) - (s (* (signum a) (signum b))) - (r (- a (* (* s q) b)))) +Q=|A|/|B|, S is the sign of A/B, R is the rest A - S*Q*B." + ;; (unless (and (numberp a) (numberp b)) + ;; (error "arguments to `safe-idiv' must be numbers")) + ;; (when (zerop b) + ;; (error "cannot divide %d by zero" a)) + (let* ((q (/ (abs a) (abs b))) + (s (* (signum a) (signum b))) + (r (- a (* s q b)))) (values q r s))) ;;;; end of cl-arith.el @@ -1871,22 +1898,29 @@ (setq head (car place)) (symbolp head) (setq updatefn (get head :setf-update-fn))) - (if (or (and (consp updatefn) (eq (car updatefn) 'lambda)) - (and (symbolp updatefn) - (fboundp updatefn) - (let ((defn (symbol-function updatefn))) - (or (subrp defn) - (and (consp defn) - (eq (car defn) 'lambda)))))) - (cons updatefn (append (cdr place) (list value))) - (multiple-value-bind - (bindings newsyms) - (pair-with-newsyms (append (cdr place) (list value))) - ;; this let gets new symbols to ensure adequate - ;; order of evaluation of the subforms. - (list 'let - bindings - (cons updatefn newsyms))))) + ;; dispatch on the type of update function + (cond ((and (consp updatefn) (eq (car updatefn) 'lambda)) + (cons 'funcall + (cons (list 'function updatefn) + (append (cdr place) (list value))))) + ((and (symbolp updatefn) + (fboundp updatefn) + (let ((defn (symbol-function updatefn))) + (or (subrp defn) + (and (consp defn) + (or (eq (car defn) 'lambda) + (eq (car defn) 'macro)))))) + (cons updatefn (append (cdr place) (list value)))) + (t + (multiple-value-bind + (bindings newsyms) + (pair-with-newsyms + (append (cdr place) (list value))) + ;; this let gets new symbols to ensure adequate + ;; order of evaluation of the subforms. + (list 'let + bindings + (cons updatefn newsyms)))))) (t (error "no `setf' update-function for `%s'" (prin1-to-string place))))))))) @@ -2242,6 +2276,70 @@ (append (cdr newsyms) (list (car newsyms))))) nil)))) +;;; GETF, REMF, and REMPROP +;;; + +(defun getf (place indicator &optional default) + "Return PLACE's PROPNAME property, or DEFAULT if not present." + (while (and place (not (eq (car place) indicator))) + (setq place (cdr (cdr place)))) + (if place + (car (cdr place)) + default)) + +(defmacro getf$setf$method (place indicator default &rest newval) + "SETF method for GETF. Not for public use." + (case (length newval) + (0 (setq newval default default nil)) + (1 (setq newval (car newval))) + (t (error "Wrong number of arguments to (setf (getf ...)) form"))) + (let ((psym (gentemp)) (isym (gentemp)) (vsym (gentemp))) + (list 'let (list (list psym place) + (list isym indicator) + (list vsym newval)) + (list 'while + (list 'and psym + (list 'not + (list 'eq (list 'car psym) isym))) + (list 'setq psym (list 'cdr (list 'cdr psym)))) + (list 'if psym + (list 'setcar (list 'cdr psym) vsym) + (list 'setf place + (list 'nconc place (list 'list isym newval)))) + vsym))) + +(defsetf getf + getf$setf$method) + +(defmacro remf (place indicator) + "Remove from the property list at PLACE its PROPNAME property. +Returns non-nil if and only if the property existed." + (let ((psym (gentemp)) (isym (gentemp))) + (list 'let (list (list psym place) (list isym indicator)) + (list 'cond + (list (list 'eq isym (list 'car psym)) + (list 'setf place (list 'cdr (list 'cdr psym))) + t) + (list t + (list 'setq psym (list 'cdr psym)) + (list 'while + (list 'and (list 'cdr psym) + (list 'not + (list 'eq (list 'car (list 'cdr psym)) + isym))) + (list 'setq psym (list 'cdr (list 'cdr psym)))) + (list 'cond + (list (list 'cdr psym) + (list 'setcdr psym + (list 'cdr + (list 'cdr (list 'cdr psym)))) + t))))))) + +(defun remprop (symbol indicator) + "Remove SYMBOL's PROPNAME property, returning non-nil if it was present." + (remf (symbol-plist symbol) indicator)) + + ;;;; STRUCTS ;;;; This file provides the structures mechanism. See the ;;;; documentation for Common-Lisp's defstruct. Mine doesn't @@ -2402,9 +2500,7 @@ (list 'quote name) 'args)))) (list 'fset (list 'quote copier) - (list 'function - (list 'lambda (list 'struct) - (list 'copy-sequence 'struct)))) + (list 'function 'copy-sequence)) (let ((typetag (gensym))) (list 'fset (list 'quote predicate) (list @@ -2441,7 +2537,7 @@ (list (cons 'vector (mapcar - '(lambda (x) (list 'quote x)) + (function (lambda (x) (list 'quote x))) (cons name slots))))) ;; generate code (cons 'progn @@ -2891,7 +2987,7 @@ ;;; Copiers -(defun copy-list (list) +(defsubst copy-list (list) "Build a copy of LIST" (append list '())) @@ -3037,7 +3133,28 @@ No checking is even attempted. This is just for compatibility with Common-Lisp codes." form) + +;;; Due to Aaron Larson (alarson@src.honeywell.com, 26 Jul 91) +(put 'progv 'common-lisp-indent-hook '(4 4 &body)) +(defmacro progv (vars vals &rest body) + "progv vars vals &body forms +bind vars to vals then execute forms. +If there are more vars than vals, the extra vars are unbound, if +there are more vals than vars, the extra vals are just ignored." + (` (progv$runtime (, vars) (, vals) (function (lambda () (,@ body)))))) + +;;; To do this efficiently, it really needs to be a special form... +(defun progv$runtime (vars vals body) + (eval (let ((vars-n-vals nil) + (unbind-forms nil)) + (do ((r vars (cdr r)) + (l vals (cdr l))) + ((endp r)) + (push (list (car r) (list 'quote (car l))) vars-n-vals) + (if (null l) + (push (` (makunbound '(, (car r)))) unbind-forms))) + (` (let (, vars-n-vals) (,@ unbind-forms) (funcall '(, body))))))) (provide 'cl) -;;; cl.el ends here +;;;; end of cl.el