Mercurial > hg > xemacs-beta
changeset 5177:b785049378e3
merge
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Tue, 23 Feb 2010 07:28:35 -0600 |
parents | 8b2f75cecb89 (current diff) cc74f60c150e (diff) |
children | 97eb4942aec8 |
files | etc/ChangeLog etc/dbxrc.in lisp/ChangeLog lisp/dumped-lisp.el src/ChangeLog src/Makefile.in.in src/lrecord.h tests/ChangeLog tests/automated/test-harness.el |
diffstat | 24 files changed, 1762 insertions(+), 1245 deletions(-) [+] |
line wrap: on
line diff
--- a/etc/ChangeLog Mon Feb 22 06:49:30 2010 -0600 +++ b/etc/ChangeLog Tue Feb 23 07:28:35 2010 -0600 @@ -3,6 +3,11 @@ * dbxrc.in: Rename objects.c -> fontcolor.c. +2010-02-22 Ben Wing <ben@xemacs.org> + + * dbxrc.in: + test-harness.el is in lisp directory now. + 2010-01-28 Jerry James <james@xemacs.org> * tests/external-widget/Makefile: Add copyright and license
--- a/etc/dbxrc.in Mon Feb 22 06:49:30 2010 -0600 +++ b/etc/dbxrc.in Tue Feb 23 07:28:35 2010 -0600 @@ -4,6 +4,7 @@ ## The generated file depends on src/config.h (currently only in one place). ## Copyright (C) 1998 Free Software Foundation, Inc. +## Copyright (C) 2010 Ben Wing. ## This file is part of XEmacs. @@ -194,7 +195,7 @@ end function check-xemacs { - run -batch -l ../tests/automated/test-harness.el -f batch-test-emacs ../tests/automated + run -batch -l test-harness -f batch-test-emacs ../tests/automated } document check-temacs << 'end' @@ -205,7 +206,7 @@ end function check-temacs { - run-temacs -q -batch -l ../tests/automated/test-harness.el -f batch-test-emacs ../tests/automated + run-temacs -q -batch -l test-harness -f batch-test-emacs ../tests/automated } document update-elc << 'end'
--- a/lisp/ChangeLog Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/ChangeLog Tue Feb 23 07:28:35 2010 -0600 @@ -46,6 +46,171 @@ put categories in alphabetical order, move remaning "misc" stuff to bottom. +2010-02-23 Ben Wing <ben@xemacs.org> + + * help.el: fux typo in comment. (oops) + +2010-02-23 Ben Wing <ben@xemacs.org> + + * autoload.el: + * autoload.el (make-autoload): + * cl-macs.el (cl-function-arglist): + * cl-macs.el (cl-transform-lambda): + Don't add argument list with the tag "Common Lisp lambda list:"; + instead add in "standard" form using "arguments:" and omitting the + function name. Add an arg to `cl-function-arglist' to omit the + name and use it in autoload.el instead of just hacking it off. + + * help.el: + * help.el (function-arglist): + * help.el (function-documentation-1): New. + Extract out common code to recognize and/or strip the arglist from + documentation into `function-documentation-1'. Use in + `function-arglist' and `function-documentation'. Modify + `function-arglist' so it looks for the `arguments: ' stuff in all + doc strings, not just subrs/autoloads, so that CL functions get + recognized properly. Change the regexp used to match "arguments: " + specs to allow nested parens inside the arg list (happens when you + have a default value specified in a CL arglist). + +2010-02-22 Ben Wing <ben@xemacs.org> + + * test-harness.el: + * test-harness.el (test-harness-from-buffer): + * test-harness.el (batch-test-emacs): + Move file from tests/automated into lisp/ so it gets + byte-compiled. This significantly reduces the amount of extra + crap in outputted backtraces. Delete hack in batch-test-emacs to + look for test-harness.el in the test directory since it's not there + any more. + + Also, in `Check-Message', incorporate call to `Skip-Test-Unless' + in the macro output rather than its body, to avoid problems byte- + compiling the file -- `Skip-Test-Unless' isn't available in the + environment during byte-compilation so we can't call it then. + +2010-02-22 Ben Wing <ben@xemacs.org> + + * mule/make-coding-system.el: + * mule/make-coding-system.el (fixed-width-generate-helper): + * mule/make-coding-system.el (fixed-width-private-use-start): Removed. + * mule/make-coding-system.el (fixed-width-create-decode-encode-tables): + * coding.el: + * coding.el (decode-char): New. + * coding.el (featurep): + * coding.el (encode-char): New. + * dumped-lisp.el (preloaded-file-list): + Dump make-coding-system. Aidan's hack to avoid dumping this file + never really worked right -- with some configurations (not clear + exactly which ones) `make-coding-system.el' gets dumped anyway due to + calls to `make-coding-system' in unicode.el, with the result that + the documentation of functions in make-coding-system.el gets lost. + + Also needed to remove defvar fixed-width-private-use-start and + incorporate it inline, due to bootstrapping issues -- the call to + decode-char introduced a cross-dependency between unicode.el and + make-coding-system.el. + + +2010-02-22 Ben Wing <ben@xemacs.org> + + * cl-seq.el: + * cl-seq.el (stable-union): New. + * cl-seq.el (stable-intersection): New. + New functions to do stable set operations, i.e. preserve the order + of the elements in the argument lists, and prefer LIST1 over LIST2 + when ordering the combined result. The result looks as much like + LIST1 as possible, followed (in the case of `stable-union') by + any necessary elements from LIST2, in order. This is contrary to + `union' and `intersection', which are not required to be order- + preserving and are not -- they prefer LIST2 and output results in + backwards order. + +2010-02-22 Ben Wing <ben@xemacs.org> + + * cl-seq.el: + * cl-seq.el (reduce): + * cl-seq.el (fill): + * cl-seq.el (replace): + * cl-seq.el (remove*): + * cl-seq.el (remove-if): + * cl-seq.el (remove-if-not): + * cl-seq.el (delete*): + * cl-seq.el (delete-if): + * cl-seq.el (delete-if-not): + * cl-seq.el (remove-duplicates): + * cl-seq.el (delete-duplicates): + * cl-seq.el (substitute): + * cl-seq.el (substitute-if): + * cl-seq.el (substitute-if-not): + * cl-seq.el (nsubstitute): + * cl-seq.el (nsubstitute-if): + * cl-seq.el (nsubstitute-if-not): + * cl-seq.el (find): + * cl-seq.el (find-if): + * cl-seq.el (find-if-not): + * cl-seq.el (position): + * cl-seq.el (position-if): + * cl-seq.el (position-if-not): + * cl-seq.el (count): + * cl-seq.el (count-if): + * cl-seq.el (count-if-not): + * cl-seq.el (mismatch): + * cl-seq.el (search): + * cl-seq.el (sort*): + * cl-seq.el (stable-sort): + * cl-seq.el (merge): + * cl-seq.el (member*): + * cl-seq.el (member-if): + * cl-seq.el (member-if-not): + * cl-seq.el (assoc*): + * cl-seq.el (assoc-if): + * cl-seq.el (assoc-if-not): + * cl-seq.el (rassoc*): + * cl-seq.el (rassoc-if): + * cl-seq.el (rassoc-if-not): + * cl-seq.el (union): + * cl-seq.el (nunion): + * cl-seq.el (intersection): + * cl-seq.el (nintersection): + * cl-seq.el (set-difference): + * cl-seq.el (nset-difference): + * cl-seq.el (set-exclusive-or): + * cl-seq.el (nset-exclusive-or): + * cl-seq.el (subsetp): + * cl-seq.el (subst-if): + * cl-seq.el (subst-if-not): + * cl-seq.el (nsubst): + * cl-seq.el (nsubst-if): + * cl-seq.el (nsubst-if-not): + * cl-seq.el (sublis): + * cl-seq.el (nsublis): + * cl-seq.el (tree-equal): + * cl-seq.el (cl-tree-equal-rec): + * cl.el: + * cl.el (pushnew): + * cl.el (adjoin): + * cl.el (subst): + Document the keywords to the various sequence/list functions. + +2010-02-21 Ben Wing <ben@xemacs.org> + + * diagnose.el: + * diagnose.el (show-object-memory-usage-stats): + Fix errors preventing this from working properly, account for + words like "entry" pluralized to "entries". + +2010-02-22 Aidan Kehoe <kehoea@parhasard.net> + + * cl-extra.el (constantly): + Add this function, from ANSI Common Lisp, using the SBCL extension + that extra arguments to it are passed back as multiple values in + the constructed function. + * cl-macs.el (constantly): + In the compiler macro for #'constantly, construct a + compiled-function object almost every time, at compile time when + all arguments are constant, and at runtime when they vary. + 2010-02-08 Ben Wing <ben@xemacs.org> * help.el (describe-function-1):
--- a/lisp/autoload.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/autoload.el Tue Feb 23 07:28:35 2010 -0600 @@ -2,7 +2,7 @@ ;; Copyright (C) 1991-1994, 1997, 2003 Free Software Foundation, Inc. ;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp. -;; Copyright (C) 1996, 2000, 2002, 2003, 2004 Ben Wing. +;; Copyright (C) 1996, 2000, 2002, 2003, 2004, 2010 Ben Wing. ;; Original Author: Roland McGrath <roland@gnu.ai.mit.edu> ;; Heavily Modified: XEmacs Maintainers @@ -290,10 +290,8 @@ (placeholder (eval-when-compile (gensym)))) (setq doc (concat (or doc "") "\n\narguments: " - (replace-in-string - (cl-function-arglist placeholder arglist) - (format "^(%s ?" placeholder) - "(") "\n")))) + (cl-function-arglist placeholder arglist t) + "\n")))) ;; `define-generic-mode' quotes the name, so take care of that (list 'autoload (if (listp name) name (list 'quote name)) file doc (or (and (memq car '(define-skeleton define-derived-mode
--- a/lisp/cl-extra.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/cl-extra.el Tue Feb 23 07:28:35 2010 -0600 @@ -612,6 +612,17 @@ ((memq (car plst) indicator-list) (return (values (car plst) (cadr plst) plst)))))) +;; See our compiler macro in cl-macs.el, we will only pass back the +;; actual lambda list in interpreted code or if we've been funcalled +;; (from #'apply or #'mapcar or whatever). +(defun constantly (value &rest more-values) + "Construct a function always returning VALUE, and possibly MORE-VALUES. + +The constructed function accepts any number of arguments, and ignores them. + +Members of MORE-VALUES, if provided, will be passed as multiple values; see +`multiple-value-bind' and `multiple-value-setq'." + `(lambda (&rest ignore) (values-list ',(cons value more-values)))) ;;; Hash tables.
--- a/lisp/cl-macs.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/cl-macs.el Tue Feb 23 07:28:35 2010 -0600 @@ -299,29 +299,33 @@ ;; npak@ispras.ru ;;;###autoload -(defun cl-function-arglist (name arglist) +(defun cl-function-arglist (name arglist &optional omit-name) "Returns string with printed representation of arguments list. Supports Common Lisp lambda lists." + ;; #### I would just change this so that OMIT-NAME is always true and + ;; eliminate the argument, but this function is autoloaded, which means + ;; someone might be using it somewhere. (if (not (or (listp arglist) (symbolp arglist))) "Not available" (check-argument-type #'true-list-p arglist) (let ((print-gensym nil)) (condition-case nil (prin1-to-string - (cons (if (eq name 'cl-none) 'lambda name) - (cond ((null arglist) nil) - ((listp arglist) (cl-upcase-arg arglist)) - ((symbolp arglist) - (cl-upcase-arg (list '&rest arglist))) - (t (wrong-type-argument 'listp arglist))))) - (t "Not available"))))) + (let ((args (cond ((null arglist) nil) + ((listp arglist) (cl-upcase-arg arglist)) + ((symbolp arglist) + (cl-upcase-arg (list '&rest arglist))) + (t (wrong-type-argument 'listp arglist))))) + (if omit-name args + (cons (if (eq name 'cl-none) 'lambda name) args)))) + (t "Not available"))))) (defun cl-transform-lambda (form bind-block) (let* ((args (car form)) (body (cdr form)) (bind-defs nil) (bind-enquote nil) (bind-inits nil) (bind-lets nil) (bind-forms nil) (header nil) (simple-args nil) - (complex-arglist (cl-function-arglist bind-block args)) + (complex-arglist (cl-function-arglist bind-block args t)) (doc "")) (while (or (stringp (car body)) (eq (car-safe (car body)) 'interactive)) (push (pop body) header)) @@ -348,12 +352,12 @@ ;; Add CL lambda list to documentation, if the CL lambda list differs ;; from the non-CL lambda list. npak@ispras.ru (unless (equal complex-arglist - (cl-function-arglist bind-block simple-args)) + (cl-function-arglist bind-block simple-args t)) (and (stringp (car header)) (setq doc (pop header))) - (push (concat doc - "\n\nCommon Lisp lambda list:\n" - " " complex-arglist "\n\n") - header)) + ;; Stick the arguments onto the end of the doc string in a way that + ;; will be recognized specially by `function-arglist'. + (push (concat doc "\n\narguments: " complex-arglist "\n") + header)) (if (null args) (list* nil simple-args (nconc header body)) (if (memq '&optional simple-args) (push '&optional args)) @@ -3551,6 +3555,41 @@ (define-compiler-macro notevery (&whole form &rest cl-rest) (cons 'not (cons 'every (cdr cl-rest)))) +(define-compiler-macro constantly (&whole form value &rest more-values) + (cond + ((< (length form) 2) + ;; Error at runtime: + form) + ((cl-const-exprs-p (cdr form)) + `#'(lambda (&rest ignore) (values ,@(cdr form)))) + (t + (let* ((num-values (length (cdr form))) + (placeholders-counts (make-vector num-values -1)) + (placeholders (loop + for i from 0 below num-values + collect (make-symbol (format "%d" i)))) + (compiled + (byte-compile-sexp + `#'(lambda (&rest ignore) + ;; Compiles to a references into the compiled function + ;; constants vector: + (values ,@(mapcar #'quote-maybe placeholders))))) + position) + `(make-byte-code '(&rest ignore) + ,(compiled-function-instructions compiled) + (vector ,@(loop + for constant across (compiled-function-constants compiled) + collect (if (setq position + (position constant placeholders)) + (prog2 + (incf (aref placeholders-counts position)) + (nth position (cdr form))) + (quote-maybe constant)) + finally + (assert (every #'zerop placeholders-counts) + t "Placeholders should each have been used once"))) + ,(compiled-function-stack-depth compiled)))))) + (mapc #'(lambda (y) (put (car y) 'side-effect-free t)
--- a/lisp/cl-seq.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/cl-seq.el Tue Feb 23 07:28:35 2010 -0600 @@ -1,6 +1,7 @@ ;;; cl-seq.el --- Common Lisp extensions for XEmacs Lisp (part three) ;; Copyright (C) 1993 Free Software Foundation, Inc. +;; Copyright (C) 2010 Ben Wing. ;; Author: Dave Gillespie <daveg@synaptics.com> ;; Maintainer: XEmacs Development Team @@ -147,8 +148,18 @@ (defun reduce (cl-func cl-seq &rest cl-keys) - "Reduce two-argument FUNCTION across SEQUENCE. -Keywords supported: :start :end :from-end :initial-value :key" + "Combine the elements of sequence using FUNCTION, a binary operation. +For example, `(reduce #'+ SEQUENCE)' returns the sum of all elements in +SEQUENCE, and `(reduce #'union SEQUENCE)' returns the union of all elements +in SEQUENCE. +Keywords supported: :start :end :from-end :initial-value :key +See `remove*' for the meaning of :start, :end, :from-end and :key. +:initial-value specifies an element (typically an identity element, such as 0) +that is conceptually prepended to the sequence (or appended, when :from-end +is given). +If the sequence has one element, that element is returned directly. +If the sequence has no elements, :initial-value is returned if given; +otherwise, FUNCTION is called with no arguments, and its result returned." (cl-parsing-keywords (:from-end (:start 0) :end :initial-value :key) () (or (listp cl-seq) (setq cl-seq (append cl-seq nil))) (setq cl-seq (subseq cl-seq cl-start cl-end)) @@ -167,7 +178,9 @@ (defun fill (seq item &rest cl-keys) "Fill the elements of SEQ with ITEM. -Keywords supported: :start :end" +Keywords supported: :start :end +:start and :end specify a subsequence of SEQ; see `remove*' for more +information." (cl-parsing-keywords ((:start 0) :end) () (if (listp seq) (let ((p (nthcdr cl-start seq)) @@ -186,7 +199,9 @@ (defun replace (cl-seq1 cl-seq2 &rest cl-keys) "Replace the elements of SEQ1 with the elements of SEQ2. SEQ1 is destructively modified, then returned. -Keywords supported: :start1 :end1 :start2 :end2" +Keywords supported: :start1 :end1 :start2 :end2 +:start1 and :end1 specify a subsequence of SEQ1, and :start2 and :end2 a +subsequence of SEQ2; see `search' for more information." (cl-parsing-keywords ((:start1 0) :end1 (:start2 0) :end2) () (if (and (eq cl-seq1 cl-seq2) (<= cl-start2 cl-start1)) (or (= cl-start1 cl-start2) @@ -228,7 +243,19 @@ "Remove all occurrences of ITEM in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. -Keywords supported: :test :test-not :key :count :start :end :from-end" +Keywords supported: :test :test-not :key :count :start :end :from-end +The keywords :test and :test-not specify two-argument test and negated-test +predicates, respectively; :test defaults to `eql'. :key specifies a +one-argument function that transforms elements of SEQ into \"comparison keys\" +before the test predicate is applied. See `member*' for more information +on these keywords. +:start and :end, if given, specify indices of a subsequence of SEQ to +be processed. Indices are 0-based and processing involves the subsequence +starting at the index given by :start and ending just before the index +given by :end. +:count, if given, limits the number of items removed to the number specified. +:from-end, if given, causes processing to proceed starting from the end +instead of the beginning; in this case, this matters only if :count is given." (cl-parsing-keywords (:test :test-not :key :if :if-not :count :from-end (:start 0) :end) () (if (<= (or cl-count (setq cl-count 8000000)) 0) @@ -272,20 +299,23 @@ "Remove all items satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. -Keywords supported: :key :count :start :end :from-end" +Keywords supported: :key :count :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'remove* nil cl-list :if cl-pred cl-keys)) (defun remove-if-not (cl-pred cl-list &rest cl-keys) "Remove all items not satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. -Keywords supported: :key :count :start :end :from-end" +Keywords supported: :key :count :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'remove* nil cl-list :if-not cl-pred cl-keys)) (defun delete* (cl-item cl-seq &rest cl-keys) "Remove all occurrences of ITEM in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. -Keywords supported: :test :test-not :key :count :start :end :from-end" +Keywords supported: :test :test-not :key :count :start :end :from-end +See `remove*' for the meaning of the keywords." (cl-parsing-keywords (:test :test-not :key :if :if-not :count :from-end (:start 0) :end) () (if (<= (or cl-count (setq cl-count 8000000)) 0) @@ -327,16 +357,18 @@ (defun delete-if (cl-pred cl-list &rest cl-keys) "Remove all items satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. -Keywords supported: :key :count :start :end :from-end" +Keywords supported: :key :count :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'delete* nil cl-list :if cl-pred cl-keys)) (defun delete-if-not (cl-pred cl-list &rest cl-keys) "Remove all items not satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. -Keywords supported: :key :count :start :end :from-end" +Keywords supported: :key :count :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'delete* nil cl-list :if-not cl-pred cl-keys)) -;; XEmacs change: this is in subr.el in Emacs +;; XEmacs change: this is in subr.el in GNU Emacs (defun remove (cl-item cl-seq) "Remove all occurrences of ITEM in SEQ, testing with `equal' This is a non-destructive function; it makes a copy of SEQ if necessary @@ -344,7 +376,7 @@ Also see: `remove*', `delete', `delete*'" (remove* cl-item cl-seq ':test 'equal)) -;; XEmacs change: this is in subr.el in Emacs +;; XEmacs change: this is in subr.el in GNU Emacs (defun remq (cl-elt cl-list) "Remove all occurrences of ELT in LIST, comparing with `eq'. This is a non-destructive function; it makes a copy of LIST to avoid @@ -356,12 +388,14 @@ (defun remove-duplicates (cl-seq &rest cl-keys) "Return a copy of SEQ with all duplicate elements removed. -Keywords supported: :test :test-not :key :start :end :from-end" +Keywords supported: :test :test-not :key :start :end :from-end +See `remove*' for the meaning of the keywords." (cl-delete-duplicates cl-seq cl-keys t)) (defun delete-duplicates (cl-seq &rest cl-keys) "Remove all duplicate elements from SEQ (destructively). -Keywords supported: :test :test-not :key :start :end :from-end" +Keywords supported: :test :test-not :key :start :end :from-end +See `remove*' for the meaning of the keywords." (cl-delete-duplicates cl-seq cl-keys nil)) (defun cl-delete-duplicates (cl-seq cl-keys cl-copy) @@ -408,7 +442,8 @@ "Substitute NEW for OLD in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. -Keywords supported: :test :test-not :key :count :start :end :from-end" +Keywords supported: :test :test-not :key :count :start :end :from-end +See `remove*' for the meaning of the keywords." (cl-parsing-keywords (:test :test-not :key :if :if-not :count (:start 0) :end :from-end) () (if (or (eq cl-old cl-new) @@ -428,20 +463,21 @@ "Substitute NEW for all items satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. -Keywords supported: :key :count :start :end :from-end" +See `remove*' for the meaning of the keywords." (apply 'substitute cl-new nil cl-list :if cl-pred cl-keys)) (defun substitute-if-not (cl-new cl-pred cl-list &rest cl-keys) "Substitute NEW for all items not satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. -Keywords supported: :key :count :start :end :from-end" +See `remove*' for the meaning of the keywords." (apply 'substitute cl-new nil cl-list :if-not cl-pred cl-keys)) (defun nsubstitute (cl-new cl-old cl-seq &rest cl-keys) "Substitute NEW for OLD in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. -Keywords supported: :test :test-not :key :count :start :end :from-end" +Keywords supported: :test :test-not :key :count :start :end :from-end +See `remove*' for the meaning of the keywords." (cl-parsing-keywords (:test :test-not :key :if :if-not :count (:start 0) :end :from-end) () (or (eq cl-old cl-new) (<= (or cl-count (setq cl-count 8000000)) 0) @@ -473,38 +509,44 @@ (defun nsubstitute-if (cl-new cl-pred cl-list &rest cl-keys) "Substitute NEW for all items satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. -Keywords supported: :key :count :start :end :from-end" +Keywords supported: :key :count :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'nsubstitute cl-new nil cl-list :if cl-pred cl-keys)) (defun nsubstitute-if-not (cl-new cl-pred cl-list &rest cl-keys) "Substitute NEW for all items not satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. -Keywords supported: :key :count :start :end :from-end" +Keywords supported: :key :count :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'nsubstitute cl-new nil cl-list :if-not cl-pred cl-keys)) (defun find (cl-item cl-seq &rest cl-keys) "Find the first occurrence of ITEM in LIST. Return the matching ITEM, or nil if not found. -Keywords supported: :test :test-not :key :start :end :from-end" +Keywords supported: :test :test-not :key :start :end :from-end +See `remove*' for the meaning of the keywords." (let ((cl-pos (apply 'position cl-item cl-seq cl-keys))) (and cl-pos (elt cl-seq cl-pos)))) (defun find-if (cl-pred cl-list &rest cl-keys) "Find the first item satisfying PREDICATE in LIST. Return the matching ITEM, or nil if not found. -Keywords supported: :key :start :end :from-end" +Keywords supported: :key :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'find nil cl-list :if cl-pred cl-keys)) (defun find-if-not (cl-pred cl-list &rest cl-keys) "Find the first item not satisfying PREDICATE in LIST. Return the matching ITEM, or nil if not found. -Keywords supported: :key :start :end :from-end" +Keywords supported: :key :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'find nil cl-list :if-not cl-pred cl-keys)) (defun position (cl-item cl-seq &rest cl-keys) "Find the first occurrence of ITEM in LIST. Return the index of the matching item, or nil if not found. -Keywords supported: :test :test-not :key :start :end :from-end" +Keywords supported: :test :test-not :key :start :end :from-end +See `remove*' for the meaning of the keywords." (cl-parsing-keywords (:test :test-not :key :if :if-not (:start 0) :end :from-end) () (cl-position cl-item cl-seq cl-start cl-end cl-from-end))) @@ -533,18 +575,21 @@ (defun position-if (cl-pred cl-list &rest cl-keys) "Find the first item satisfying PREDICATE in LIST. Return the index of the matching item, or nil if not found. -Keywords supported: :key :start :end :from-end" +Keywords supported: :key :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'position nil cl-list :if cl-pred cl-keys)) (defun position-if-not (cl-pred cl-list &rest cl-keys) "Find the first item not satisfying PREDICATE in LIST. Return the index of the matching item, or nil if not found. -Keywords supported: :key :start :end :from-end" +Keywords supported: :key :start :end :from-end +See `remove*' for the meaning of the keywords." (apply 'position nil cl-list :if-not cl-pred cl-keys)) (defun count (cl-item cl-seq &rest cl-keys) "Count the number of occurrences of ITEM in LIST. -Keywords supported: :test :test-not :key :start :end" +Keywords supported: :test :test-not :key :start :end +See `remove*' for the meaning of the keywords." (cl-parsing-keywords (:test :test-not :key :if :if-not (:start 0) :end) () (let ((cl-count 0) cl-x) (or cl-end (setq cl-end (length cl-seq))) @@ -557,19 +602,22 @@ (defun count-if (cl-pred cl-list &rest cl-keys) "Count the number of items satisfying PREDICATE in LIST. -Keywords supported: :key :start :end" +Keywords supported: :key :start :end +See `remove*' for the meaning of the keywords." (apply 'count nil cl-list :if cl-pred cl-keys)) (defun count-if-not (cl-pred cl-list &rest cl-keys) "Count the number of items not satisfying PREDICATE in LIST. -Keywords supported: :key :start :end" +Keywords supported: :key :start :end +See `remove*' for the meaning of the keywords." (apply 'count nil cl-list :if-not cl-pred cl-keys)) (defun mismatch (cl-seq1 cl-seq2 &rest cl-keys) "Compare SEQ1 with SEQ2, return index of first mismatching element. Return nil if the sequences match. If one sequence is a prefix of the other, the return value indicates the end of the shorter sequence. -Keywords supported: :test :test-not :key :start1 :end1 :start2 :end2 :from-end" +Keywords supported: :test :test-not :key :start1 :end1 :start2 :end2 :from-end +See `search' for the meaning of the keywords." (cl-parsing-keywords (:test :test-not :key :from-end (:start1 0) :end1 (:start2 0) :end2) () (or cl-end1 (setq cl-end1 (length cl-seq1))) @@ -598,7 +646,10 @@ "Search for SEQ1 as a subsequence of SEQ2. Return the index of the leftmost element of the first match found; return nil if there are no matches. -Keywords supported: :test :test-not :key :start1 :end1 :start2 :end2 :from-end" +Keywords supported: :test :test-not :key :start1 :end1 :start2 :end2 :from-end +See `remove*' for the meaning of the keywords. In this case, :start1 and :end1 +specify a subsequence of SEQ1, and :start2 and :end2 specify a subsequence +of SEQ2." (cl-parsing-keywords (:test :test-not :key :from-end (:start1 0) :end1 (:start2 0) :end2) () (or cl-end1 (setq cl-end1 (length cl-seq1))) @@ -622,7 +673,10 @@ (defun sort* (cl-seq cl-pred &rest cl-keys) "Sort the argument SEQUENCE according to PREDICATE. This is a destructive function; it reuses the storage of SEQUENCE if possible. -Keywords supported: :key" +Keywords supported: :key +:key specifies a one-argument function that transforms elements of SEQUENCE +into \"comparison keys\" before the test predicate is applied. See +`member*' for more information." (if (nlistp cl-seq) (replace cl-seq (apply 'sort* (append cl-seq nil) cl-pred cl-keys)) (cl-parsing-keywords (:key) () @@ -635,14 +689,20 @@ (defun stable-sort (cl-seq cl-pred &rest cl-keys) "Sort the argument SEQUENCE stably according to PREDICATE. This is a destructive function; it reuses the storage of SEQUENCE if possible. -Keywords supported: :key" +Keywords supported: :key +:key specifies a one-argument function that transforms elements of SEQUENCE +into \"comparison keys\" before the test predicate is applied. See +`member*' for more information." (apply 'sort* cl-seq cl-pred cl-keys)) (defun merge (cl-type cl-seq1 cl-seq2 cl-pred &rest cl-keys) "Destructively merge the two sequences to produce a new sequence. TYPE is the sequence type to return, SEQ1 and SEQ2 are the two argument sequences, and PRED is a `less-than' predicate on the elements. -Keywords supported: :key" +Keywords supported: :key +:key specifies a one-argument function that transforms elements of SEQ1 and +SEQ2 into \"comparison keys\" before the test predicate is applied. See +`member*' for more information." (or (listp cl-seq1) (setq cl-seq1 (append cl-seq1 nil))) (or (listp cl-seq2) (setq cl-seq2 (append cl-seq2 nil))) (cl-parsing-keywords (:key) () @@ -658,7 +718,18 @@ (defun member* (cl-item cl-list &rest cl-keys) "Find the first occurrence of ITEM in LIST. Return the sublist of LIST whose car is ITEM. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +The keyword :test specifies a two-argument function that is used to + compare ITEM with elements in LIST; if omitted, it defaults to `eql'. +The keyword :test-not is similar, but specifies a negated predicate. That + is, ITEM is considered equal to an element in LIST if the given predicate + returns nil. +:key specifies a one-argument function that transforms elements of LIST into +\"comparison keys\" before the test predicate is applied. For example, +if :key is #'car, then ITEM is compared with the car of elements from LIST1. +The :key function, however, is not applied to ITEM, and does not affect the +elements in the returned list, which are taken directly from the elements in +LIST." (if cl-keys (cl-parsing-keywords (:test :test-not :key :if :if-not) () (while (and cl-list (not (cl-check-test cl-item (car cl-list)))) @@ -671,13 +742,15 @@ (defun member-if (cl-pred cl-list &rest cl-keys) "Find the first item satisfying PREDICATE in LIST. Return the sublist of LIST whose car matches. -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'member* nil cl-list :if cl-pred cl-keys)) (defun member-if-not (cl-pred cl-list &rest cl-keys) "Find the first item not satisfying PREDICATE in LIST. Return the sublist of LIST whose car matches. -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'member* nil cl-list :if-not cl-pred cl-keys)) (defun cl-adjoin (cl-item cl-list &rest cl-keys) @@ -689,7 +762,8 @@ ;;; See compiler macro in cl-macs.el (defun assoc* (cl-item cl-alist &rest cl-keys) "Find the first item whose car matches ITEM in LIST. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `member*' for the meaning of :test, :test-not and :key." (if cl-keys (cl-parsing-keywords (:test :test-not :key :if :if-not) () (while (and cl-alist @@ -703,17 +777,20 @@ (defun assoc-if (cl-pred cl-list &rest cl-keys) "Find the first item whose car satisfies PREDICATE in LIST. -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'assoc* nil cl-list :if cl-pred cl-keys)) (defun assoc-if-not (cl-pred cl-list &rest cl-keys) "Find the first item whose car does not satisfy PREDICATE in LIST. -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'assoc* nil cl-list :if-not cl-pred cl-keys)) (defun rassoc* (cl-item cl-alist &rest cl-keys) "Find the first item whose cdr matches ITEM in LIST. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `member*' for the meaning of :test, :test-not and :key." (if (or cl-keys (and (numberp cl-item) (not (fixnump cl-item)))) (cl-parsing-keywords (:test :test-not :key :if :if-not) () (while (and cl-alist @@ -725,12 +802,14 @@ (defun rassoc-if (cl-pred cl-list &rest cl-keys) "Find the first item whose cdr satisfies PREDICATE in LIST. -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'rassoc* nil cl-list :if cl-pred cl-keys)) (defun rassoc-if-not (cl-pred cl-list &rest cl-keys) "Find the first item whose cdr does not satisfy PREDICATE in LIST. -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'rassoc* nil cl-list :if-not cl-pred cl-keys)) (defun union (cl-list1 cl-list2 &rest cl-keys) @@ -738,7 +817,16 @@ The result list contains all items that appear in either LIST1 or LIST2. This is a non-destructive function; it makes a copy of the data if necessary to avoid corrupting the original LIST1 and LIST2. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +The keywords :test and :test-not specify two-argument test and negated-test +predicates, respectively; :test defaults to `eql'. see `member*' for more +information. +:key specifies a one-argument function that transforms elements of LIST1 +and LIST2 into \"comparison keys\" before the test predicate is applied. +For example, if :key is #'car, then the car of elements from LIST1 is +compared with the car of elements from LIST2. The :key function, however, +does not affect the elements in the returned list, which are taken directly +from the elements in LIST1 and LIST2." (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) ((equal cl-list1 cl-list2) cl-list1) (t @@ -757,16 +845,52 @@ The result list contains all items that appear in either LIST1 or LIST2. This is a destructive function; it reuses the storage of LIST1 and LIST2 whenever possible. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key." (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) (t (apply 'union cl-list1 cl-list2 cl-keys)))) +;; XEmacs addition: NOT IN COMMON LISP. +(defun stable-union (cl-list1 cl-list2 &rest cl-keys) + "Stably combine LIST1 and LIST2 using a set-union operation. +The result list contains all items that appear in either LIST1 or LIST2. +The result is \"stable\" in that it preserves the ordering of elements in +LIST1 and LIST2. The result specifically consists of the elements in LIST1 +in order, followed by any elements in LIST2 that are not also in LIST1, in +the order given in LIST2. +This is a non-destructive function; it makes a copy of the data if necessary +to avoid corrupting the original LIST1 and LIST2. +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key. + +NOTE: This is *NOT* a function defined by Common Lisp, but an XEmacs +extension." + ;; The standard `union' doesn't produce a "stable" union -- + ;; it iterates over the second list instead of the first one, and returns + ;; the values in backwards order. According to the CLTL2 documentation, + ;; `union' is not required to preserve the ordering of elements in + ;; any fashion, so we add a new function rather than changing the + ;; semantics of `union'. + (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) + ((equal cl-list1 cl-list2) cl-list1) + (t + (append + cl-list1 + (cl-parsing-keywords (:key) (:test :test-not) + (loop for cl-l in cl-list2 + if (not (if (or cl-keys (numberp cl-l)) + (apply 'member* (cl-check-key cl-l) + cl-list1 cl-keys) + (memq cl-l cl-list1))) + collect cl-l)))))) + (defun intersection (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-intersection operation. The result list contains all items that appear in both LIST1 and LIST2. This is a non-destructive function; it makes a copy of the data if necessary to avoid corrupting the original LIST1 and LIST2. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key." (and cl-list1 cl-list2 (if (equal cl-list1 cl-list2) cl-list1 (cl-parsing-keywords (:key) (:test :test-not) @@ -787,15 +911,46 @@ The result list contains all items that appear in both LIST1 and LIST2. This is a destructive function; it reuses the storage of LIST1 and LIST2 whenever possible. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key." (and cl-list1 cl-list2 (apply 'intersection cl-list1 cl-list2 cl-keys))) +;; XEmacs addition: NOT IN COMMON LISP. +(defun stable-intersection (cl-list1 cl-list2 &rest cl-keys) + "Stably combine LIST1 and LIST2 using a set-intersection operation. +The result list contains all items that appear in both LIST1 and LIST2. +The result is \"stable\" in that it preserves the ordering of elements in +LIST1 that are also in LIST2. +This is a non-destructive function; it makes a copy of the data if necessary +to avoid corrupting the original LIST1 and LIST2. +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key. + +NOTE: This is *NOT* a function defined by Common Lisp, but an XEmacs +extension." + ;; The standard `intersection' doesn't produce a "stable" intersection -- + ;; it iterates over the second list instead of the first one, and returns + ;; the values in backwards order. According to the CLTL2 documentation, + ;; `intersection' is not required to preserve the ordering of elements in + ;; any fashion, so we add a new function rather than changing the + ;; semantics of `intersection'. + (and cl-list1 cl-list2 + (if (equal cl-list1 cl-list2) cl-list1 + (cl-parsing-keywords (:key) (:test :test-not) + (loop for cl-l in cl-list1 + if (if (or cl-keys (numberp cl-l)) + (apply 'member* (cl-check-key cl-l) + cl-list2 cl-keys) + (memq cl-l cl-list2)) + collect cl-l))))) + (defun set-difference (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-difference operation. The result list contains all items that appear in LIST1 but not LIST2. This is a non-destructive function; it makes a copy of the data if necessary to avoid corrupting the original LIST1 and LIST2. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key." (if (or (null cl-list1) (null cl-list2)) cl-list1 (cl-parsing-keywords (:key) (:test :test-not) (let ((cl-res nil)) @@ -813,7 +968,8 @@ The result list contains all items that appear in LIST1 but not LIST2. This is a destructive function; it reuses the storage of LIST1 and LIST2 whenever possible. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key." (if (or (null cl-list1) (null cl-list2)) cl-list1 (apply 'set-difference cl-list1 cl-list2 cl-keys))) @@ -822,7 +978,8 @@ The result list contains all items that appear in exactly one of LIST1, LIST2. This is a non-destructive function; it makes a copy of the data if necessary to avoid corrupting the original LIST1 and LIST2. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key." (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) ((equal cl-list1 cl-list2) nil) (t (append (apply 'set-difference cl-list1 cl-list2 cl-keys) @@ -833,7 +990,8 @@ The result list contains all items that appear in exactly one of LIST1, LIST2. This is a destructive function; it reuses the storage of LIST1 and LIST2 whenever possible. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key." (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) ((equal cl-list1 cl-list2) nil) (t (nconc (apply 'nset-difference cl-list1 cl-list2 cl-keys) @@ -842,7 +1000,8 @@ (defun subsetp (cl-list1 cl-list2 &rest cl-keys) "True if LIST1 is a subset of LIST2. I.e., if every element of LIST1 also appears in LIST2. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key." (cond ((null cl-list1) t) ((null cl-list2) nil) ((equal cl-list1 cl-list2) t) (t (cl-parsing-keywords (:key) (:test :test-not) @@ -855,38 +1014,44 @@ (defun subst-if (cl-new cl-pred cl-tree &rest cl-keys) "Substitute NEW for elements matching PREDICATE in TREE (non-destructively). Return a copy of TREE with all matching elements replaced by NEW. -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'sublis (list (cons nil cl-new)) cl-tree :if cl-pred cl-keys)) (defun subst-if-not (cl-new cl-pred cl-tree &rest cl-keys) "Substitute NEW for elts not matching PREDICATE in TREE (non-destructively). Return a copy of TREE with all non-matching elements replaced by NEW. -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'sublis (list (cons nil cl-new)) cl-tree :if-not cl-pred cl-keys)) (defun nsubst (cl-new cl-old cl-tree &rest cl-keys) "Substitute NEW for OLD everywhere in TREE (destructively). Any element of TREE which is `eql' to OLD is changed to NEW (via a call to `setcar'). -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `member*' for the meaning of :test, :test-not and :key." (apply 'nsublis (list (cons cl-old cl-new)) cl-tree cl-keys)) (defun nsubst-if (cl-new cl-pred cl-tree &rest cl-keys) "Substitute NEW for elements matching PREDICATE in TREE (destructively). Any element of TREE which matches is changed to NEW (via a call to `setcar'). -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'nsublis (list (cons nil cl-new)) cl-tree :if cl-pred cl-keys)) (defun nsubst-if-not (cl-new cl-pred cl-tree &rest cl-keys) "Substitute NEW for elements not matching PREDICATE in TREE (destructively). Any element of TREE which matches is changed to NEW (via a call to `setcar'). -Keywords supported: :key" +Keywords supported: :key +See `member*' for the meaning of :key." (apply 'nsublis (list (cons nil cl-new)) cl-tree :if-not cl-pred cl-keys)) (defun sublis (cl-alist cl-tree &rest cl-keys) "Perform substitutions indicated by ALIST in TREE (non-destructively). Return a copy of TREE with all matching elements replaced. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `member*' for the meaning of :test, :test-not and :key." (cl-parsing-keywords (:test :test-not :key :if :if-not) () (cl-sublis-rec cl-tree))) @@ -907,7 +1072,8 @@ (defun nsublis (cl-alist cl-tree &rest cl-keys) "Perform substitutions indicated by ALIST in TREE (destructively). Any matching element of TREE is changed via a call to `setcar'. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `member*' for the meaning of :test, :test-not and :key." (cl-parsing-keywords (:test :test-not :key :if :if-not) () (let ((cl-hold (list cl-tree))) (cl-nsublis-rec cl-hold) @@ -930,7 +1096,8 @@ (defun tree-equal (cl-x cl-y &rest cl-keys) "Return t if trees X and Y have `eql' leaves. Atoms are compared by `eql'; cons cells are compared recursively. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `union' for the meaning of :test, :test-not and :key." (cl-parsing-keywords (:test :test-not :key) () (cl-tree-equal-rec cl-x cl-y)))
--- a/lisp/cl.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/cl.el Tue Feb 23 07:28:35 2010 -0600 @@ -1,6 +1,7 @@ ;;; cl.el --- Common Lisp extensions for XEmacs Lisp ;; Copyright (C) 1993, 1997 Free Software Foundation, Inc. +;; Copyright (C) 2010 Ben Wing. ;; Author: Dave Gillespie <daveg@synaptics.com> ;; Maintainer: XEmacs Development Team @@ -179,7 +180,8 @@ "Add NEWELT at the beginning of LISTNAME, unless it's already in LISTNAME. Like (push NEWELT LISTNAME), except that the list is unmodified if NEWELT is `eql' to an element already on the list. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `member*' for the meaning of :test, :test-not and :key." (if (symbolp listname) (list 'setq listname (list* 'adjoin newelt listname keys)) (list* 'callf2 'adjoin newelt listname keys))) @@ -583,7 +585,8 @@ (defun adjoin (cl-item cl-list &rest cl-keys) ; See compiler macro in cl-macs "Return ITEM consed onto the front of LIST only if it's not already there. Otherwise, return LIST unmodified. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `member*' for the meaning of :test, :test-not and :key." (cond ((or (equal cl-keys '(:test eq)) (and (null cl-keys) (not (numberp cl-item)))) (if (memq cl-item cl-list) cl-list (cons cl-item cl-list))) @@ -594,7 +597,8 @@ (defun subst (cl-new cl-old cl-tree &rest cl-keys) "Substitute NEW for OLD everywhere in TREE (non-destructively). Return a copy of TREE with all elements `eql' to OLD replaced by NEW. -Keywords supported: :test :test-not :key" +Keywords supported: :test :test-not :key +See `member*' for the meaning of :test, :test-not and :key." (if (or cl-keys (and (numberp cl-old) (not (fixnump cl-old)))) (apply 'sublis (list (cons cl-old cl-new)) cl-tree cl-keys) (cl-do-subst cl-new cl-old cl-tree)))
--- a/lisp/coding.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/coding.el Tue Feb 23 07:28:35 2010 -0600 @@ -5,7 +5,7 @@ ;; Copyright (C) 1995 Amdahl Corporation. ;; Copyright (C) 1995 Sun Microsystems. ;; Copyright (C) 1997 MORIOKA Tomohiko -;; Copyright (C) 2000, 2001, 2002 Ben Wing. +;; Copyright (C) 2000, 2001, 2002, 2010 Ben Wing. ;; This file is part of XEmacs. @@ -464,27 +464,25 @@ (and (query-coding-string char coding-system) (encode-coding-string char coding-system))) -(if (featurep 'mule) - (progn - ;; Under Mule, we do much of the complicated coding system creation in - ;; Lisp and especially at compile time. We need some function - ;; definition for this function to be created in this file, but we can - ;; leave assigning the docstring to the autoload cookie - ;; handling later. Thankfully; that docstring is big. - (autoload 'make-coding-system "mule/make-coding-system") +(defun decode-char (quote-ucs code &optional restriction) + "FSF compatibility--return Mule character with Unicode codepoint CODE. +The second argument must be 'ucs, the third argument is ignored. " + ;; We're prepared to accept invalid Unicode in unicode-to-char, but not in + ;; this function, which is the API that should actually be used, since + ;; it's available in GNU and in Mule-UCS. + (check-argument-range code #x0 #x10FFFF) + (assert (eq quote-ucs 'ucs) t + "Sorry, decode-char doesn't yet support anything but the UCS. ") + (unicode-to-char code)) - ;; (During byte-compile before dumping, make-coding-system may already - ;; have been loaded, make sure not to overwrite the correct compiler - ;; macro:) - (when (eq 'autoload (car (symbol-function 'make-coding-system))) - ;; Make sure to pick up the correct compiler macro when compiling - ;; files: - (define-compiler-macro make-coding-system (&whole form name type - &optional description props) - (load (second (symbol-function 'make-coding-system))) - (funcall (get 'make-coding-system 'cl-compiler-macro) - form name type description props)))) +(defun encode-char (char quote-ucs &optional restriction) + "FSF compatibility--return the Unicode code point of CHAR. +The second argument must be 'ucs, the third argument is ignored. " + (assert (eq quote-ucs 'ucs) t + "Sorry, encode-char doesn't yet support anything but the UCS. ") + (char-to-unicode char)) +(unless (featurep 'mule) ;; Mule's not available; (fset 'make-coding-system (symbol-function 'make-coding-system-internal)) (define-coding-system-alias 'escape-quoted 'binary)
--- a/lisp/diagnose.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/diagnose.el Tue Feb 23 07:28:35 2010 -0600 @@ -1,6 +1,6 @@ ;;; diagnose.el --- routines for debugging problems in XEmacs -;; Copyright (C) 2002 Ben Wing. +;; Copyright (C) 2002, 2010 Ben Wing. ;; Maintainer: XEmacs Development Team ;; Keywords: dumped @@ -197,29 +197,33 @@ (intern (concat (match-string 1 (symbol-name stat)) "-storage-including-overhead")))) (storage-count - (or (plist-get - plist - (intern - (concat (match-string 1 (symbol-name stat)) - "s-used"))) + (or (loop for str in '("s-used" "es-used" "-used") + for val = (plist-get + plist + (intern + (concat (match-string + 1 (symbol-name stat)) + str))) + if val + return val) (plist-get plist (intern - (concat (match-string 1 (symbol-name stat)) - "es-used"))) - (plist-get - plist - (intern - (concat (match-string 1 (symbol-name stat)) - "-used")))))) + (concat (substring + (match-string 1 (symbol-name stat)) + 0 -1) + "ies-used"))) + ))) (incf total-use storage-use) (incf total-use-overhead (if storage-use-overhead storage-use-overhead storage-use)) - (incf total-count storage-count) - (princ (format fmt - (match-string 1 (symbol-name stat)) - storage-count storage-use))))) + (incf total-count (or storage-count 0)) + (and (> storage-use 0) + (princ (format fmt + (match-string 1 (symbol-name stat)) + (or storage-count "unknown") + storage-use)))))) plist) (princ "\n") (princ (format fmt "total" @@ -229,7 +233,7 @@ (sort-numeric-fields -1 (save-excursion (goto-char begin) - (forward-line 2) + (forward-line 3) (point)) (save-excursion (forward-line -2)
--- a/lisp/dumped-lisp.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/dumped-lisp.el Tue Feb 23 07:28:35 2010 -0600 @@ -160,6 +160,7 @@ "code-process" ;; Provide basic commands to set coding systems to user "code-cmds" + (when (featurep 'mule) "mule/make-coding-system") "unicode" ;;;;;;;;;;;;;;;;;; MULE support (when (featurep 'mule)
--- a/lisp/help.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/help.el Tue Feb 23 07:28:35 2010 -0600 @@ -1,7 +1,7 @@ ;; help.el --- help commands for XEmacs. ;; Copyright (C) 1985, 1986, 1992-4, 1997 Free Software Foundation, Inc. -;; Copyright (C) 2001, 2002, 2003 Ben Wing. +;; Copyright (C) 2001, 2002, 2003, 2010 Ben Wing. ;; Maintainer: FSF ;; Keywords: help, internal, dumped @@ -1182,27 +1182,21 @@ (fndef (if (eq (car-safe fnc) 'macro) (cdr fnc) fnc)) + (args (cdr (function-documentation-1 function t))) (arglist - (cond ((compiled-function-p fndef) - (compiled-function-arglist fndef)) - ((eq (car-safe fndef) 'lambda) - (nth 1 fndef)) - ((or (subrp fndef) (eq 'autoload (car-safe fndef))) - (let* ((doc (documentation function)) - (args (and doc - (string-match - "[\n\t ]*\narguments: ?(\\([^)]*\\))\n?\\'" - doc) - (match-string 1 doc))) - (args (and args (replace-in-string args - "[ ]*\\\\\n[ \t]*" - " " t)))) - ;; If there are no arguments documented for the - ;; subr, rather don't print anything. - (cond ((null args) t) - ((equal args "") nil) - (args)))) - (t t))) + (or args + (cond ((compiled-function-p fndef) + (compiled-function-arglist fndef)) + ((eq (car-safe fndef) 'lambda) + (nth 1 fndef)) + ((or (subrp fndef) (eq 'autoload (car-safe fndef))) + + ;; If there are no arguments documented for the + ;; subr, rather don't print anything. + (cond ((null args) t) + ((equal args "") nil) + (args))) + (t t)))) (print-gensym nil)) (cond ((listp arglist) (prin1-to-string @@ -1217,20 +1211,31 @@ ((stringp arglist) (format "(%s %s)" function arglist))))) -(defun function-documentation (function &optional strip-arglist) - "Return a string giving the documentation for FUNCTION, if any. -If the optional argument STRIP-ARGLIST is non-nil, remove the arglist -part of the documentation of internal subroutines." +;; If STRIP-ARGLIST is true, return a cons (DOC . ARGS) of the documentation +;; with any embedded arglist stripped out, and the arglist that was stripped +;; out. If STRIP-ARGLIST is false, the cons will be (FULL-DOC . nil), +;; where FULL-DOC is the full documentation without the embedded arglist +;; stripped out. +(defun function-documentation-1 (function &optional strip-arglist) (let ((doc (condition-case nil (or (documentation function) (gettext "not documented")) (void-function "(alias for undefined function)") - (error "(unexpected error from `documention')")))) + (error "(unexpected error from `documentation')"))) + args) (when (and strip-arglist - (string-match "[\n\t ]*\narguments: ?(\\([^)]*\\))\n?\\'" doc)) + (string-match "[\n\t ]*\narguments: ?(\\(.*\\))\n?\\'" doc)) + (setq args (match-string 1 doc)) (setq doc (substring doc 0 (match-beginning 0))) + (and args (setq args (replace-in-string args "[ ]*\\\\\n[ \t]*" " " t))) (and (zerop (length doc)) (setq doc (gettext "not documented")))) - doc)) + (cons doc args))) + +(defun function-documentation (function &optional strip-arglist) + "Return a string giving the documentation for FUNCTION, if any. +If the optional argument STRIP-ARGLIST is non-nil, remove the arglist +part of the documentation of internal subroutines, CL lambda forms, etc." + (car (function-documentation-1 function strip-arglist))) ;; replacement for `princ' that puts the text in the specified face, ;; if possible
--- a/lisp/mule/make-coding-system.el Mon Feb 22 06:49:30 2010 -0600 +++ b/lisp/mule/make-coding-system.el Tue Feb 23 07:28:35 2010 -0600 @@ -2,6 +2,7 @@ ;;; much of the implementation of the fixed-width coding system type. ;; Copyright (C) 2009 Free Software Foundation +;; Copyright (C) 2010 Ben Wing. ;; Author: Aidan Kehoe @@ -26,13 +27,6 @@ ;;; Code: -(defvar fixed-width-private-use-start (decode-char 'ucs #xE000) - "Start of a 256 code private use area for fixed-width coding systems. - -This is used to ensure that distinct octets on disk for a given coding -system map to distinct XEmacs characters, preventing spurious changes when -a file is read, not changed, and then written. ") - (defun fixed-width-generate-helper (decode-table encode-table encode-failure-octet) "Helper func, `fixed-width-generate-encode-program-and-skip-chars-strings', @@ -323,7 +317,7 @@ (check-argument-type #'listp unicode-map) (let ((decode-table (make-vector 256 nil)) (encode-table (make-hash-table :size 256 :rehash-threshold 0.999)) - (private-use-start (encode-char fixed-width-private-use-start 'ucs)) + (private-use-start #xE000) (invalid-sequence-code-point-start (eval-when-compile (char-to-unicode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/test-harness.el Tue Feb 23 07:28:35 2010 -0600 @@ -0,0 +1,835 @@ +;; test-harness.el --- Run Emacs Lisp test suites. + +;;; Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc. +;;; Copyright (C) 2002, 2010 Ben Wing. + +;; Author: Martin Buchholz +;; Maintainer: Stephen J. Turnbull <stephen@xemacs.org> +;; Keywords: testing + +;; This file is part of XEmacs. + +;; XEmacs is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; XEmacs is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with XEmacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Synched up with: Not in FSF. + +;;; Commentary: + +;;; A test suite harness for testing XEmacs. +;;; The actual tests are in other files in this directory. +;;; Basically you just create files of emacs-lisp, and use the +;;; Assert, Check-Error, Check-Message, and Check-Error-Message functions +;;; to create tests. See `test-harness-from-buffer' below. +;;; Don't suppress tests just because they're due to known bugs not yet +;;; fixed -- use the Known-Bug-Expect-Failure and +;;; Implementation-Incomplete-Expect-Failure wrapper macros to mark them. +;;; A lot of the tests we run push limits; suppress Ebola message with the +;;; Ignore-Ebola wrapper macro. +;;; Some noisy code will call `message'. Output from `message' can be +;;; suppressed with the Silence-Message macro. Functions that are known to +;;; issue messages include `write-region', `find-tag', `tag-loop-continue', +;;; `insert', and `mark-whole-buffer'. N.B. The Silence-Message macro +;;; currently does not suppress the newlines printed by `message'. +;;; Definitely do not use Silence-Message with Check-Message. +;;; In general it should probably only be used on code that prepares for a +;;; test, not on tests. +;;; +;;; You run the tests using M-x test-emacs-test-file, +;;; or $(EMACS) -batch -l test-harness -f batch-test-emacs file ... +;;; which is run for you by the `make check' target in the top-level Makefile. + +(require 'bytecomp) + +(defvar unexpected-test-suite-failures 0 + "Cumulative number of unexpected failures since test-harness was loaded. + +\"Unexpected failures\" are those caught by a generic handler established +outside of the test context. As such they involve an abort of the test +suite for the file being tested. + +They often occur during preparation of a test or recording of the results. +For example, an executable used to generate test data might not be present +on the system, or a system error might occur while reading a data file.") + +(defvar unexpected-test-suite-failure-files nil + "List of test files causing unexpected failures.") + +;; Declared for dynamic scope; _do not_ initialize here. +(defvar unexpected-test-file-failures) + +(defvar test-harness-bug-expected nil + "Non-nil means a bug is expected; backtracing/debugging should not happen.") + +(defvar test-harness-test-compiled nil + "Non-nil means the test code was compiled before execution. + +You probably should not make tests depend on compilation. +However, it can be useful to conditionally change messages based on whether +the code was compiled or not. For example, the case that motivated the +implementation of this variable: + +\(when test-harness-test-compiled + ;; this ha-a-ack depends on the failing compiled test coming last + \(setq test-harness-failure-tag + \"KNOWN BUG - fix reverted; after 2003-10-31 notify stephen\n\"))") + +(defvar test-harness-verbose + (and (not noninteractive) (> (device-baud-rate) search-slow-speed)) + "*Non-nil means print messages describing progress of emacs-tester.") + +(defvar test-harness-unexpected-error-enter-debugger debug-on-error + "*Non-nil means enter debugger when an unexpected error occurs. +Only applies interactively. Normally true if `debug-on-error' has been set. +See also `test-harness-assertion-failure-enter-debugger' and +`test-harness-unexpected-error-show-backtrace'.") + +(defvar test-harness-assertion-failure-enter-debugger debug-on-error + "*Non-nil means enter debugger when an assertion failure occurs. +Only applies interactively. Normally true if `debug-on-error' has been set. +See also `test-harness-unexpected-error-enter-debugger' and +`test-harness-assertion-failure-show-backtrace'.") + +(defvar test-harness-unexpected-error-show-backtrace t + "*Non-nil means show backtrace upon unexpected error. +Only applies when debugger is not entered. Normally true by default. See also +`test-harness-unexpected-error-enter-debugger' and +`test-harness-assertion-failure-show-backtrace'.") + +(defvar test-harness-assertion-failure-show-backtrace stack-trace-on-error + "*Non-nil means show backtrace upon assertion failure. +Only applies when debugger is not entered. Normally true if +`stack-trace-on-error' has been set. See also +`test-harness-assertion-failure-enter-debugger' and +`test-harness-unexpected-error-show-backtrace'.") + +(defvar test-harness-file-results-alist nil + "Each element is a list (FILE SUCCESSES TESTS). +The order is the reverse of the order in which tests are run. + +FILE is a string naming the test file. +SUCCESSES is a non-negative integer, the number of successes. +TESTS is a non-negative integer, the number of tests run.") + +(defvar test-harness-risk-infloops nil + "*Non-nil to run tests that may loop infinitely in buggy implementations.") + +(defvar test-harness-current-file nil) + +(defvar emacs-lisp-file-regexp (purecopy "\\.el\\'") + "*Regexp which matches Emacs Lisp source files.") + +(defconst test-harness-file-summary-template + (format "%%-%ds %%%dd of %%%dd tests successful (%%3d%%%%)." + (length "byte-compiler-tests.el:") ; use the longest file name + 5 + 5) + "Format for summary lines printed after each file is run.") + +(defconst test-harness-null-summary-template + (format "%%-%ds No tests run." + (length "byte-compiler-tests.el:")) ; use the longest file name + "Format for \"No tests\" lines printed after a file is run.") + +(defconst test-harness-aborted-summary-template + (format "%%-%ds %%%dd tests completed (aborted)." + (length "byte-compiler-tests.el:") ; use the longest file name + 5) + "Format for summary lines printed after a test run on a file was aborted.") + +;;;###autoload +(defun test-emacs-test-file (filename) + "Test a file of Lisp code named FILENAME. +The output file's name is made by appending `c' to the end of FILENAME." + (interactive + (let ((file buffer-file-name) + (file-name nil) + (file-dir nil)) + (and file + (eq (cdr (assq 'major-mode (buffer-local-variables))) + 'emacs-lisp-mode) + (setq file-name (file-name-nondirectory file) + file-dir (file-name-directory file))) + (list (read-file-name "Test file: " file-dir nil nil file-name)))) + ;; Expand now so we get the current buffer's defaults + (setq filename (expand-file-name filename)) + + ;; If we're testing a file that's in a buffer and is modified, offer + ;; to save it first. + (or noninteractive + (let ((b (get-file-buffer (expand-file-name filename)))) + (if (and b (buffer-modified-p b) + (y-or-n-p (format "save buffer %s first? " (buffer-name b)))) + (save-excursion (set-buffer b) (save-buffer))))) + + (if (or noninteractive test-harness-verbose) + (message "Testing %s..." filename)) + (let ((test-harness-current-file filename) + input-buffer) + (save-excursion + (setq input-buffer (get-buffer-create " *Test Input*")) + (set-buffer input-buffer) + (erase-buffer) + (insert-file-contents filename) + ;; Run hooks including the uncompression hook. + ;; If they change the file name, then change it for the output also. + (let ((buffer-file-name filename) + (default-major-mode 'emacs-lisp-mode) + (enable-local-eval nil)) + (normal-mode) + (setq filename buffer-file-name))) + (test-harness-from-buffer input-buffer filename) + (kill-buffer input-buffer) + )) + +(defsubst test-harness-assertion-failure-do-debug (error-info) + "Maybe enter debugger or display a backtrace on assertion failure. +ERROR-INFO is a cons of the args (SIG . DATA) that were passed to `signal'. +The debugger will be entered if noninteractive and +`test-harness-unexpected-error-enter-debugger' is non-nil; else, a +backtrace will be displayed if `test-harness-unexpected-error-show-backtrace' +is non-nil." + (when (not test-harness-bug-expected) + (cond ((and (not noninteractive) + test-harness-assertion-failure-enter-debugger) + (funcall debugger 'error error-info)) + (test-harness-assertion-failure-show-backtrace + (backtrace nil t))))) + +(defsubst test-harness-unexpected-error-do-debug (error-info) + "Maybe enter debugger or display a backtrace on unexpected error. +ERROR-INFO is a cons of the args (SIG . DATA) that were passed to `signal'. +The debugger will be entered if noninteractive and +`test-harness-unexpected-error-enter-debugger' is non-nil; else, a +backtrace will be displayed if `test-harness-unexpected-error-show-backtrace' +is non-nil." + (when (not test-harness-bug-expected) + (cond ((and (not noninteractive) + test-harness-unexpected-error-enter-debugger) + (funcall debugger 'error error-info)) + (test-harness-unexpected-error-show-backtrace + (backtrace nil t))))) + +(defsubst test-harness-unexpected-error-condition-handler (error-info context-msg) + "Condition handler for when unexpected errors occur. +Useful in conjunction with `call-with-condition-handler'. ERROR-INFO is the +value passed to the condition handler. CONTEXT-MSG is a string indicating +the context in which the unexpected error occurred. A message is outputted +including CONTEXT-MSG in it, `unexpected-test-file-failures' is incremented, +and `test-harness-unexpected-error-do-debug' is called, which may enter the +debugger or output a backtrace, depending on the settings of +`test-harness-unexpected-error-enter-debugger' and +`test-harness-unexpected-error-show-backtrace'. + +The function returns normally, which causes error-handling processing to +continue; if you want to catch the error, you also need to wrap everything +in `condition-case'. See also `test-harness-error-wrap', which does this +wrapping." + (incf unexpected-test-file-failures) + (princ (format "Unexpected error %S while %s\n" + error-info context-msg)) + (message "Unexpected error %S while %s." error-info context-msg) + (test-harness-unexpected-error-do-debug error-info)) + +(defmacro test-harness-error-wrap (context-msg abort-msg &rest body) + "Wrap BODY so that unexpected errors are caught. +The debugger will be entered if noninteractive and +`test-harness-unexpected-error-enter-debugger' is non-nil; else, a backtrace +will be displayed if `test-harness-unexpected-error-show-backtrace' is +non-nil. CONTEXT-MSG is displayed as part of a message shown before entering +the debugger or showing a backtrace, and ABORT-MSG, if non-nil, is displayed +afterwards. See " + `(condition-case nil + (call-with-condition-handler + #'(lambda (error-info) + (test-harness-unexpected-error-condition-handler + error-info ,context-msg)) + #'(lambda () + ,@body)) + (error ,(if abort-msg `(message ,abort-msg) nil)))) + +(defun test-harness-read-from-buffer (buffer) + "Read forms from BUFFER, and turn it into a lambda test form." + (let ((body nil)) + (goto-char (point-min) buffer) + (condition-case nil + (call-with-condition-handler + #'(lambda (error-info) + ;; end-of-file is expected, so don't output error or backtrace + ;; or enter debugger in this case. + (unless (eq 'end-of-file (car error-info)) + (test-harness-unexpected-error-condition-handler + error-info "reading forms from buffer"))) + #'(lambda () + (while t + (setq body (cons (read buffer) body))))) + (error nil)) + `(lambda () + (defvar passes) + (defvar assertion-failures) + (defvar no-error-failures) + (defvar wrong-error-failures) + (defvar missing-message-failures) + (defvar other-failures) + + (defvar trick-optimizer) + + ,@(nreverse body)))) + +(defun test-harness-from-buffer (inbuffer filename) + "Run tests in buffer INBUFFER, visiting FILENAME." + (defvar trick-optimizer) + (let ((passes 0) + (assertion-failures 0) + (no-error-failures 0) + (wrong-error-failures 0) + (missing-message-failures 0) + (other-failures 0) + (unexpected-test-file-failures 0) + + ;; #### perhaps this should be a defvar, and output at the very end + ;; OTOH, this way AC types can use a null EMACSPACKAGEPATH to find + ;; what stuff is needed, and ways to avoid using them + (skipped-test-reasons (make-hash-table :test 'equal)) + + (trick-optimizer nil) + (debug-on-error t) + ) + (with-output-to-temp-buffer "*Test-Log*" + (princ (format "Testing %s...\n\n" filename)) + + (defconst test-harness-failure-tag "FAIL") + (defconst test-harness-success-tag "PASS") + +;;;;; BEGIN DEFINITION OF MACROS USEFUL IN TEST CODE + + (defmacro Known-Bug-Expect-Failure (&rest body) + "Wrap a BODY that consists of tests that are known to fail. +This causes messages to be printed on failure indicating that this is expected, +and on success indicating that this is unexpected." + `(let ((test-harness-bug-expected t) + (test-harness-failure-tag "KNOWN BUG") + (test-harness-success-tag "PASS (FAILURE EXPECTED)")) + ,@body)) + + (defmacro Known-Bug-Expect-Error (expected-error &rest body) + "Wrap a BODY that consists of tests that are known to trigger an error. +This causes messages to be printed on failure indicating that this is expected, +and on success indicating that this is unexpected." + (let ((quoted-body (if (= 1 (length body)) + `(quote ,(car body)) `(quote (progn ,@body))))) + `(let ((test-harness-bug-expected t) + (test-harness-failure-tag "KNOWN BUG") + (test-harness-success-tag "PASS (FAILURE EXPECTED)")) + (condition-case error-info + (progn + (setq trick-optimizer (progn ,@body)) + (Print-Pass + "%S executed successfully, but expected error %S" + ,quoted-body + ',expected-error) + (incf passes)) + (,expected-error + (Print-Failure "%S ==> error %S, as expected" + ,quoted-body ',expected-error) + (incf no-error-failures)) + (error + (Print-Failure "%S ==> expected error %S, got error %S instead" + ,quoted-body ',expected-error error-info) + (incf wrong-error-failures)))))) + + (defmacro Implementation-Incomplete-Expect-Failure (&rest body) + "Wrap a BODY containing tests that are known to fail due to incomplete code. +This causes messages to be printed on failure indicating that the +implementation is incomplete (and hence the failure is expected); and on +success indicating that this is unexpected." + `(let ((test-harness-bug-expected t) + (test-harness-failure-tag "IMPLEMENTATION INCOMPLETE") + (test-harness-success-tag "PASS (FAILURE EXPECTED)")) + ,@body)) + + (defun Print-Failure (fmt &rest args) + (setq fmt (format "%s: %s" test-harness-failure-tag fmt)) + (if (noninteractive) (apply #'message fmt args)) + (princ (concat (apply #'format fmt args) "\n"))) + + (defun Print-Pass (fmt &rest args) + (setq fmt (format "%s: %s" test-harness-success-tag fmt)) + (and test-harness-verbose + (princ (concat (apply #'format fmt args) "\n")))) + + (defun Print-Skip (test reason &optional fmt &rest args) + (setq fmt (concat "SKIP: %S BECAUSE %S" fmt)) + (princ (concat (apply #'format fmt test reason args) "\n"))) + + (defmacro Skip-Test-Unless (condition reason description &rest body) + "Unless CONDITION is satisfied, skip test BODY. +REASON is a description of the condition failure, and must be unique (it +is used as a hash key). DESCRIPTION describes the tests that were skipped. +BODY is a sequence of expressions and may contain several tests." + `(if (not ,condition) + (let ((count (gethash ,reason skipped-test-reasons))) + (puthash ,reason (if (null count) 1 (1+ count)) + skipped-test-reasons) + (Print-Skip ,description ,reason)) + ,@body)) + + (defmacro Assert (assertion &optional failing-case description) + "Test passes if ASSERTION is true. +Optional FAILING-CASE describes the particular failure. Optional +DESCRIPTION describes the assertion; by default, the unevalated assertion +expression is given. FAILING-CASE and DESCRIPTION are useful when Assert +is used in a loop." + (let ((description + (or description `(quote ,assertion)))) + `(condition-case nil + (call-with-condition-handler + #'(lambda (error-info) + (if (eq 'cl-assertion-failed (car error-info)) + (progn + (Print-Failure + (if ,failing-case + "Assertion failed: %S; failing case = %S" + "Assertion failed: %S") + ,description ,failing-case) + (incf assertion-failures) + (test-harness-assertion-failure-do-debug error-info)) + (Print-Failure + (if ,failing-case + "%S ==> error: %S; failing case = %S" + "%S ==> error: %S") + ,description error-info ,failing-case) + (incf other-failures) + (test-harness-unexpected-error-do-debug error-info))) + #'(lambda () + (assert ,assertion) + (Print-Pass "%S" ,description) + (incf passes))) + (cl-assertion-failed nil)))) + +;;;;; BEGIN DEFINITION OF SPECIFIC KINDS OF ASSERT MACROS + + (defmacro Assert-test (test testval expected &optional failing-case + description) + "Test passes if TESTVAL compares correctly to EXPECTED using TEST. +TEST should be a two-argument predicate (i.e. a function of two arguments +that returns t or nil), such as `eq', `eql', `equal', `equalp', `=', `<=', +'>', 'file-newer-than-file-p' etc. Optional FAILING-CASE describes the +particular failure; any value given here will be concatenated with a phrase +describing the expected and actual values of the comparison. Optional +DESCRIPTION describes the assertion; by default, the unevalated comparison +expressions are given. FAILING-CASE and DESCRIPTION are useful when Assert +is used in a loop." + (let* ((assertion `(,test ,testval ,expected)) + (failmsg `(format "%S should be `%s' to %S but isn't" + ,testval ',test ,expected)) + (failmsg2 (if failing-case `(concat + (format "%S, " ,failing-case) + ,failmsg) + failmsg))) + `(Assert ,assertion ,failmsg2 ,description))) + + (defmacro Assert-test-not (test testval expected &optional failing-case + description) + "Test passes if TESTVAL does not compare correctly to EXPECTED using TEST. +TEST should be a two-argument predicate (i.e. a function of two arguments +that returns t or nil), such as `eq', `eql', `equal', `equalp', `=', `<=', +'>', 'file-newer-than-file-p' etc. Optional FAILING-CASE describes the +particular failure; any value given here will be concatenated with a phrase +describing the expected and actual values of the comparison. Optional +DESCRIPTION describes the assertion; by default, the unevalated comparison +expressions are given. FAILING-CASE and DESCRIPTION are useful when Assert +is used in a loop." + (let* ((assertion `(not (,test ,testval ,expected))) + (failmsg `(format "%S shouldn't be `%s' to %S but is" + ,testval ',test ,expected)) + (failmsg2 (if failing-case `(concat + (format "%S, " ,failing-case) + ,failmsg) + failmsg))) + `(Assert ,assertion ,failmsg2 ,description))) + + ;; Specific versions of `Assert-test'. These are just convenience + ;; functions, functioning identically to `Assert-test', and duplicating + ;; the doc string for each would be too annoying. + (defmacro Assert-eq (testval expected &optional failing-case + description) + `(Assert-test eq ,testval ,expected ,failing-case ,description)) + (defmacro Assert-eql (testval expected &optional failing-case + description) + `(Assert-test eql ,testval ,expected ,failing-case ,description)) + (defmacro Assert-equal (testval expected &optional failing-case + description) + `(Assert-test equal ,testval ,expected ,failing-case ,description)) + (defmacro Assert-equalp (testval expected &optional failing-case + description) + `(Assert-test equalp ,testval ,expected ,failing-case ,description)) + (defmacro Assert-string= (testval expected &optional failing-case + description) + `(Assert-test string= ,testval ,expected ,failing-case ,description)) + (defmacro Assert= (testval expected &optional failing-case + description) + `(Assert-test = ,testval ,expected ,failing-case ,description)) + (defmacro Assert<= (testval expected &optional failing-case + description) + `(Assert-test <= ,testval ,expected ,failing-case ,description)) + + ;; Specific versions of `Assert-test-not'. These are just convenience + ;; functions, functioning identically to `Assert-test-not', and + ;; duplicating the doc string for each would be too annoying. + (defmacro Assert-not-eq (testval expected &optional failing-case + description) + `(Assert-test-not eq ,testval ,expected ,failing-case ,description)) + (defmacro Assert-not-eql (testval expected &optional failing-case + description) + `(Assert-test-not eql ,testval ,expected ,failing-case ,description)) + (defmacro Assert-not-equal (testval expected &optional failing-case + description) + `(Assert-test-not equal ,testval ,expected ,failing-case ,description)) + (defmacro Assert-not-equalp (testval expected &optional failing-case + description) + `(Assert-test-not equalp ,testval ,expected ,failing-case ,description)) + (defmacro Assert-not-string= (testval expected &optional failing-case + description) + `(Assert-test-not string= ,testval ,expected ,failing-case ,description)) + (defmacro Assert-not= (testval expected &optional failing-case + description) + `(Assert-test-not = ,testval ,expected ,failing-case ,description)) + + (defmacro Check-Error (expected-error &rest body) + (let ((quoted-body (if (= 1 (length body)) + `(quote ,(car body)) `(quote (progn ,@body))))) + `(condition-case error-info + (progn + (setq trick-optimizer (progn ,@body)) + (Print-Failure "%S executed successfully, but expected error %S" + ,quoted-body + ',expected-error) + (incf no-error-failures)) + (,expected-error + (Print-Pass "%S ==> error %S, as expected" + ,quoted-body ',expected-error) + (incf passes)) + (error + (Print-Failure "%S ==> expected error %S, got error %S instead" + ,quoted-body ',expected-error error-info) + (incf wrong-error-failures))))) + + (defmacro Check-Error-Message (expected-error expected-error-regexp + &rest body) + (let ((quoted-body (if (= 1 (length body)) + `(quote ,(car body)) `(quote (progn ,@body))))) + `(condition-case error-info + (progn + (setq trick-optimizer (progn ,@body)) + (Print-Failure "%S executed successfully, but expected error %S" + ,quoted-body ',expected-error) + (incf no-error-failures)) + (,expected-error + ;; #### Damn, this binding doesn't capture frobs, eg, for + ;; invalid_argument() ... you only get the REASON. And for + ;; wrong_type_argument(), there's no reason only FROBs. + ;; If this gets fixed, fix tests in regexp-tests.el. + (let ((error-message (second error-info))) + (if (string-match ,expected-error-regexp error-message) + (progn + (Print-Pass "%S ==> error %S %S, as expected" + ,quoted-body error-message ',expected-error) + (incf passes)) + (Print-Failure "%S ==> got error %S as expected, but error message %S did not match regexp %S" + ,quoted-body ',expected-error error-message ,expected-error-regexp) + (incf wrong-error-failures)))) + (error + (Print-Failure "%S ==> expected error %S, got error %S instead" + ,quoted-body ',expected-error error-info) + (incf wrong-error-failures))))) + + ;; Do not use this with Silence-Message. + (defmacro Check-Message (expected-message-regexp &rest body) + (let ((quoted-body (if (= 1 (length body)) + `(quote ,(car body)) + `(quote (progn ,@body))))) + `(Skip-Test-Unless (fboundp 'defadvice) "can't defadvice" + expected-message-regexp + (let ((messages "")) + (defadvice message (around collect activate) + (defvar messages) + (let ((msg-string (apply 'format (ad-get-args 0)))) + (setq messages (concat messages msg-string)) + msg-string)) + (ignore-errors + (call-with-condition-handler + #'(lambda (error-info) + (Print-Failure "%S ==> unexpected error %S" + ,quoted-body error-info) + (incf other-failures) + (test-harness-unexpected-error-do-debug error-info)) + #'(lambda () + (setq trick-optimizer (progn ,@body)) + (if (string-match ,expected-message-regexp messages) + (progn + (Print-Pass + "%S ==> value %S, message %S, matching %S, as expected" + ,quoted-body trick-optimizer messages + ',expected-message-regexp) + (incf passes)) + (Print-Failure + "%S ==> value %S, message %S, NOT matching expected %S" + ,quoted-body trick-optimizer messages + ',expected-message-regexp) + (incf missing-message-failures))))) + (ad-unadvise 'message))))) + + ;; #### Perhaps this should override `message' itself, too? + (defmacro Silence-Message (&rest body) + `(flet ((append-message (&rest args) ()) + (clear-message (&rest args) ())) + ,@body)) + + (defmacro Ignore-Ebola (&rest body) + `(let ((debug-issue-ebola-notices -42)) ,@body)) + + (defun Int-to-Marker (pos) + (save-excursion + (set-buffer standard-output) + (save-excursion + (goto-char pos) + (point-marker)))) + + (princ "Testing Interpreted Lisp\n\n") + + (test-harness-error-wrap + "executing interpreted code" + "Test suite execution aborted." + (funcall (test-harness-read-from-buffer inbuffer))) + + (princ "\nTesting Compiled Lisp\n\n") + + (let (code + (test-harness-test-compiled t)) + (test-harness-error-wrap + "byte-compiling code" nil + (setq code + ;; our lisp code is often intentionally dubious, + ;; so throw away _all_ the byte compiler warnings. + (letf (((symbol-function 'byte-compile-warn) + 'ignore)) + (byte-compile (test-harness-read-from-buffer + inbuffer)))) + ) + + (test-harness-error-wrap "executing byte-compiled code" + "Test suite execution aborted." + (if code (funcall code))) + ) + (princ (format "\nSUMMARY for %s:\n" filename)) + (princ (format "\t%5d passes\n" passes)) + (princ (format "\t%5d assertion failures\n" assertion-failures)) + (princ (format "\t%5d errors that should have been generated, but weren't\n" no-error-failures)) + (princ (format "\t%5d wrong-error failures\n" wrong-error-failures)) + (princ (format "\t%5d missing-message failures\n" missing-message-failures)) + (princ (format "\t%5d other failures\n" other-failures)) + (let* ((total (+ passes + assertion-failures + no-error-failures + wrong-error-failures + missing-message-failures + other-failures)) + (basename (file-name-nondirectory filename)) + (summary-msg + (cond ((> unexpected-test-file-failures 0) + (format test-harness-aborted-summary-template + (concat basename ":") total)) + ((> total 0) + (format test-harness-file-summary-template + (concat basename ":") + passes total (/ (* 100 passes) total))) + (t + (format test-harness-null-summary-template + (concat basename ":"))))) + (reasons "")) + (maphash (lambda (key value) + (setq reasons + (concat reasons + (format "\n %d tests skipped because %s." + value key)))) + skipped-test-reasons) + (when (> (length reasons) 1) + (setq summary-msg (concat summary-msg reasons " + It may be that XEmacs cannot find your installed packages. Set + EMACSPACKAGEPATH to the package hierarchy root or configure with + --package-path to enable the skipped tests."))) + (setq test-harness-file-results-alist + (cons (list filename passes total) + test-harness-file-results-alist)) + (message "%s" summary-msg)) + (when (> unexpected-test-file-failures 0) + (setq unexpected-test-suite-failure-files + (cons filename unexpected-test-suite-failure-files)) + (setq unexpected-test-suite-failures + (+ unexpected-test-suite-failures unexpected-test-file-failures)) + (message "Test suite execution failed unexpectedly.")) + (fmakunbound 'Assert) + (fmakunbound 'Check-Error) + (fmakunbound 'Check-Message) + (fmakunbound 'Check-Error-Message) + (fmakunbound 'Ignore-Ebola) + (fmakunbound 'Int-to-Marker) + (and noninteractive + (message "%s" (buffer-substring-no-properties + nil nil "*Test-Log*"))) + ))) + +(defvar test-harness-results-point-max nil) +(defmacro displaying-emacs-test-results (&rest body) + `(let ((test-harness-results-point-max test-harness-results-point-max)) + ;; Log the file name. + (test-harness-log-file) + ;; Record how much is logged now. + ;; We will display the log buffer if anything more is logged + ;; before the end of BODY. + (or test-harness-results-point-max + (save-excursion + (set-buffer (get-buffer-create "*Test-Log*")) + (setq test-harness-results-point-max (point-max)))) + (unwind-protect + (condition-case error-info + (progn ,@body) + (error + (test-harness-report-error error-info))) + (save-excursion + ;; If there were compilation warnings, display them. + (set-buffer "*Test-Log*") + (if (= test-harness-results-point-max (point-max)) + nil + (if temp-buffer-show-function + (let ((show-buffer (get-buffer-create "*Test-Log-Show*"))) + (save-excursion + (set-buffer show-buffer) + (setq buffer-read-only nil) + (erase-buffer)) + (copy-to-buffer show-buffer + (save-excursion + (goto-char test-harness-results-point-max) + (forward-line -1) + (point)) + (point-max)) + (funcall temp-buffer-show-function show-buffer)) + (select-window + (prog1 (selected-window) + (select-window (display-buffer (current-buffer))) + (goto-char test-harness-results-point-max) + (recenter 1))))))))) + +(defun batch-test-emacs-1 (file) + (condition-case error-info + (progn (test-emacs-test-file file) t) + (error + (princ ">>Error occurred processing ") + (princ file) + (princ ": ") + (display-error error-info nil) + (terpri) + nil))) + +(defun batch-test-emacs () + "Run `test-harness' on the files remaining on the command line. +Use this from the command line, with `-batch'; +it won't work in an interactive Emacs. +Each file is processed even if an error occurred previously. +A directory can be given as well, and all files will be processed. +For example, invoke \"xemacs -batch -f batch-test-emacs tests\"" + ;; command-line-args-left is what is left of the command line (from + ;; startup.el) + (defvar command-line-args-left) ;Avoid 'free variable' warning + (defvar debug-issue-ebola-notices) + (if (not noninteractive) + (error "`batch-test-emacs' is to be used only with -batch")) + (let ((error nil)) + (dolist (file command-line-args-left) + (if (file-directory-p file) + (dolist (file-in-dir (directory-files file t)) + (when (and (string-match emacs-lisp-file-regexp file-in-dir) + (not (or (auto-save-file-name-p file-in-dir) + (backup-file-name-p file-in-dir)))) + (or (batch-test-emacs-1 file-in-dir) + (setq error t)))) + (or (batch-test-emacs-1 file) + (setq error t)))) + (let ((namelen 0) + (succlen 0) + (testlen 0) + (results test-harness-file-results-alist)) + ;; compute maximum lengths of variable components of report + ;; probably should just use (length "byte-compiler-tests.el") + ;; and 5-place sizes -- this will also work for the file-by-file + ;; printing when Adrian's kludge gets reverted + (flet ((print-width (i) + (let ((x 10) (y 1)) + (while (>= i x) + (setq x (* 10 x) y (1+ y))) + y))) + (while results + (let* ((head (car results)) + (nn (length (file-name-nondirectory (first head)))) + (ss (print-width (second head))) + (tt (print-width (third head)))) + (when (> nn namelen) (setq namelen nn)) + (when (> ss succlen) (setq succlen ss)) + (when (> tt testlen) (setq testlen tt))) + (setq results (cdr results)))) + ;; create format and print + (let ((results (reverse test-harness-file-results-alist))) + (while results + (let* ((head (car results)) + (basename (file-name-nondirectory (first head))) + (nsucc (second head)) + (ntest (third head))) + (cond ((member (first head) unexpected-test-suite-failure-files) + (message test-harness-aborted-summary-template + (concat basename ":") + ntest)) + ((> ntest 0) + (message test-harness-file-summary-template + (concat basename ":") + nsucc + ntest + (/ (* 100 nsucc) ntest))) + (t + (message test-harness-null-summary-template + (concat basename ":")))) + (setq results (cdr results))))) + (when (> unexpected-test-suite-failures 0) + (message "\n***** There %s %d unexpected test suite %s in %s:" + (if (= unexpected-test-suite-failures 1) "was" "were") + unexpected-test-suite-failures + (if (= unexpected-test-suite-failures 1) "failure" "failures") + (if (= (length unexpected-test-suite-failure-files) 1) + "file" + "files")) + (while unexpected-test-suite-failure-files + (let ((line (pop unexpected-test-suite-failure-files))) + (while (and (< (length line) 61) + unexpected-test-suite-failure-files) + (setq line + (concat line " " + (pop unexpected-test-suite-failure-files)))) + (message line))))) + (message "\nDone") + (kill-emacs (if error 1 0)))) + +(provide 'test-harness) + +;;; test-harness.el ends here
--- a/src/.gdbinit.in.in Mon Feb 22 06:49:30 2010 -0600 +++ b/src/.gdbinit.in.in Tue Feb 23 07:28:35 2010 -0600 @@ -159,7 +159,7 @@ end define check-xemacs-arg - run -vanilla -batch -l @srcdir@/../tests/automated/test-harness.el -f batch-test-emacs @srcdir@/../tests/$arg0 + run -vanilla -batch -l test-harness -f batch-test-emacs @srcdir@/../tests/$arg0 end define check-xemacs @@ -178,7 +178,7 @@ define check-temacs-arg environment-to-run-temacs - run -nd -no-packages -batch -l @srcdir@/../lisp/loadup.el run-temacs -q -batch -l @srcdir@/../tests/automated/test-harness.el -f batch-test-emacs @srcdir@/../tests/$arg0 + run -nd -no-packages -batch -l @srcdir@/../lisp/loadup.el run-temacs -q -batch -l test-harness -f batch-test-emacs @srcdir@/../tests/$arg0 define check-temacs if $argc == 0
--- a/src/ChangeLog Mon Feb 22 06:49:30 2010 -0600 +++ b/src/ChangeLog Tue Feb 23 07:28:35 2010 -0600 @@ -93,6 +93,76 @@ the old files (e.g. in #include statements, Makefiles, functions like syms_of_objects_x(), etc.). +2010-02-22 Ben Wing <ben@xemacs.org> + + * .gdbinit.in.in: + * Makefile.in.in (batch_test_emacs): + test-harness.el is in lisp directory now so change how we call it. + +2010-02-22 Ben Wing <ben@xemacs.org> + + * alloc.c (object_memory_usage_stats): + Remove unused var. + +2010-02-21 Ben Wing <ben@xemacs.org> + + * alloc.c: + * alloc.c (FREE_FIXED_TYPE_WHEN_NOT_IN_GC): + * alloc.c (struct): + * alloc.c (tick_lrecord_stats): + * alloc.c (tick_lcrecord_stats): + * alloc.c (sweep_lcrecords_1): + * alloc.c (COUNT_FROB_BLOCK_USAGE): + * alloc.c (SWEEP_FIXED_TYPE_BLOCK_1): + * alloc.c (free_cons): + * alloc.c (free_key_data): + * alloc.c (free_button_data): + * alloc.c (free_motion_data): + * alloc.c (free_process_data): + * alloc.c (free_timeout_data): + * alloc.c (free_magic_data): + * alloc.c (free_magic_eval_data): + * alloc.c (free_eval_data): + * alloc.c (free_misc_user_data): + * alloc.c (free_marker): + * alloc.c (gc_sweep_1): + * alloc.c (HACK_O_MATIC): + * alloc.c (FROB): + * alloc.c (object_memory_usage_stats): + * alloc.c (Fgarbage_collect): + * dumper.c: + * dumper.c (pdump_objects_unmark): + * lrecord.h: + * lrecord.h (enum lrecord_alloc_status): + Fixes to memory-usage-tracking code, etc. + + (1) Incorporate NEW_GC stuff into FREE_FIXED_TYPE_WHEN_NOT_IN_GC + to avoid duplication. + + (2) Rewrite tick_lcrecord_stats() to include separate + tick_lrecord_stats(); use in dumper.c to note pdumped objects. + + (3) Instead of handling frob-block objects specially in + object_memory_usage_stats(), have SWEEP_FIXED_TYPE_BLOCK_1 + increment the stats in lrecord_stats[] so that they get handled + like other objects. + + (4) Pluralize entry as entries, etc. + +2010-02-21 Ben Wing <ben@xemacs.org> + + * alloc.c: + * alloc.c (pluralize_word): + New function to pluralize a word. + * alloc.c (pluralize_and_append): New function. + * alloc.c (object_memory_usage_stats): + Clean up duplication. + +2010-02-21 Vin Shelton <acs@xemacs.org> + + * events.c (event_pixel_translation): Simplify assertion for + Visual C 6. + 2010-02-21 Ben Wing <ben@xemacs.org> * gc.c (kkcc_marking): Fix compile error.
--- a/src/Makefile.in.in Mon Feb 22 06:49:30 2010 -0600 +++ b/src/Makefile.in.in Tue Feb 23 07:28:35 2010 -0600 @@ -882,7 +882,7 @@ ###################### Automated tests testdir = $(SRC)/../tests/automated -batch_test_emacs = $(BATCH_PACKAGES) -l $(testdir)/test-harness.el -f batch-test-emacs $(testdir) +batch_test_emacs = $(BATCH_PACKAGES) -l test-harness -f batch-test-emacs $(testdir) ## `config-changed' is useful if you are building both Unicode-internal ## and old-Mule workspaces using --srcdir and don't run configure before
--- a/src/alloc.c Mon Feb 22 06:49:30 2010 -0600 +++ b/src/alloc.c Tue Feb 23 07:28:35 2010 -0600 @@ -1150,7 +1150,12 @@ PUT_FIXED_TYPE_ON_FREE_LIST (type, structtype, FFT_ptr); \ MARK_LRECORD_AS_FREE (FFT_ptr); \ } while (0) - +#endif /* NEW_GC */ + +#ifdef NEW_GC +#define FREE_FIXED_TYPE_WHEN_NOT_IN_GC(lo, type, structtype, ptr) \ + free_lrecord (lo) +#else /* not NEW_GC */ /* Like FREE_FIXED_TYPE() but used when we are explicitly freeing a structure through free_cons(), free_marker(), etc. rather than through the normal process of sweeping. @@ -1165,15 +1170,15 @@ set, which is used for Purify and the like. */ #ifndef ALLOC_NO_POOLS -#define FREE_FIXED_TYPE_WHEN_NOT_IN_GC(type, structtype, ptr) \ -do { FREE_FIXED_TYPE (type, structtype, ptr); \ - DECREMENT_CONS_COUNTER (sizeof (structtype)); \ - gc_count_num_##type##_freelist++; \ +#define FREE_FIXED_TYPE_WHEN_NOT_IN_GC(lo, type, structtype, ptr) \ +do { FREE_FIXED_TYPE (type, structtype, ptr); \ + DECREMENT_CONS_COUNTER (sizeof (structtype)); \ + gc_count_num_##type##_freelist++; \ } while (0) #else -#define FREE_FIXED_TYPE_WHEN_NOT_IN_GC(type, structtype, ptr) +#define FREE_FIXED_TYPE_WHEN_NOT_IN_GC(lo, type, structtype, ptr) #endif -#endif /* NEW_GC */ +#endif /* (not) NEW_GC */ #ifdef NEW_GC #define ALLOCATE_FIXED_TYPE_AND_SET_IMPL(type, lisp_type, var, lrec_ptr) \ @@ -3481,33 +3486,45 @@ int instances_freed; int bytes_freed; int instances_on_free_list; -} lcrecord_stats [countof (lrecord_implementations_table)]; - -static void -tick_lcrecord_stats (const struct lrecord_header *h, int free_p) + int bytes_on_free_list; +} lrecord_stats [countof (lrecord_implementations_table)]; + +void +tick_lrecord_stats (const struct lrecord_header *h, + enum lrecord_alloc_status status) { int type_index = h->type; - + Bytecount sz = detagged_lisp_object_size (h); + + switch (status) + { + case ALLOC_IN_USE: + lrecord_stats[type_index].instances_in_use++; + lrecord_stats[type_index].bytes_in_use += sz; + break; + case ALLOC_FREE: + lrecord_stats[type_index].instances_freed++; + lrecord_stats[type_index].bytes_freed += sz; + break; + case ALLOC_ON_FREE_LIST: + lrecord_stats[type_index].instances_on_free_list++; + lrecord_stats[type_index].bytes_on_free_list += sz; + break; + default: + ABORT (); + } +} + +inline static void +tick_lcrecord_stats (const struct lrecord_header *h, int free_p) +{ if (((struct old_lcrecord_header *) h)->free) { gc_checking_assert (!free_p); - lcrecord_stats[type_index].instances_on_free_list++; + tick_lrecord_stats (h, ALLOC_ON_FREE_LIST); } else - { - Bytecount sz = detagged_lisp_object_size (h); - - if (free_p) - { - lcrecord_stats[type_index].instances_freed++; - lcrecord_stats[type_index].bytes_freed += sz; - } - else - { - lcrecord_stats[type_index].instances_in_use++; - lcrecord_stats[type_index].bytes_in_use += sz; - } - } + tick_lrecord_stats (h, free_p ? ALLOC_FREE : ALLOC_IN_USE); } #endif /* not NEW_GC */ @@ -3521,8 +3538,6 @@ int num_used = 0; /* int total_size = 0; */ - xzero (lcrecord_stats); /* Reset all statistics to 0. */ - /* First go through and call all the finalize methods. Then go through and free the objects. There used to be only one loop here, with the call to the finalizer @@ -3577,6 +3592,22 @@ /* And the Lord said: Thou shalt use the `c-backslash-region' command to make macros prettier. */ +#define COUNT_FROB_BLOCK_USAGE(type) \ + EMACS_INT s = 0; \ + struct type##_block *x = current_##type##_block; \ + while (x) { s += sizeof (*x) + MALLOC_OVERHEAD; x = x->prev; } \ + DO_NOTHING + +#define COPY_INTO_LRECORD_STATS(type) \ +do { \ + COUNT_FROB_BLOCK_USAGE (type); \ + lrecord_stats[lrecord_type_##type].bytes_in_use += s; \ + lrecord_stats[lrecord_type_##type].instances_on_free_list += \ + gc_count_num_##type##_freelist; \ + lrecord_stats[lrecord_type_##type].instances_in_use += \ + gc_count_num_##type##_in_use; \ +} while (0) + #ifdef ERROR_CHECK_GC #define SWEEP_FIXED_TYPE_BLOCK_1(typename, obj_type, lheader) \ @@ -3621,86 +3652,88 @@ \ gc_count_num_##typename##_in_use = num_used; \ gc_count_num_##typename##_freelist = num_free; \ + COPY_INTO_LRECORD_STATS (typename); \ } while (0) #else /* !ERROR_CHECK_GC */ -#define SWEEP_FIXED_TYPE_BLOCK_1(typename, obj_type, lheader) \ -do { \ - struct typename##_block *SFTB_current; \ - struct typename##_block **SFTB_prev; \ - int SFTB_limit; \ - int num_free = 0, num_used = 0; \ - \ - typename##_free_list = 0; \ - \ - for (SFTB_prev = ¤t_##typename##_block, \ - SFTB_current = current_##typename##_block, \ - SFTB_limit = current_##typename##_block_index; \ - SFTB_current; \ - ) \ - { \ - int SFTB_iii; \ - int SFTB_empty = 1; \ - Lisp_Free *SFTB_old_free_list = typename##_free_list; \ - \ - for (SFTB_iii = 0; SFTB_iii < SFTB_limit; SFTB_iii++) \ - { \ - obj_type *SFTB_victim = &(SFTB_current->block[SFTB_iii]); \ - \ - if (LRECORD_FREE_P (SFTB_victim)) \ - { \ - num_free++; \ +#define SWEEP_FIXED_TYPE_BLOCK_1(typename, obj_type, lheader) \ +do { \ + struct typename##_block *SFTB_current; \ + struct typename##_block **SFTB_prev; \ + int SFTB_limit; \ + int num_free = 0, num_used = 0; \ + \ + typename##_free_list = 0; \ + \ + for (SFTB_prev = ¤t_##typename##_block, \ + SFTB_current = current_##typename##_block, \ + SFTB_limit = current_##typename##_block_index; \ + SFTB_current; \ + ) \ + { \ + int SFTB_iii; \ + int SFTB_empty = 1; \ + Lisp_Free *SFTB_old_free_list = typename##_free_list; \ + \ + for (SFTB_iii = 0; SFTB_iii < SFTB_limit; SFTB_iii++) \ + { \ + obj_type *SFTB_victim = &(SFTB_current->block[SFTB_iii]); \ + \ + if (LRECORD_FREE_P (SFTB_victim)) \ + { \ + num_free++; \ PUT_FIXED_TYPE_ON_FREE_LIST (typename, obj_type, SFTB_victim); \ - } \ - else if (C_READONLY_RECORD_HEADER_P (&SFTB_victim->lheader)) \ - { \ - SFTB_empty = 0; \ - num_used++; \ - } \ - else if (! MARKED_RECORD_HEADER_P (&SFTB_victim->lheader)) \ - { \ - num_free++; \ - FREE_FIXED_TYPE (typename, obj_type, SFTB_victim); \ - } \ - else \ - { \ - SFTB_empty = 0; \ - num_used++; \ - UNMARK_##typename (SFTB_victim); \ - } \ - } \ - if (!SFTB_empty) \ - { \ - SFTB_prev = &(SFTB_current->prev); \ - SFTB_current = SFTB_current->prev; \ - } \ - else if (SFTB_current == current_##typename##_block \ - && !SFTB_current->prev) \ - { \ - /* No real point in freeing sole allocation block */ \ - break; \ - } \ - else \ - { \ - struct typename##_block *SFTB_victim_block = SFTB_current; \ - if (SFTB_victim_block == current_##typename##_block) \ - current_##typename##_block_index \ - = countof (current_##typename##_block->block); \ - SFTB_current = SFTB_current->prev; \ - { \ - *SFTB_prev = SFTB_current; \ - xfree (SFTB_victim_block); \ - /* Restore free list to what it was before victim was swept */ \ - typename##_free_list = SFTB_old_free_list; \ - num_free -= SFTB_limit; \ - } \ - } \ - SFTB_limit = countof (current_##typename##_block->block); \ - } \ - \ - gc_count_num_##typename##_in_use = num_used; \ - gc_count_num_##typename##_freelist = num_free; \ + } \ + else if (C_READONLY_RECORD_HEADER_P (&SFTB_victim->lheader)) \ + { \ + SFTB_empty = 0; \ + num_used++; \ + } \ + else if (! MARKED_RECORD_HEADER_P (&SFTB_victim->lheader)) \ + { \ + num_free++; \ + FREE_FIXED_TYPE (typename, obj_type, SFTB_victim); \ + } \ + else \ + { \ + SFTB_empty = 0; \ + num_used++; \ + UNMARK_##typename (SFTB_victim); \ + } \ + } \ + if (!SFTB_empty) \ + { \ + SFTB_prev = &(SFTB_current->prev); \ + SFTB_current = SFTB_current->prev; \ + } \ + else if (SFTB_current == current_##typename##_block \ + && !SFTB_current->prev) \ + { \ + /* No real point in freeing sole allocation block */ \ + break; \ + } \ + else \ + { \ + struct typename##_block *SFTB_victim_block = SFTB_current; \ + if (SFTB_victim_block == current_##typename##_block) \ + current_##typename##_block_index \ + = countof (current_##typename##_block->block); \ + SFTB_current = SFTB_current->prev; \ + { \ + *SFTB_prev = SFTB_current; \ + xfree (SFTB_victim_block); \ + /* Restore free list to what it was before victim was swept */ \ + typename##_free_list = SFTB_old_free_list; \ + num_free -= SFTB_limit; \ + } \ + } \ + SFTB_limit = countof (current_##typename##_block->block); \ + } \ + \ + gc_count_num_##typename##_in_use = num_used; \ + gc_count_num_##typename##_freelist = num_free; \ + COPY_INTO_LRECORD_STATS (typename); \ } while (0) #endif /* !ERROR_CHECK_GC */ @@ -3748,11 +3781,7 @@ ASSERT_VALID_POINTER (XPNTR (cons_car (ptr))); #endif /* ERROR_CHECK_GC */ -#ifdef NEW_GC - free_lrecord (cons); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (cons, Lisp_Cons, ptr); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (cons, cons, Lisp_Cons, ptr); } /* explicitly free a list. You **must make sure** that you have @@ -3887,11 +3916,8 @@ void free_key_data (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (key_data, Lisp_Key_Data, XKEY_DATA (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, key_data, Lisp_Key_Data, + XKEY_DATA (ptr)); } #ifndef NEW_GC @@ -3908,11 +3934,8 @@ void free_button_data (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (button_data, Lisp_Button_Data, XBUTTON_DATA (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, button_data, Lisp_Button_Data, + XBUTTON_DATA (ptr)); } #ifndef NEW_GC @@ -3929,11 +3952,8 @@ void free_motion_data (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (motion_data, Lisp_Motion_Data, XMOTION_DATA (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, motion_data, Lisp_Motion_Data, + XMOTION_DATA (ptr)); } #ifndef NEW_GC @@ -3950,11 +3970,8 @@ void free_process_data (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (process_data, Lisp_Process_Data, XPROCESS_DATA (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, process_data, Lisp_Process_Data, + XPROCESS_DATA (ptr)); } #ifndef NEW_GC @@ -3971,11 +3988,8 @@ void free_timeout_data (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (timeout_data, Lisp_Timeout_Data, XTIMEOUT_DATA (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, timeout_data, Lisp_Timeout_Data, + XTIMEOUT_DATA (ptr)); } #ifndef NEW_GC @@ -3992,11 +4006,8 @@ void free_magic_data (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (magic_data, Lisp_Magic_Data, XMAGIC_DATA (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, magic_data, Lisp_Magic_Data, + XMAGIC_DATA (ptr)); } #ifndef NEW_GC @@ -4013,11 +4024,8 @@ void free_magic_eval_data (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (magic_eval_data, Lisp_Magic_Eval_Data, XMAGIC_EVAL_DATA (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, magic_eval_data, Lisp_Magic_Eval_Data, + XMAGIC_EVAL_DATA (ptr)); } #ifndef NEW_GC @@ -4034,11 +4042,8 @@ void free_eval_data (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (eval_data, Lisp_Eval_Data, XEVAL_DATA (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, eval_data, Lisp_Eval_Data, + XEVAL_DATA (ptr)); } #ifndef NEW_GC @@ -4055,11 +4060,8 @@ void free_misc_user_data (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (misc_user_data, Lisp_Misc_User_Data, XMISC_USER_DATA (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, misc_user_data, Lisp_Misc_User_Data, + XMISC_USER_DATA (ptr)); } #endif /* EVENT_DATA_AS_OBJECTS */ @@ -4083,11 +4085,7 @@ void free_marker (Lisp_Object ptr) { -#ifdef NEW_GC - free_lrecord (ptr); -#else /* not NEW_GC */ - FREE_FIXED_TYPE_WHEN_NOT_IN_GC (marker, Lisp_Marker, XMARKER (ptr)); -#endif /* not NEW_GC */ + FREE_FIXED_TYPE_WHEN_NOT_IN_GC (ptr, marker, Lisp_Marker, XMARKER (ptr)); } @@ -4304,6 +4302,10 @@ void gc_sweep_1 (void) { + /* Reset all statistics to 0. They will be incremented when + sweeping lcrecords, frob-block lrecords and dumped objects. */ + xzero (lrecord_stats); + /* Free all unmarked records. Do this at the very beginning, before anything else, so that the finalize methods can safely examine items in the objects. sweep_lcrecords_1() makes @@ -4466,6 +4468,60 @@ return cons3 (intern (name), make_int (value), tail); } +/* Pluralize a lowercase English word stored in BUF, assuming BUF has + enough space to hold the extra letters (at most 2). */ +static void +pluralize_word (Ascbyte *buf) +{ + Bytecount len = strlen (buf); + int upper = 0; + Ascbyte d, e; + + if (len == 0 || len == 1) + goto pluralize_apostrophe_s; + e = buf[len - 1]; + d = buf[len - 2]; + upper = isupper (e); + e = tolower (e); + d = tolower (d); + if (e == 'y') + { + switch (d) + { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + goto pluralize_s; + default: + buf[len - 1] = (upper ? 'I' : 'i'); + goto pluralize_es; + } + } + else if (e == 's' || e == 'x' || (e == 'h' && (d == 's' || d == 'c'))) + { + pluralize_es: + buf[len++] = (upper ? 'E' : 'e'); + } + pluralize_s: + buf[len++] = (upper ? 'S' : 's'); + buf[len] = '\0'; + return; + + pluralize_apostrophe_s: + buf[len++] = '\''; + goto pluralize_s; +} + +static void +pluralize_and_append (Ascbyte *buf, const Ascbyte *name, const Ascbyte *suffix) +{ + strcpy (buf, name); + pluralize_word (buf); + strcat (buf, suffix); +} + static Lisp_Object object_memory_usage_stats (int set_total_gc_usage) { @@ -4481,7 +4537,6 @@ { Ascbyte buf[255]; const Ascbyte *name = lrecord_implementations_table[i]->name; - int len = strlen (name); if (lrecord_stats[i].bytes_in_use_including_overhead != lrecord_stats[i].bytes_in_use) @@ -4498,87 +4553,70 @@ lrecord_stats[i].bytes_in_use, pl); tgu_val += lrecord_stats[i].bytes_in_use_including_overhead; - - if (name[len-1] == 's') - sprintf (buf, "%ses-used", name); - else - sprintf (buf, "%ss-used", name); + + pluralize_and_append (buf, name, "-used"); pl = gc_plist_hack (buf, lrecord_stats[i].instances_in_use, pl); } } #else /* not NEW_GC */ -#define HACK_O_MATIC(type, name, pl) do { \ - EMACS_INT s = 0; \ - struct type##_block *x = current_##type##_block; \ - while (x) { s += sizeof (*x) + MALLOC_OVERHEAD; x = x->prev; } \ - tgu_val += s; \ - (pl) = gc_plist_hack ((name), s, (pl)); \ +#define HACK_O_MATIC(type, name, pl) \ +do { \ + COUNT_FROB_BLOCK_USAGE (type); \ + tgu_val += s; \ + (pl) = gc_plist_hack ((name), s, (pl)); \ +} while (0) + +#define FROB(type) \ +do { \ + COUNT_FROB_BLOCK_USAGE (type); \ + tgu_val += s; \ } while (0) + FROB (extent); + FROB (event); + FROB (marker); + FROB (float); +#ifdef HAVE_BIGNUM + FROB (bignum); +#endif /* HAVE_BIGNUM */ +#ifdef HAVE_RATIO + FROB (ratio); +#endif /* HAVE_RATIO */ +#ifdef HAVE_BIGFLOAT + FROB (bigfloat); +#endif /* HAVE_BIGFLOAT */ + FROB (compiled_function); + FROB (symbol); + FROB (cons); + +#undef FROB + for (i = 0; i < lrecord_type_count; i++) { - if (lcrecord_stats[i].bytes_in_use != 0 - || lcrecord_stats[i].bytes_freed != 0 - || lcrecord_stats[i].instances_on_free_list != 0) + if (lrecord_stats[i].bytes_in_use != 0 + || lrecord_stats[i].bytes_freed != 0 + || lrecord_stats[i].instances_on_free_list != 0) { Ascbyte buf[255]; const Ascbyte *name = lrecord_implementations_table[i]->name; - int len = strlen (name); sprintf (buf, "%s-storage", name); - pl = gc_plist_hack (buf, lcrecord_stats[i].bytes_in_use, pl); - tgu_val += lcrecord_stats[i].bytes_in_use; - /* Okay, simple pluralization check for `symbol-value-varalias' */ - if (name[len-1] == 's') - sprintf (buf, "%ses-freed", name); - else - sprintf (buf, "%ss-freed", name); - if (lcrecord_stats[i].instances_freed != 0) - pl = gc_plist_hack (buf, lcrecord_stats[i].instances_freed, pl); - if (name[len-1] == 's') - sprintf (buf, "%ses-on-free-list", name); - else - sprintf (buf, "%ss-on-free-list", name); - if (lcrecord_stats[i].instances_on_free_list != 0) - pl = gc_plist_hack (buf, lcrecord_stats[i].instances_on_free_list, + pl = gc_plist_hack (buf, lrecord_stats[i].bytes_in_use, pl); + tgu_val += lrecord_stats[i].bytes_in_use; + pluralize_and_append (buf, name, "-freed"); + if (lrecord_stats[i].instances_freed != 0) + pl = gc_plist_hack (buf, lrecord_stats[i].instances_freed, pl); + pluralize_and_append (buf, name, "-on-free-list"); + if (lrecord_stats[i].instances_on_free_list != 0) + pl = gc_plist_hack (buf, lrecord_stats[i].instances_on_free_list, pl); - if (name[len-1] == 's') - sprintf (buf, "%ses-used", name); - else - sprintf (buf, "%ss-used", name); - pl = gc_plist_hack (buf, lcrecord_stats[i].instances_in_use, pl); + pluralize_and_append (buf, name, "-used"); + pl = gc_plist_hack (buf, lrecord_stats[i].instances_in_use, pl); } } - HACK_O_MATIC (extent, "extent-storage", pl); - pl = gc_plist_hack ("extents-free", gc_count_num_extent_freelist, pl); - pl = gc_plist_hack ("extents-used", gc_count_num_extent_in_use, pl); - HACK_O_MATIC (event, "event-storage", pl); - pl = gc_plist_hack ("events-free", gc_count_num_event_freelist, pl); - pl = gc_plist_hack ("events-used", gc_count_num_event_in_use, pl); - HACK_O_MATIC (marker, "marker-storage", pl); - pl = gc_plist_hack ("markers-free", gc_count_num_marker_freelist, pl); - pl = gc_plist_hack ("markers-used", gc_count_num_marker_in_use, pl); - HACK_O_MATIC (float, "float-storage", pl); - pl = gc_plist_hack ("floats-free", gc_count_num_float_freelist, pl); - pl = gc_plist_hack ("floats-used", gc_count_num_float_in_use, pl); -#ifdef HAVE_BIGNUM - HACK_O_MATIC (bignum, "bignum-storage", pl); - pl = gc_plist_hack ("bignums-free", gc_count_num_bignum_freelist, pl); - pl = gc_plist_hack ("bignums-used", gc_count_num_bignum_in_use, pl); -#endif /* HAVE_BIGNUM */ -#ifdef HAVE_RATIO - HACK_O_MATIC (ratio, "ratio-storage", pl); - pl = gc_plist_hack ("ratios-free", gc_count_num_ratio_freelist, pl); - pl = gc_plist_hack ("ratios-used", gc_count_num_ratio_in_use, pl); -#endif /* HAVE_RATIO */ -#ifdef HAVE_BIGFLOAT - HACK_O_MATIC (bigfloat, "bigfloat-storage", pl); - pl = gc_plist_hack ("bigfloats-free", gc_count_num_bigfloat_freelist, pl); - pl = gc_plist_hack ("bigfloats-used", gc_count_num_bigfloat_in_use, pl); -#endif /* HAVE_BIGFLOAT */ HACK_O_MATIC (string, "string-header-storage", pl); pl = gc_plist_hack ("long-strings-total-length", gc_count_string_total_size @@ -4593,20 +4631,6 @@ pl = gc_plist_hack ("short-strings-used", gc_count_num_short_string_in_use, pl); - HACK_O_MATIC (compiled_function, "compiled-function-storage", pl); - pl = gc_plist_hack ("compiled-functions-free", - gc_count_num_compiled_function_freelist, pl); - pl = gc_plist_hack ("compiled-functions-used", - gc_count_num_compiled_function_in_use, pl); - - HACK_O_MATIC (symbol, "symbol-storage", pl); - pl = gc_plist_hack ("symbols-free", gc_count_num_symbol_freelist, pl); - pl = gc_plist_hack ("symbols-used", gc_count_num_symbol_in_use, pl); - - HACK_O_MATIC (cons, "cons-storage", pl); - pl = gc_plist_hack ("conses-free", gc_count_num_cons_freelist, pl); - pl = gc_plist_hack ("conses-used", gc_count_num_cons_in_use, pl); - #undef HACK_O_MATIC #endif /* NEW_GC */ @@ -4683,8 +4707,9 @@ Fcons (make_int (gc_count_num_marker_in_use), make_int (gc_count_num_marker_freelist)), make_int (gc_count_string_total_size), - make_int (lcrecord_stats[lrecord_type_vector].bytes_in_use + - lcrecord_stats[lrecord_type_vector].bytes_freed), + make_int (lrecord_stats[lrecord_type_vector].bytes_in_use + + lrecord_stats[lrecord_type_vector].bytes_freed + + lrecord_stats[lrecord_type_vector].bytes_on_free_list), object_memory_usage_stats (1)); #endif /* not NEW_GC */ #else /* not ALLOC_TYPE_STATS */
--- a/src/dumper.c Mon Feb 22 06:49:30 2010 -0600 +++ b/src/dumper.c Tue Feb 23 07:28:35 2010 -0600 @@ -1,7 +1,7 @@ /* Portable data dumper for XEmacs. Copyright (C) 1999-2000,2004 Olivier Galibert Copyright (C) 2001 Martin Buchholz - Copyright (C) 2001, 2002, 2003, 2004, 2005 Ben Wing. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2010 Ben Wing. This file is part of XEmacs. @@ -253,8 +253,20 @@ for (i=0; i<rt->count; i++) { struct lrecord_header *lh = * (struct lrecord_header **) p; +#ifdef ALLOC_TYPE_STATS + if (C_READONLY_RECORD_HEADER_P (lh)) + tick_lrecord_stats (lh, ALLOC_IN_USE); + + else + { + tick_lrecord_stats (lh, MARKED_RECORD_HEADER_P (lh) ? + ALLOC_IN_USE : ALLOC_ON_FREE_LIST); + UNMARK_RECORD_HEADER (lh); + } +#else /* not ALLOC_TYPE_STATS */ if (! C_READONLY_RECORD_HEADER_P (lh)) UNMARK_RECORD_HEADER (lh); +#endif /* (not) ALLOC_TYPE_STATS */ p += sizeof (EMACS_INT); } } else
--- a/src/events.c Mon Feb 22 06:49:30 2010 -0600 +++ b/src/events.c Tue Feb 23 07:28:35 2010 -0600 @@ -2134,11 +2134,12 @@ pointer points to random memory, often filled with 0, sometimes not. */ /* #### Chuck, do we still need this crap? */ +#ifdef HAVE_TOOLBARS assert (NILP (ret_obj1) || GLYPHP (ret_obj1) -#ifdef HAVE_TOOLBARS - || TOOLBAR_BUTTONP (ret_obj1) + || TOOLBAR_BUTTONP (ret_obj1)); +#else + assert (NILP (ret_obj1) || GLYPHP (ret_obj1)); #endif - ); assert (NILP (ret_obj2) || EXTENTP (ret_obj2) || CONSP (ret_obj2)); if (char_x)
--- a/src/lrecord.h Mon Feb 22 06:49:30 2010 -0600 +++ b/src/lrecord.h Tue Feb 23 07:28:35 2010 -0600 @@ -523,6 +523,16 @@ #else /* not NEW_GC */ +enum lrecord_alloc_status +{ + ALLOC_IN_USE, + ALLOC_FREE, + ALLOC_ON_FREE_LIST +}; + +void tick_lrecord_stats (const struct lrecord_header *h, + enum lrecord_alloc_status status); + #define LRECORD_FREE_P(ptr) \ (((struct lrecord_header *) ptr)->type == lrecord_type_free)
--- a/tests/ChangeLog Mon Feb 22 06:49:30 2010 -0600 +++ b/tests/ChangeLog Tue Feb 23 07:28:35 2010 -0600 @@ -3,6 +3,17 @@ * reproduce-crashes.el (8): objects*.[ch] -> fontcolor*.[ch]. +2010-02-22 Ben Wing <ben@xemacs.org> + + * automated/syntax-tests.el: + Use Known-Bug-Expect-Error, not Known-Bug-Expect-Failure, when + error expected; else test suite will abort this file. + +2010-02-22 Ben Wing <ben@xemacs.org> + + * automated/test-harness.el (test-harness-from-buffer): + Remove unused binding. + 2010-02-15 Ben Wing <ben@xemacs.org> * automated/search-tests.el (let):
--- a/tests/automated/syntax-tests.el Mon Feb 22 06:49:30 2010 -0600 +++ b/tests/automated/syntax-tests.el Tue Feb 23 07:28:35 2010 -0600 @@ -192,8 +192,9 @@ (Assert (backward-up-list-moves-point-from-to 20 3)) (Known-Bug-Expect-Failure (Assert (backward-up-list-moves-point-from-to 22 3))) - (Known-Bug-Expect-Failure - (Assert (backward-up-list-moves-point-from-to 23 3))) + (Known-Bug-Expect-Error scan-error + (Assert (backward-up-list-moves-point-from-to 23 3)) + ) (Assert (backward-up-list-moves-point-from-to 24 3)) ;; This is maybe a little tricky, since we don't expect the position ;; check to happen -- so use an illegal expected position
--- a/tests/automated/test-harness.el Mon Feb 22 06:49:30 2010 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,840 +0,0 @@ -;; test-harness.el --- Run Emacs Lisp test suites. - -;;; Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc. -;;; Copyright (C) 2002, 2010 Ben Wing. - -;; Author: Martin Buchholz -;; Maintainer: Stephen J. Turnbull <stephen@xemacs.org> -;; Keywords: testing - -;; This file is part of XEmacs. - -;; XEmacs is free software; you can redistribute it and/or modify it -;; under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; XEmacs is distributed in the hope that it will be useful, but -;; WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;; General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with XEmacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;;; Synched up with: Not in FSF. - -;;; Commentary: - -;;; A test suite harness for testing XEmacs. -;;; The actual tests are in other files in this directory. -;;; Basically you just create files of emacs-lisp, and use the -;;; Assert, Check-Error, Check-Message, and Check-Error-Message functions -;;; to create tests. See `test-harness-from-buffer' below. -;;; Don't suppress tests just because they're due to known bugs not yet -;;; fixed -- use the Known-Bug-Expect-Failure and -;;; Implementation-Incomplete-Expect-Failure wrapper macros to mark them. -;;; A lot of the tests we run push limits; suppress Ebola message with the -;;; Ignore-Ebola wrapper macro. -;;; Some noisy code will call `message'. Output from `message' can be -;;; suppressed with the Silence-Message macro. Functions that are known to -;;; issue messages include `write-region', `find-tag', `tag-loop-continue', -;;; `insert', and `mark-whole-buffer'. N.B. The Silence-Message macro -;;; currently does not suppress the newlines printed by `message'. -;;; Definitely do not use Silence-Message with Check-Message. -;;; In general it should probably only be used on code that prepares for a -;;; test, not on tests. -;;; -;;; You run the tests using M-x test-emacs-test-file, -;;; or $(EMACS) -batch -l .../test-harness.el -f batch-test-emacs file ... -;;; which is run for you by the `make check' target in the top-level Makefile. - -(require 'bytecomp) - -(defvar unexpected-test-suite-failures 0 - "Cumulative number of unexpected failures since test-harness was loaded. - -\"Unexpected failures\" are those caught by a generic handler established -outside of the test context. As such they involve an abort of the test -suite for the file being tested. - -They often occur during preparation of a test or recording of the results. -For example, an executable used to generate test data might not be present -on the system, or a system error might occur while reading a data file.") - -(defvar unexpected-test-suite-failure-files nil - "List of test files causing unexpected failures.") - -;; Declared for dynamic scope; _do not_ initialize here. -(defvar unexpected-test-file-failures) - -(defvar test-harness-bug-expected nil - "Non-nil means a bug is expected; backtracing/debugging should not happen.") - -(defvar test-harness-test-compiled nil - "Non-nil means the test code was compiled before execution. - -You probably should not make tests depend on compilation. -However, it can be useful to conditionally change messages based on whether -the code was compiled or not. For example, the case that motivated the -implementation of this variable: - -\(when test-harness-test-compiled - ;; this ha-a-ack depends on the failing compiled test coming last - \(setq test-harness-failure-tag - \"KNOWN BUG - fix reverted; after 2003-10-31 notify stephen\n\"))") - -(defvar test-harness-verbose - (and (not noninteractive) (> (device-baud-rate) search-slow-speed)) - "*Non-nil means print messages describing progress of emacs-tester.") - -(defvar test-harness-unexpected-error-enter-debugger debug-on-error - "*Non-nil means enter debugger when an unexpected error occurs. -Only applies interactively. Normally true if `debug-on-error' has been set. -See also `test-harness-assertion-failure-enter-debugger' and -`test-harness-unexpected-error-show-backtrace'.") - -(defvar test-harness-assertion-failure-enter-debugger debug-on-error - "*Non-nil means enter debugger when an assertion failure occurs. -Only applies interactively. Normally true if `debug-on-error' has been set. -See also `test-harness-unexpected-error-enter-debugger' and -`test-harness-assertion-failure-show-backtrace'.") - -(defvar test-harness-unexpected-error-show-backtrace t - "*Non-nil means show backtrace upon unexpected error. -Only applies when debugger is not entered. Normally true by default. See also -`test-harness-unexpected-error-enter-debugger' and -`test-harness-assertion-failure-show-backtrace'.") - -(defvar test-harness-assertion-failure-show-backtrace stack-trace-on-error - "*Non-nil means show backtrace upon assertion failure. -Only applies when debugger is not entered. Normally true if -`stack-trace-on-error' has been set. See also -`test-harness-assertion-failure-enter-debugger' and -`test-harness-unexpected-error-show-backtrace'.") - -(defvar test-harness-file-results-alist nil - "Each element is a list (FILE SUCCESSES TESTS). -The order is the reverse of the order in which tests are run. - -FILE is a string naming the test file. -SUCCESSES is a non-negative integer, the number of successes. -TESTS is a non-negative integer, the number of tests run.") - -(defvar test-harness-risk-infloops nil - "*Non-nil to run tests that may loop infinitely in buggy implementations.") - -(defvar test-harness-current-file nil) - -(defvar emacs-lisp-file-regexp (purecopy "\\.el\\'") - "*Regexp which matches Emacs Lisp source files.") - -(defconst test-harness-file-summary-template - (format "%%-%ds %%%dd of %%%dd tests successful (%%3d%%%%)." - (length "byte-compiler-tests.el:") ; use the longest file name - 5 - 5) - "Format for summary lines printed after each file is run.") - -(defconst test-harness-null-summary-template - (format "%%-%ds No tests run." - (length "byte-compiler-tests.el:")) ; use the longest file name - "Format for \"No tests\" lines printed after a file is run.") - -(defconst test-harness-aborted-summary-template - (format "%%-%ds %%%dd tests completed (aborted)." - (length "byte-compiler-tests.el:") ; use the longest file name - 5) - "Format for summary lines printed after a test run on a file was aborted.") - -;;;###autoload -(defun test-emacs-test-file (filename) - "Test a file of Lisp code named FILENAME. -The output file's name is made by appending `c' to the end of FILENAME." - (interactive - (let ((file buffer-file-name) - (file-name nil) - (file-dir nil)) - (and file - (eq (cdr (assq 'major-mode (buffer-local-variables))) - 'emacs-lisp-mode) - (setq file-name (file-name-nondirectory file) - file-dir (file-name-directory file))) - (list (read-file-name "Test file: " file-dir nil nil file-name)))) - ;; Expand now so we get the current buffer's defaults - (setq filename (expand-file-name filename)) - - ;; If we're testing a file that's in a buffer and is modified, offer - ;; to save it first. - (or noninteractive - (let ((b (get-file-buffer (expand-file-name filename)))) - (if (and b (buffer-modified-p b) - (y-or-n-p (format "save buffer %s first? " (buffer-name b)))) - (save-excursion (set-buffer b) (save-buffer))))) - - (if (or noninteractive test-harness-verbose) - (message "Testing %s..." filename)) - (let ((test-harness-current-file filename) - input-buffer) - (save-excursion - (setq input-buffer (get-buffer-create " *Test Input*")) - (set-buffer input-buffer) - (erase-buffer) - (insert-file-contents filename) - ;; Run hooks including the uncompression hook. - ;; If they change the file name, then change it for the output also. - (let ((buffer-file-name filename) - (default-major-mode 'emacs-lisp-mode) - (enable-local-eval nil)) - (normal-mode) - (setq filename buffer-file-name))) - (test-harness-from-buffer input-buffer filename) - (kill-buffer input-buffer) - )) - -(defsubst test-harness-assertion-failure-do-debug (error-info) - "Maybe enter debugger or display a backtrace on assertion failure. -ERROR-INFO is a cons of the args (SIG . DATA) that were passed to `signal'. -The debugger will be entered if noninteractive and -`test-harness-unexpected-error-enter-debugger' is non-nil; else, a -backtrace will be displayed if `test-harness-unexpected-error-show-backtrace' -is non-nil." - (when (not test-harness-bug-expected) - (cond ((and (not noninteractive) - test-harness-assertion-failure-enter-debugger) - (funcall debugger 'error error-info)) - (test-harness-assertion-failure-show-backtrace - (backtrace nil t))))) - -(defsubst test-harness-unexpected-error-do-debug (error-info) - "Maybe enter debugger or display a backtrace on unexpected error. -ERROR-INFO is a cons of the args (SIG . DATA) that were passed to `signal'. -The debugger will be entered if noninteractive and -`test-harness-unexpected-error-enter-debugger' is non-nil; else, a -backtrace will be displayed if `test-harness-unexpected-error-show-backtrace' -is non-nil." - (when (not test-harness-bug-expected) - (cond ((and (not noninteractive) - test-harness-unexpected-error-enter-debugger) - (funcall debugger 'error error-info)) - (test-harness-unexpected-error-show-backtrace - (backtrace nil t))))) - -(defsubst test-harness-unexpected-error-condition-handler (error-info context-msg) - "Condition handler for when unexpected errors occur. -Useful in conjunction with `call-with-condition-handler'. ERROR-INFO is the -value passed to the condition handler. CONTEXT-MSG is a string indicating -the context in which the unexpected error occurred. A message is outputted -including CONTEXT-MSG in it, `unexpected-test-file-failures' is incremented, -and `test-harness-unexpected-error-do-debug' is called, which may enter the -debugger or output a backtrace, depending on the settings of -`test-harness-unexpected-error-enter-debugger' and -`test-harness-unexpected-error-show-backtrace'. - -The function returns normally, which causes error-handling processing to -continue; if you want to catch the error, you also need to wrap everything -in `condition-case'. See also `test-harness-error-wrap', which does this -wrapping." - (incf unexpected-test-file-failures) - (princ (format "Unexpected error %S while %s\n" - error-info context-msg)) - (message "Unexpected error %S while %s." error-info context-msg) - (test-harness-unexpected-error-do-debug error-info)) - -(defmacro test-harness-error-wrap (context-msg abort-msg &rest body) - "Wrap BODY so that unexpected errors are caught. -The debugger will be entered if noninteractive and -`test-harness-unexpected-error-enter-debugger' is non-nil; else, a backtrace -will be displayed if `test-harness-unexpected-error-show-backtrace' is -non-nil. CONTEXT-MSG is displayed as part of a message shown before entering -the debugger or showing a backtrace, and ABORT-MSG, if non-nil, is displayed -afterwards. See " - `(condition-case nil - (call-with-condition-handler - #'(lambda (error-info) - (test-harness-unexpected-error-condition-handler - error-info ,context-msg)) - #'(lambda () - ,@body)) - (error ,(if abort-msg `(message ,abort-msg) nil)))) - -(defun test-harness-read-from-buffer (buffer) - "Read forms from BUFFER, and turn it into a lambda test form." - (let ((body nil)) - (goto-char (point-min) buffer) - (condition-case nil - (call-with-condition-handler - #'(lambda (error-info) - ;; end-of-file is expected, so don't output error or backtrace - ;; or enter debugger in this case. - (unless (eq 'end-of-file (car error-info)) - (test-harness-unexpected-error-condition-handler - error-info "reading forms from buffer"))) - #'(lambda () - (while t - (setq body (cons (read buffer) body))))) - (error nil)) - `(lambda () - (defvar passes) - (defvar assertion-failures) - (defvar no-error-failures) - (defvar wrong-error-failures) - (defvar missing-message-failures) - (defvar other-failures) - - (defvar trick-optimizer) - - ,@(nreverse body)))) - -(defun test-harness-from-buffer (inbuffer filename) - "Run tests in buffer INBUFFER, visiting FILENAME." - (defvar trick-optimizer) - (let ((passes 0) - (assertion-failures 0) - (no-error-failures 0) - (wrong-error-failures 0) - (missing-message-failures 0) - (other-failures 0) - (unexpected-test-file-failures 0) - - ;; #### perhaps this should be a defvar, and output at the very end - ;; OTOH, this way AC types can use a null EMACSPACKAGEPATH to find - ;; what stuff is needed, and ways to avoid using them - (skipped-test-reasons (make-hash-table :test 'equal)) - - (trick-optimizer nil) - (debug-on-error t) - (pass-stream nil)) - (with-output-to-temp-buffer "*Test-Log*" - (princ (format "Testing %s...\n\n" filename)) - - (defconst test-harness-failure-tag "FAIL") - (defconst test-harness-success-tag "PASS") - -;;;;; BEGIN DEFINITION OF MACROS USEFUL IN TEST CODE - - (defmacro Known-Bug-Expect-Failure (&rest body) - "Wrap a BODY that consists of tests that are known to fail. -This causes messages to be printed on failure indicating that this is expected, -and on success indicating that this is unexpected." - `(let ((test-harness-bug-expected t) - (test-harness-failure-tag "KNOWN BUG") - (test-harness-success-tag "PASS (FAILURE EXPECTED)")) - ,@body)) - - (defmacro Known-Bug-Expect-Error (expected-error &rest body) - "Wrap a BODY that consists of tests that are known to trigger an error. -This causes messages to be printed on failure indicating that this is expected, -and on success indicating that this is unexpected." - (let ((quoted-body (if (= 1 (length body)) - `(quote ,(car body)) `(quote (progn ,@body))))) - `(let ((test-harness-bug-expected t) - (test-harness-failure-tag "KNOWN BUG") - (test-harness-success-tag "PASS (FAILURE EXPECTED)")) - (condition-case error-info - (progn - (setq trick-optimizer (progn ,@body)) - (Print-Pass - "%S executed successfully, but expected error %S" - ,quoted-body - ',expected-error) - (incf passes)) - (,expected-error - (Print-Failure "%S ==> error %S, as expected" - ,quoted-body ',expected-error) - (incf no-error-failures)) - (error - (Print-Failure "%S ==> expected error %S, got error %S instead" - ,quoted-body ',expected-error error-info) - (incf wrong-error-failures)))))) - - (defmacro Implementation-Incomplete-Expect-Failure (&rest body) - "Wrap a BODY containing tests that are known to fail due to incomplete code. -This causes messages to be printed on failure indicating that the -implementation is incomplete (and hence the failure is expected); and on -success indicating that this is unexpected." - `(let ((test-harness-bug-expected t) - (test-harness-failure-tag "IMPLEMENTATION INCOMPLETE") - (test-harness-success-tag "PASS (FAILURE EXPECTED)")) - ,@body)) - - (defun Print-Failure (fmt &rest args) - (setq fmt (format "%s: %s" test-harness-failure-tag fmt)) - (if (noninteractive) (apply #'message fmt args)) - (princ (concat (apply #'format fmt args) "\n"))) - - (defun Print-Pass (fmt &rest args) - (setq fmt (format "%s: %s" test-harness-success-tag fmt)) - (and test-harness-verbose - (princ (concat (apply #'format fmt args) "\n")))) - - (defun Print-Skip (test reason &optional fmt &rest args) - (setq fmt (concat "SKIP: %S BECAUSE %S" fmt)) - (princ (concat (apply #'format fmt test reason args) "\n"))) - - (defmacro Skip-Test-Unless (condition reason description &rest body) - "Unless CONDITION is satisfied, skip test BODY. -REASON is a description of the condition failure, and must be unique (it -is used as a hash key). DESCRIPTION describes the tests that were skipped. -BODY is a sequence of expressions and may contain several tests." - `(if (not ,condition) - (let ((count (gethash ,reason skipped-test-reasons))) - (puthash ,reason (if (null count) 1 (1+ count)) - skipped-test-reasons) - (Print-Skip ,description ,reason)) - ,@body)) - - (defmacro Assert (assertion &optional failing-case description) - "Test passes if ASSERTION is true. -Optional FAILING-CASE describes the particular failure. Optional -DESCRIPTION describes the assertion; by default, the unevalated assertion -expression is given. FAILING-CASE and DESCRIPTION are useful when Assert -is used in a loop." - (let ((description - (or description `(quote ,assertion)))) - `(condition-case nil - (call-with-condition-handler - #'(lambda (error-info) - (if (eq 'cl-assertion-failed (car error-info)) - (progn - (Print-Failure - (if ,failing-case - "Assertion failed: %S; failing case = %S" - "Assertion failed: %S") - ,description ,failing-case) - (incf assertion-failures) - (test-harness-assertion-failure-do-debug error-info)) - (Print-Failure - (if ,failing-case - "%S ==> error: %S; failing case = %S" - "%S ==> error: %S") - ,description error-info ,failing-case) - (incf other-failures) - (test-harness-unexpected-error-do-debug error-info))) - #'(lambda () - (assert ,assertion) - (Print-Pass "%S" ,description) - (incf passes))) - (cl-assertion-failed nil)))) - -;;;;; BEGIN DEFINITION OF SPECIFIC KINDS OF ASSERT MACROS - - (defmacro Assert-test (test testval expected &optional failing-case - description) - "Test passes if TESTVAL compares correctly to EXPECTED using TEST. -TEST should be a two-argument predicate (i.e. a function of two arguments -that returns t or nil), such as `eq', `eql', `equal', `equalp', `=', `<=', -'>', 'file-newer-than-file-p' etc. Optional FAILING-CASE describes the -particular failure; any value given here will be concatenated with a phrase -describing the expected and actual values of the comparison. Optional -DESCRIPTION describes the assertion; by default, the unevalated comparison -expressions are given. FAILING-CASE and DESCRIPTION are useful when Assert -is used in a loop." - (let* ((assertion `(,test ,testval ,expected)) - (failmsg `(format "%S should be `%s' to %S but isn't" - ,testval ',test ,expected)) - (failmsg2 (if failing-case `(concat - (format "%S, " ,failing-case) - ,failmsg) - failmsg))) - `(Assert ,assertion ,failmsg2 ,description))) - - (defmacro Assert-test-not (test testval expected &optional failing-case - description) - "Test passes if TESTVAL does not compare correctly to EXPECTED using TEST. -TEST should be a two-argument predicate (i.e. a function of two arguments -that returns t or nil), such as `eq', `eql', `equal', `equalp', `=', `<=', -'>', 'file-newer-than-file-p' etc. Optional FAILING-CASE describes the -particular failure; any value given here will be concatenated with a phrase -describing the expected and actual values of the comparison. Optional -DESCRIPTION describes the assertion; by default, the unevalated comparison -expressions are given. FAILING-CASE and DESCRIPTION are useful when Assert -is used in a loop." - (let* ((assertion `(not (,test ,testval ,expected))) - (failmsg `(format "%S shouldn't be `%s' to %S but is" - ,testval ',test ,expected)) - (failmsg2 (if failing-case `(concat - (format "%S, " ,failing-case) - ,failmsg) - failmsg))) - `(Assert ,assertion ,failmsg2 ,description))) - - ;; Specific versions of `Assert-test'. These are just convenience - ;; functions, functioning identically to `Assert-test', and duplicating - ;; the doc string for each would be too annoying. - (defmacro Assert-eq (testval expected &optional failing-case - description) - `(Assert-test eq ,testval ,expected ,failing-case ,description)) - (defmacro Assert-eql (testval expected &optional failing-case - description) - `(Assert-test eql ,testval ,expected ,failing-case ,description)) - (defmacro Assert-equal (testval expected &optional failing-case - description) - `(Assert-test equal ,testval ,expected ,failing-case ,description)) - (defmacro Assert-equalp (testval expected &optional failing-case - description) - `(Assert-test equalp ,testval ,expected ,failing-case ,description)) - (defmacro Assert-string= (testval expected &optional failing-case - description) - `(Assert-test string= ,testval ,expected ,failing-case ,description)) - (defmacro Assert= (testval expected &optional failing-case - description) - `(Assert-test = ,testval ,expected ,failing-case ,description)) - (defmacro Assert<= (testval expected &optional failing-case - description) - `(Assert-test <= ,testval ,expected ,failing-case ,description)) - - ;; Specific versions of `Assert-test-not'. These are just convenience - ;; functions, functioning identically to `Assert-test-not', and - ;; duplicating the doc string for each would be too annoying. - (defmacro Assert-not-eq (testval expected &optional failing-case - description) - `(Assert-test-not eq ,testval ,expected ,failing-case ,description)) - (defmacro Assert-not-eql (testval expected &optional failing-case - description) - `(Assert-test-not eql ,testval ,expected ,failing-case ,description)) - (defmacro Assert-not-equal (testval expected &optional failing-case - description) - `(Assert-test-not equal ,testval ,expected ,failing-case ,description)) - (defmacro Assert-not-equalp (testval expected &optional failing-case - description) - `(Assert-test-not equalp ,testval ,expected ,failing-case ,description)) - (defmacro Assert-not-string= (testval expected &optional failing-case - description) - `(Assert-test-not string= ,testval ,expected ,failing-case ,description)) - (defmacro Assert-not= (testval expected &optional failing-case - description) - `(Assert-test-not = ,testval ,expected ,failing-case ,description)) - - (defmacro Check-Error (expected-error &rest body) - (let ((quoted-body (if (= 1 (length body)) - `(quote ,(car body)) `(quote (progn ,@body))))) - `(condition-case error-info - (progn - (setq trick-optimizer (progn ,@body)) - (Print-Failure "%S executed successfully, but expected error %S" - ,quoted-body - ',expected-error) - (incf no-error-failures)) - (,expected-error - (Print-Pass "%S ==> error %S, as expected" - ,quoted-body ',expected-error) - (incf passes)) - (error - (Print-Failure "%S ==> expected error %S, got error %S instead" - ,quoted-body ',expected-error error-info) - (incf wrong-error-failures))))) - - (defmacro Check-Error-Message (expected-error expected-error-regexp - &rest body) - (let ((quoted-body (if (= 1 (length body)) - `(quote ,(car body)) `(quote (progn ,@body))))) - `(condition-case error-info - (progn - (setq trick-optimizer (progn ,@body)) - (Print-Failure "%S executed successfully, but expected error %S" - ,quoted-body ',expected-error) - (incf no-error-failures)) - (,expected-error - ;; #### Damn, this binding doesn't capture frobs, eg, for - ;; invalid_argument() ... you only get the REASON. And for - ;; wrong_type_argument(), there's no reason only FROBs. - ;; If this gets fixed, fix tests in regexp-tests.el. - (let ((error-message (second error-info))) - (if (string-match ,expected-error-regexp error-message) - (progn - (Print-Pass "%S ==> error %S %S, as expected" - ,quoted-body error-message ',expected-error) - (incf passes)) - (Print-Failure "%S ==> got error %S as expected, but error message %S did not match regexp %S" - ,quoted-body ',expected-error error-message ,expected-error-regexp) - (incf wrong-error-failures)))) - (error - (Print-Failure "%S ==> expected error %S, got error %S instead" - ,quoted-body ',expected-error error-info) - (incf wrong-error-failures))))) - - ;; Do not use this with Silence-Message. - (defmacro Check-Message (expected-message-regexp &rest body) - (Skip-Test-Unless (fboundp 'defadvice) - "can't defadvice" - expected-message-regexp - (let ((quoted-body (if (= 1 (length body)) - `(quote ,(car body)) - `(quote (progn ,@body))))) - `(let ((messages "")) - (defadvice message (around collect activate) - (defvar messages) - (let ((msg-string (apply 'format (ad-get-args 0)))) - (setq messages (concat messages msg-string)) - msg-string)) - (ignore-errors - (call-with-condition-handler - #'(lambda (error-info) - (Print-Failure "%S ==> unexpected error %S" - ,quoted-body error-info) - (incf other-failures) - (test-harness-unexpected-error-do-debug error-info)) - #'(lambda () - (setq trick-optimizer (progn ,@body)) - (if (string-match ,expected-message-regexp messages) - (progn - (Print-Pass - "%S ==> value %S, message %S, matching %S, as expected" - ,quoted-body trick-optimizer messages - ',expected-message-regexp) - (incf passes)) - (Print-Failure - "%S ==> value %S, message %S, NOT matching expected %S" - ,quoted-body trick-optimizer messages - ',expected-message-regexp) - (incf missing-message-failures))))) - (ad-unadvise 'message))))) - - ;; #### Perhaps this should override `message' itself, too? - (defmacro Silence-Message (&rest body) - `(flet ((append-message (&rest args) ()) - (clear-message (&rest args) ())) - ,@body)) - - (defmacro Ignore-Ebola (&rest body) - `(let ((debug-issue-ebola-notices -42)) ,@body)) - - (defun Int-to-Marker (pos) - (save-excursion - (set-buffer standard-output) - (save-excursion - (goto-char pos) - (point-marker)))) - - (princ "Testing Interpreted Lisp\n\n") - - (test-harness-error-wrap - "executing interpreted code" - "Test suite execution aborted." - (funcall (test-harness-read-from-buffer inbuffer))) - - (princ "\nTesting Compiled Lisp\n\n") - - (let (code - (test-harness-test-compiled t)) - (test-harness-error-wrap - "byte-compiling code" nil - (setq code - ;; our lisp code is often intentionally dubious, - ;; so throw away _all_ the byte compiler warnings. - (letf (((symbol-function 'byte-compile-warn) - 'ignore)) - (byte-compile (test-harness-read-from-buffer - inbuffer)))) - ) - - (test-harness-error-wrap "executing byte-compiled code" - "Test suite execution aborted." - (if code (funcall code))) - ) - (princ (format "\nSUMMARY for %s:\n" filename)) - (princ (format "\t%5d passes\n" passes)) - (princ (format "\t%5d assertion failures\n" assertion-failures)) - (princ (format "\t%5d errors that should have been generated, but weren't\n" no-error-failures)) - (princ (format "\t%5d wrong-error failures\n" wrong-error-failures)) - (princ (format "\t%5d missing-message failures\n" missing-message-failures)) - (princ (format "\t%5d other failures\n" other-failures)) - (let* ((total (+ passes - assertion-failures - no-error-failures - wrong-error-failures - missing-message-failures - other-failures)) - (basename (file-name-nondirectory filename)) - (summary-msg - (cond ((> unexpected-test-file-failures 0) - (format test-harness-aborted-summary-template - (concat basename ":") total)) - ((> total 0) - (format test-harness-file-summary-template - (concat basename ":") - passes total (/ (* 100 passes) total))) - (t - (format test-harness-null-summary-template - (concat basename ":"))))) - (reasons "")) - (maphash (lambda (key value) - (setq reasons - (concat reasons - (format "\n %d tests skipped because %s." - value key)))) - skipped-test-reasons) - (when (> (length reasons) 1) - (setq summary-msg (concat summary-msg reasons " - It may be that XEmacs cannot find your installed packages. Set - EMACSPACKAGEPATH to the package hierarchy root or configure with - --package-path to enable the skipped tests."))) - (setq test-harness-file-results-alist - (cons (list filename passes total) - test-harness-file-results-alist)) - (message "%s" summary-msg)) - (when (> unexpected-test-file-failures 0) - (setq unexpected-test-suite-failure-files - (cons filename unexpected-test-suite-failure-files)) - (setq unexpected-test-suite-failures - (+ unexpected-test-suite-failures unexpected-test-file-failures)) - (message "Test suite execution failed unexpectedly.")) - (fmakunbound 'Assert) - (fmakunbound 'Check-Error) - (fmakunbound 'Check-Message) - (fmakunbound 'Check-Error-Message) - (fmakunbound 'Ignore-Ebola) - (fmakunbound 'Int-to-Marker) - (and noninteractive - (message "%s" (buffer-substring-no-properties - nil nil "*Test-Log*"))) - ))) - -(defvar test-harness-results-point-max nil) -(defmacro displaying-emacs-test-results (&rest body) - `(let ((test-harness-results-point-max test-harness-results-point-max)) - ;; Log the file name. - (test-harness-log-file) - ;; Record how much is logged now. - ;; We will display the log buffer if anything more is logged - ;; before the end of BODY. - (or test-harness-results-point-max - (save-excursion - (set-buffer (get-buffer-create "*Test-Log*")) - (setq test-harness-results-point-max (point-max)))) - (unwind-protect - (condition-case error-info - (progn ,@body) - (error - (test-harness-report-error error-info))) - (save-excursion - ;; If there were compilation warnings, display them. - (set-buffer "*Test-Log*") - (if (= test-harness-results-point-max (point-max)) - nil - (if temp-buffer-show-function - (let ((show-buffer (get-buffer-create "*Test-Log-Show*"))) - (save-excursion - (set-buffer show-buffer) - (setq buffer-read-only nil) - (erase-buffer)) - (copy-to-buffer show-buffer - (save-excursion - (goto-char test-harness-results-point-max) - (forward-line -1) - (point)) - (point-max)) - (funcall temp-buffer-show-function show-buffer)) - (select-window - (prog1 (selected-window) - (select-window (display-buffer (current-buffer))) - (goto-char test-harness-results-point-max) - (recenter 1))))))))) - -(defun batch-test-emacs-1 (file) - (condition-case error-info - (progn (test-emacs-test-file file) t) - (error - (princ ">>Error occurred processing ") - (princ file) - (princ ": ") - (display-error error-info nil) - (terpri) - nil))) - -(defun batch-test-emacs () - "Run `test-harness' on the files remaining on the command line. -Use this from the command line, with `-batch'; -it won't work in an interactive Emacs. -Each file is processed even if an error occurred previously. -A directory can be given as well, and all files will be processed -- -however, the file test-harness.el, which implements the test harness, -will be skipped. -For example, invoke \"xemacs -batch -f batch-test-emacs tests\"" - ;; command-line-args-left is what is left of the command line (from - ;; startup.el) - (defvar command-line-args-left) ;Avoid 'free variable' warning - (defvar debug-issue-ebola-notices) - (if (not noninteractive) - (error "`batch-test-emacs' is to be used only with -batch")) - (let ((error nil)) - (dolist (file command-line-args-left) - (if (file-directory-p file) - (dolist (file-in-dir (directory-files file t)) - (when (and (string-match emacs-lisp-file-regexp file-in-dir) - (not (or (auto-save-file-name-p file-in-dir) - (backup-file-name-p file-in-dir) - (equal (file-name-nondirectory file-in-dir) - "test-harness.el")))) - (or (batch-test-emacs-1 file-in-dir) - (setq error t)))) - (or (batch-test-emacs-1 file) - (setq error t)))) - (let ((namelen 0) - (succlen 0) - (testlen 0) - (results test-harness-file-results-alist)) - ;; compute maximum lengths of variable components of report - ;; probably should just use (length "byte-compiler-tests.el") - ;; and 5-place sizes -- this will also work for the file-by-file - ;; printing when Adrian's kludge gets reverted - (flet ((print-width (i) - (let ((x 10) (y 1)) - (while (>= i x) - (setq x (* 10 x) y (1+ y))) - y))) - (while results - (let* ((head (car results)) - (nn (length (file-name-nondirectory (first head)))) - (ss (print-width (second head))) - (tt (print-width (third head)))) - (when (> nn namelen) (setq namelen nn)) - (when (> ss succlen) (setq succlen ss)) - (when (> tt testlen) (setq testlen tt))) - (setq results (cdr results)))) - ;; create format and print - (let ((results (reverse test-harness-file-results-alist))) - (while results - (let* ((head (car results)) - (basename (file-name-nondirectory (first head))) - (nsucc (second head)) - (ntest (third head))) - (cond ((member (first head) unexpected-test-suite-failure-files) - (message test-harness-aborted-summary-template - (concat basename ":") - ntest)) - ((> ntest 0) - (message test-harness-file-summary-template - (concat basename ":") - nsucc - ntest - (/ (* 100 nsucc) ntest))) - (t - (message test-harness-null-summary-template - (concat basename ":")))) - (setq results (cdr results))))) - (when (> unexpected-test-suite-failures 0) - (message "\n***** There %s %d unexpected test suite %s in %s:" - (if (= unexpected-test-suite-failures 1) "was" "were") - unexpected-test-suite-failures - (if (= unexpected-test-suite-failures 1) "failure" "failures") - (if (= (length unexpected-test-suite-failure-files) 1) - "file" - "files")) - (while unexpected-test-suite-failure-files - (let ((line (pop unexpected-test-suite-failure-files))) - (while (and (< (length line) 61) - unexpected-test-suite-failure-files) - (setq line - (concat line " " - (pop unexpected-test-suite-failure-files)))) - (message line))))) - (message "\nDone") - (kill-emacs (if error 1 0)))) - -(provide 'test-harness) - -;;; test-harness.el ends here