T-gnus 6.16.3 revision 00.
[elisp/gnus.git-] / lisp / gnus-clfns.el
1 ;;; gnus-clfns.el --- compiler macros for emulating cl functions
2
3 ;; Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4
5 ;; Author: Kastsumi Yamaoka <yamaoka@jpl.org>
6 ;; Keywords: cl, compile
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;; This module is for mainly avoiding cl runtime functions in FSF
28 ;; Emacsen.  Function should also be defined as an ordinary function
29 ;; if it will not be provided in cl.
30
31 ;;; Code:
32
33 (if (featurep 'xemacs)
34     nil
35   (eval-when-compile (require 'cl))
36   (require 'pym)
37
38   (define-compiler-macro butlast (&whole form x &optional n)
39     (if (>= emacs-major-version 21)
40         form
41       (if n
42           `(let ((x ,x)
43                  (n ,n))
44              (if (and n (<= n 0))
45                  x
46                (let ((m (length x)))
47                  (or n (setq n 1))
48                  (and (< n m)
49                       (progn
50                         (if (> n 0)
51                             (progn
52                               (setq x (copy-sequence x))
53                               (setcdr (nthcdr (- (1- m) n) x) nil)))
54                         x)))))
55         `(let* ((x ,x)
56                 (m (length x)))
57            (and (< 1 m)
58                 (progn
59                   (setq x (copy-sequence x))
60                   (setcdr (nthcdr (- m 2) x) nil)
61                   x))))))
62
63 ;;  (define-compiler-macro coerce (&whole form x type)
64 ;;    (if (and (fboundp 'coerce)
65 ;;           (subrp (symbol-function 'coerce)))
66 ;;      form
67 ;;      `(let ((x ,x)
68 ;;           (type ,type))
69 ;;       (cond ((eq type 'list) (if (listp x) x (append x nil)))
70 ;;             ((eq type 'vector) (if (vectorp x) x (vconcat x)))
71 ;;             ((eq type 'string) (if (stringp x) x (concat x)))
72 ;;             ((eq type 'array) (if (arrayp x) x (vconcat x)))
73 ;;             ((and (eq type 'character) (stringp x) (= (length x) 1))
74 ;;              (aref x 0))
75 ;;             ((and (eq type 'character) (symbolp x)
76 ;;                   (= (length (symbol-name x)) 1))
77 ;;              (aref (symbol-name x) 0))
78 ;;             ((eq type 'float) (float x))
79 ;;             ((typep x type) x)
80 ;;             (t (error "Can't coerce %s to type %s" x type))))))
81
82 ;;  (define-compiler-macro copy-list (&whole form list)
83 ;;    (if (and (fboundp 'copy-list)
84 ;;           (subrp (symbol-function 'copy-list)))
85 ;;      form
86 ;;      `(let ((list ,list))
87 ;;       (if (consp list)
88 ;;           (let ((res nil))
89 ;;             (while (consp list) (push (pop list) res))
90 ;;             (prog1 (nreverse res) (setcdr res list)))
91 ;;         (car list)))))
92
93   (define-compiler-macro last (&whole form x &optional n)
94     (if (>= emacs-major-version 20)
95         form
96       (if n
97           `(let* ((x ,x)
98                   (n ,n)
99                   (m 0)
100                   (p x))
101              (while (consp p)
102                (incf m)
103                (pop p))
104              (if (<= n 0)
105                  p
106                (if (< n m)
107                    (nthcdr (- m n) x)
108                  x)))
109         `(let ((x ,x))
110            (while (consp (cdr x))
111              (pop x))
112            x))))
113
114   (define-compiler-macro mapc (&whole form fn seq &rest rest)
115     (if (>= emacs-major-version 21)
116         form
117       (if rest
118           `(let* ((fn ,fn)
119                   (seq ,seq)
120                   (args (list seq ,@rest))
121                   (m (apply (function min) (mapcar (function length) args)))
122                   (n 0))
123              (while (< n m)
124                (apply fn (mapcar (function (lambda (arg) (nth n arg))) args))
125                (setq n (1+ n)))
126              seq)
127         `(let ((seq ,seq))
128            (mapcar ,fn seq)
129            seq))))
130
131 ;;  (define-compiler-macro merge (&whole form type seq1 seq2 pred &rest keys)
132 ;;    (if (and (fboundp 'merge)
133 ;;           (subrp (symbol-function 'merge)))
134 ;;      form
135 ;;      `(let ((type ,type)
136 ;;           (seq1 ,seq1)
137 ;;           (seq2 ,seq2)
138 ;;           (pred ,pred))
139 ;;       (or (listp seq1) (setq seq1 (append seq1 nil)))
140 ;;       (or (listp seq2) (setq seq2 (append seq2 nil)))
141 ;;       (let ((res nil))
142 ;;         (while (and seq1 seq2)
143 ;;           (if (funcall pred (car seq2) (car seq1))
144 ;;               (push (pop seq2) res)
145 ;;             (push (pop seq1) res)))
146 ;;         (coerce (nconc (nreverse res) seq1 seq2) type)))))
147
148 ;;  (define-compiler-macro string (&whole form &rest args)
149 ;;    (if (>= emacs-major-version 20)
150 ;;      form
151 ;;      (list 'concat (cons 'list args))))
152
153 ;;  (defun-maybe string (&rest args)
154 ;;    "Concatenate all the argument characters and make the result a string."
155 ;;    (concat args))
156
157   (define-compiler-macro string-to-list (&whole form string)
158     (cond ((fboundp 'string-to-list)
159            form)
160           ((fboundp 'string-to-char-list)
161            (list 'string-to-char-list string))
162           (t
163            `(let* ((str ,string)
164                    (len (length str))
165                    (idx 0)
166                    c l)
167               (while (< idx len)
168                 (setq c (sref str idx))
169                 (setq idx (+ idx (char-bytes c)))
170                 (setq l (cons c l)))
171               (nreverse l)))))
172
173   ;; 92.7.2 by K.Handa (imported from Mule 2.3)
174   (defun-maybe string-to-list (str)
175     (let ((len (length str))
176           (idx 0)
177           c l)
178       (while (< idx len)
179         (setq c (sref str idx))
180         (setq idx (+ idx (char-bytes c)))
181         (setq l (cons c l)))
182       (nreverse l)))
183
184 ;;  (define-compiler-macro subseq (&whole form seq start &optional end)
185 ;;    (if (and (fboundp 'subseq)
186 ;;           (subrp (symbol-function 'subseq)))
187 ;;      form
188 ;;      (if end
189 ;;        `(let ((seq ,seq)
190 ;;               (start ,start)
191 ;;               (end ,end))
192 ;;           (if (stringp seq)
193 ;;               (substring seq start end)
194 ;;             (let (len)
195 ;;               (if (< end 0)
196 ;;                   (setq end (+ end (setq len (length seq)))))
197 ;;               (if (< start 0)
198 ;;                   (setq start (+ start (or len (setq len (length seq))))))
199 ;;               (cond ((listp seq)
200 ;;                      (if (> start 0)
201 ;;                          (setq seq (nthcdr start seq)))
202 ;;                      (let ((res nil))
203 ;;                        (while (>= (setq end (1- end)) start)
204 ;;                          (push (pop seq) res))
205 ;;                        (nreverse res)))
206 ;;                     (t
207 ;;                      (let ((res (make-vector (max (- end start) 0) nil))
208 ;;                            (i 0))
209 ;;                        (while (< start end)
210 ;;                          (aset res i (aref seq start))
211 ;;                          (setq i (1+ i)
212 ;;                                start (1+ start)))
213 ;;                        res))))))
214 ;;      `(let ((seq ,seq)
215 ;;             (start ,start))
216 ;;         (if (stringp seq)
217 ;;             (substring seq start)
218 ;;           (let (len)
219 ;;             (if (< start 0)
220 ;;                 (setq start (+ start (or len (setq len (length seq))))))
221 ;;             (cond ((listp seq)
222 ;;                    (if (> start 0)
223 ;;                        (setq seq (nthcdr start seq)))
224 ;;                    (copy-sequence seq))
225 ;;                   (t
226 ;;                    (let* ((end (or len (length seq)))
227 ;;                           (res (make-vector (max (- end start) 0) nil))
228 ;;                           (i 0))
229 ;;                      (while (< start end)
230 ;;                        (aset res i (aref seq start))
231 ;;                        (setq i (1+ i)
232 ;;                              start (1+ start)))
233 ;;                      res)))))))))
234   )
235
236 ;; A tool for the developers.
237
238 (defvar cl-run-time-functions
239   '(Values
240     Values-list acons assoc-if assoc-if-not build-klist butlast ceiling*
241     coerce common-lisp-indent-function compiler-macroexpand concatenate
242     copy-list count count-if count-if-not delete* delete-duplicates delete-if
243     delete-if-not duplicate-symbols-p elt-satisfies-test-p equalp evenp every
244     extract-from-klist fill find find-if find-if-not floatp-safe floor* gcd
245     gensym gentemp get-setf-method getf hash-table-count hash-table-p
246     intersection isqrt keyword-argument-supplied-p keyword-of keywordp last
247     lcm ldiff lisp-indent-259 lisp-indent-do lisp-indent-function-lambda-hack
248     lisp-indent-report-bad-format lisp-indent-tagbody list-length
249     make-hash-table make-random-state map mapc mapcan mapcar* mapcon mapl
250     maplist member-if member-if-not merge mismatch mod* nbutlast nintersection
251     notany notevery nreconc nset-difference nset-exclusive-or nsublis nsubst
252     nsubst-if nsubst-if-not nsubstitute nsubstitute-if nsubstitute-if-not
253     nunion oddp pair-with-newsyms pairlis position position-if position-if-not
254     proclaim random* random-state-p rassoc* rassoc-if rassoc-if-not
255     reassemble-argslists reduce rem* remove remove* remove-duplicates
256     remove-if remove-if-not remq replace revappend round* safe-idiv search
257     set-difference set-exclusive-or setelt setnth setnthcdr signum some sort*
258     stable-sort sublis subseq subsetp subst subst-if subst-if-not substitute
259     substitute-if substitute-if-not tailp tree-equal truncate* union
260     unzip-lists zip-lists)
261   "A list of CL run-time functions.  Some functions were built-in, nowadays.")
262
263 ;;;###autoload
264 (defun find-cl-run-time-functions (file-or-directory arg)
265   "Find CL run-time functions in the FILE-OR-DIRECTORY.  You can alter
266 the behavior of this command with the prefix ARG as described below.
267
268 By default, it searches for all the CL run-time functions listed in
269  the variable `cl-run-time-functions'.
270 With 1 or 3 \\[universal-argument]'s, the built-in functions in this Emacs\
271  will not be
272  reported.
273 With 2 or 3 \\[universal-argument]'s, just the symbols will also be reported.
274
275 You can use the `digit-argument' 1, 2 or 3 instead of\
276  \\[universal-argument]'s."
277   (interactive (list (read-file-name "Find CL run-time functions in: "
278                                      nil default-directory t)
279                      current-prefix-arg))
280   (unless (interactive-p)
281     (error "You should invoke `M-x find-cl-run-time-functions' interactively"))
282   (let ((report-symbols (member arg '((16) (64) 2 3)))
283         files clfns working file lines form forms fns fn newform buffer
284         window scroll
285         buffer-file-format format-alist
286         insert-file-contents-post-hook insert-file-contents-pre-hook)
287     (cond ((file-directory-p file-or-directory)
288            (setq files (directory-files file-or-directory t "\\.el$"))
289            (dolist (file files)
290              (unless (file-exists-p file)
291                (setq files (delete file files))))
292            (unless files
293              (message "No files found in: %s" file-or-directory))
294            files)
295           ((file-exists-p file-or-directory)
296            (setq files (list file-or-directory)))
297           (t
298            (message "No such file or directory: %s" file-or-directory)))
299     (when files
300       (if (member arg '((4) (64) 1 3))
301           (dolist (fn cl-run-time-functions)
302             (unless (and (fboundp fn)
303                          (subrp (symbol-function fn)))
304               (push fn clfns)))
305         (setq clfns cl-run-time-functions))
306       (set-buffer (setq working
307                         (get-buffer-create
308                          " *Searching for CL run-time functions*")))
309       (let (emacs-lisp-mode-hook)
310         (emacs-lisp-mode))
311       (while files
312         (setq file (pop files)
313               lines (list nil nil))
314         (message "Searching for CL run-time functions in: %s..."
315                  (file-name-nondirectory file))
316         (insert-file-contents file nil nil nil t)
317         ;; XEmacs moves point to the beginning of the buffer after
318         ;; inserting a file, FSFmacs doesn't so if the fifth argument
319         ;; of `insert-file-contents' is specified.
320         (goto-char (point-min))
321         ;;
322         (while (progn
323                  (while (and (looking-at "[\t\v\f\r ]*\\(;.*\\)?$")
324                              (zerop (forward-line 1))))
325                  (not (eobp)))
326           (setcar lines (if (bolp)
327                             (1+ (count-lines (point-min) (point)))
328                           (count-lines (point-min) (point))))
329           (when (consp;; Ignore stand-alone symbols, strings, etc.
330                  (setq form (condition-case nil
331                                 (read working)
332                               (error nil))))
333             (setcdr lines (list (count-lines (point-min) (point))))
334             (setq forms (list form)
335                   fns nil)
336             (while forms
337               (setq form (pop forms))
338               (when (consp form)
339                 (setq fn (pop form))
340                 (cond ((memq fn '(apply mapatoms mapcar mapconcat
341                                         mapextent symbol-function))
342                        (if (consp (car form))
343                            (when (memq (caar form) '(\` backquote quote))
344                              (setcar form (cdar form)))
345                          (setq form (cdr form))))
346                       ((memq fn '(\` backquote quote))
347                        (if report-symbols
348                            (progn
349                              (setq form (car form)
350                                    newform nil)
351                              (while form
352                                (push (list (or (car-safe form) form))
353                                      newform)
354                                (setq form (cdr-safe form)))
355                              (setq form (nreverse newform)))
356                          (setq form nil)))
357                       ((memq fn '(defadvice
358                                    defmacro defsubst defun
359                                    defmacro-maybe defmacro-maybe-cond
360                                    defsubst-maybe defun-maybe
361                                    defun-maybe-cond))
362                        (setq form (cddr form)))
363                       ((memq fn '(defalias lambda fset))
364                        (setq form (cdr form)))
365                       ((eq fn 'define-compiler-macro)
366                        (setq form nil))
367                       ((eq fn 'dolist)
368                        (setcar form (cadar form)))
369                       ((memq fn '(let let*))
370                        (setq form
371                              (append
372                               (delq nil
373                                     (mapcar
374                                      (lambda (element)
375                                        (when (and (consp element)
376                                                   (consp (cadr element)))
377                                          (cadr element)))
378                                      (car form)))
379                               (cdr form))))
380                       ((eq fn 'sort)
381                        (when (and (consp (cadr form))
382                                   (memq (caadr form) '(\` backquote quote)))
383                          (setcdr form (list (cdadr form)))))
384                       ((and (memq fn clfns)
385                             (listp form))
386                        (push fn fns)))
387                 (when (listp form)
388                   (setq forms (append form forms)))))
389             (when fns
390               (if buffer
391                   (set-buffer buffer)
392                 (display-buffer
393                  (setq buffer (get-buffer-create
394                                (concat "*CL run-time functions in: "
395                                        file-or-directory "*"))))
396                 (set-buffer buffer)
397                 (erase-buffer)
398                 (setq window (get-buffer-window buffer t)
399                       scroll (- 2 (window-height window))
400                       fill-column (max 16 (- (window-width window) 2))
401                       fill-prefix "               "))
402               (when file
403                 (insert file "\n")
404                 (setq file nil))
405               (narrow-to-region
406                (point)
407                (progn
408                  (insert fill-prefix
409                          (mapconcat (lambda (fn) (format "%s" fn))
410                                     (nreverse fns) " ")
411                          "\n")
412                  (point)))
413               (fill-region (point-min) (point-max))
414               (goto-char (point-min))
415               (widen)
416               (delete-char 14)
417               (insert (format "%5d - %5d:" (car lines) (cadr lines)))
418               (goto-char (point-max))
419               (forward-line scroll)
420               (set-window-start window (point))
421               (goto-char (point-max))
422               (sit-for 0)
423               (set-buffer working)))))
424       (kill-buffer working)
425       (if buffer
426           (message "Done")
427         (message "No CL run-time functions found in: %s"
428                  file-or-directory)))))
429
430 (provide 'gnus-clfns)
431
432 ;;; gnus-clfns.el ends here