comparison lisp/utils/pretty-print.el @ 72:b9518feda344 r20-0b31

Import from CVS: tag r20-0b31
author cvs
date Mon, 13 Aug 2007 09:03:46 +0200
parents
children c7528f8e288d
comparison
equal deleted inserted replaced
71:bae944334fa4 72:b9518feda344
1 ;; -*- Syntax: Emacs-Lisp; Mode: emacs-lisp -*-
2 ;;
3 ;; Emacs Lisp pretty printer and macro expander
4 ;;
5 ;; Copyright (C) 1992,1993 Guido Bosch <Guido.Bosch@loria.fr>
6
7 ;; This file is written in GNU Emacs Lisp, but is not part of GNU Emacs.
8
9 ;; The software contained in this file is free software; you can
10 ;; redistribute it and/or modify it under the terms of the GNU General
11 ;; Public License as published by the Free Software Foundation; either
12 ;; version 2, or (at your option) any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to
21 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 ;;
23 ;; Please send bugs and comments to the author.
24 ;;
25 ;; <DISCLAIMER>
26 ;; This program is still under development. Neither the author nor
27 ;; CRIN-INRIA accepts responsibility to anyone for the consequences of
28 ;; using it or for whether it serves any particular purpose or works
29 ;; at all.
30 ;;
31 ;; The package has been developed under Lucid Emacs 19, but also runs
32 ;; on Emacs 18, if it is compiled with the version 19 byte compiler
33 ;; (function `compiled-function-p' lacking).
34 ;;
35
36 ;; Installation and Usage
37 ;; ----------------------
38 ;;
39 ;; This package provides an Emacs Lisp sexpression pretty printer and
40 ;; macroexpander. To install it, put the following line in your .emacs,
41 ;; default.el or site-init.el/site-run.el (for Lucid Emacs):
42 ;; (require 'pp)
43 ;;
44 ;; The package can also be made autoloadable, with the following entry
45 ;; points:
46 ;; (autoload 'pp-function "pp" nil t)
47 ;; (autoload 'pp-variable "pp" nil t)
48 ;; (autoload 'pp-plist "pp" nil t)
49 ;; (autoload 'macroexpand-sexp "pp" nil t)
50 ;; (autoload 'macroexpand-all-sexp "pp" nil t)
51 ;; (autoload 'prettyexpand-sexp "pp" nil t)
52 ;; (autoload 'prettyexpand-all-sexp "pp" nil t)
53 ;;
54 ;;(define-key emacs-lisp-mode-map '(control meta m) 'macroexpand-sexp)
55 ;;(define-key emacs-lisp-mode-map '(control meta M) 'macroexpand-all-sexp)
56 ;;(define-key emacs-lisp-mode-map '(control symbol m) 'prettyexpand-sexp)
57 ;;(define-key emacs-lisp-mode-map '(control symbol M) 'prettyexpand-all-sexp)
58 ;;
59 ;;(define-key lisp-interaction-mode-map '(control meta m) 'macroexpand-sexp)
60 ;;(define-key lisp-interaction-mode-map '(control meta M) 'macroexpand-all-sexp)
61 ;;(define-key lisp-interaction-mode-map '(control symbol m) 'prettyexpand-sexp)
62 ;;(define-key lisp-interaction-mode-map '(control symbol M) 'prettyexpand-all-sexp)
63 ;;
64
65 ;; Pretty printing of the different cells of a symbol is done with the
66 ;; commands:
67 ;;
68 ;; M-x pp-function
69 ;; M-x pp-variable
70 ;; M-x pp-plist
71 ;;
72 ;; They print a symbol's function definition, variable value and
73 ;; property list, respectively. These commands pop up a separate
74 ;; window in which the pretty printed lisp object is displayed.
75 ;; Completion for function and variable symbols is provided. If a
76 ;; function is byte compiled, `pp-function' proposes to call the Emacs
77 ;; Lisp disassembler (this feature only works for Emacs 19, as it
78 ;; needs the `compiled-function-p' predicate).
79 ;;
80 ;; To use the macro expander, put the cursor at the beginning of the
81 ;; form to be expanded, then type
82 ;;
83 ;; C-M-m (macroexpand-sexp)
84 ;; or C-M-Sh-M (macroexpand-all-sexp)
85 ;;
86 ;; Both commands will pop up a temporary window containing the
87 ;; macroexpanded code. The only difference is that the second command
88 ;; expands recursively all containing macro calls, while the first one
89 ;; does it only for the uppermost sexpression.
90 ;; With a prefix argument, the macro expansion isn't displayed in a
91 ;; separate buffer but replaces the original code in the current
92 ;; buffer. Be aware: Comments will be lost.
93 ;; You can get back the original sexpression using the `undo'
94 ;; command on `C-x u'.
95 ;;
96 ;; There is also a prettyfied version of the macroexpander:
97 ;;
98 ;; C-Sym-m (prettyexpand-sexp)
99 ;; or C-Sym-M (prettyexpand-all-sexp)
100 ;;
101 ;; The only difference with the corresponding macroexpand commands is
102 ;; that calls to macros specified in the variable
103 ;; `pp-shadow-expansion-list' are not expanded, in order to make the
104 ;; code look nicer. This is only useful for Lucid Emacs or code that
105 ;; uses Dave Gillespies cl package, as it inhibits expansion of the
106 ;; following macros: block, eval-when, defun*, defmacro*, function*,
107 ;; setf.
108
109 ; Change History
110 ;
111 ; $Log: pretty-print.el,v $
112 ; Revision 1.1.1.1 1996/12/18 22:51:29 steve
113 ; XEmacs 20.0 -- Beta 31
114 ;
115 ; Revision 1.4 1993/03/25 14:09:52 bosch
116 ; Commands `prettyexpand-sexp' and `prettyexpand-all-sexp' and
117 ; corresponding key bindings added. Commands pp-{function, variable}
118 ; rewritten. `pp-plist' added. Function `pp-internal-loop' (for Dave
119 ; Gillespies CL loop macro) added.
120 ;
121 ; Revision 1.3 1993/03/03 12:24:13 bosch
122 ; Macroexpander rewritten. Function `pp-macroexpand-all' added (snarfed
123 ; from Dave Gillespies cl-extra.el). Pretty printing for top level
124 ; defining forms added (`pp-internal-def'). Key bindings for
125 ; `emacs-lisp-mode-map' and `lisp-interaction-mode-map' added. Built-in
126 ; variable `print-gensym' set for printinng uninterned symbols. Started
127 ; adding support for cl-dg (defun*, defmacro*, ...). Minor bug fixes.
128 ;
129 ; Revision 1.2 1993/02/25 17:35:02 bosch
130 ; Comments about Emacs 18 compatibility added.
131 ;
132 ; Revision 1.1 1993/02/25 16:55:01 bosch
133 ; Initial revision
134 ;
135 ;
136
137
138 ;; TO DO LIST
139 ;; ----------
140 ;; Provide full Emacs 18 compatibility.
141
142 ;; Popper support
143 (defvar pp-buffer-name "*Pretty Print*")
144 (defvar pp-macroexpand-buffer-name "*Macro Expansion*")
145 (if (featurep 'popper)
146 (or (eq popper-pop-buffers 't)
147 (setq popper-pop-buffers
148 (cons pp-buffer-name
149 (cons pp-macroexpand-buffer-name
150 popper-pop-buffers)))))
151
152 ;; User level functions
153 ;;;###autoload
154 (defun pp-function (symbol)
155 "Pretty print the function definition of SYMBOL in a seperate buffer"
156 (interactive
157 (list (pp-read-symbol 'fboundp "Pretty print function definition of: ")))
158 (if (compiled-function-p (symbol-function symbol))
159 (if (y-or-n-p
160 (format "Function %s is byte compiled. Disassemble? " symbol))
161 (disassemble (symbol-function symbol))
162 (pp-symbol-cell symbol 'symbol-function))
163 (pp-symbol-cell symbol 'symbol-function)))
164
165 ;;;###autoload
166 (defun pp-variable (symbol)
167 "Pretty print the variable value of SYMBOL in a seperate buffer"
168 (interactive
169 (list (pp-read-symbol 'boundp "Pretty print variable value of: ")))
170 (pp-symbol-cell symbol 'symbol-value))
171
172 ;;;###autoload
173 (defun pp-plist (symbol)
174 "Pretty print the property list of SYMBOL in a seperate buffer"
175 (interactive
176 (list (pp-read-symbol 'symbol-plist "Pretty print property list of: ")))
177 (pp-symbol-cell symbol 'symbol-plist))
178
179 (defun pp-read-symbol (predicate prompt)
180 "Read a symbol for which PREDICATE is true, promptiong with PROMPT."
181 (let (symbol)
182 (while (or (not symbol) (not (funcall predicate symbol)))
183 (setq symbol
184 (intern-soft
185 (completing-read
186 prompt
187 obarray
188 predicate
189 t
190 (and symbol (symbol-name symbol))))))
191 symbol))
192
193 (defun pp-symbol-cell (symbol accessor)
194 "Pretty print the contents of the cell of SYMBOL that can be reached
195 with the function ACCESSOR."
196 (with-output-to-temp-buffer pp-buffer-name
197 (set-buffer pp-buffer-name)
198 (emacs-lisp-mode)
199 (erase-buffer)
200 (pp-internal
201 (funcall accessor symbol)
202 (format "%s's %s is:\n" symbol accessor))
203 (terpri)))
204
205
206
207 ;; Macro expansion (user level)
208
209 ;;;###autoload
210 (defun macroexpand-sexp (&optional replace)
211 "Macro expand the sexpression following point. Pretty print expansion in a
212 temporary buffer. With prefix argument, replace the original
213 sexpression by its expansion in the current buffer."
214 (interactive "P")
215 (pp-macroexpand-internal 'macroexpand replace t))
216
217 ;;;###autoload
218 (defun macroexpand-all-sexp (&optional replace)
219 "Macro expand recursively the sexpression following point. Pretty print
220 expansion in a temporary buffer. With prefix argument, replace the
221 original sexpression by its expansion in the current buffer."
222 (interactive "P")
223 (pp-macroexpand-internal 'pp-macroexpand-all replace t))
224
225 ;;;###autoload
226 (defun prettyexpand-sexp (&optional replace)
227 "Macro expand the sexpression following point. Pretty print expansion
228 in a temporary buffer. With prefix argument, replace the original
229 sexpression by its expansion in the current buffer.
230 However, calls to macros specified in the variable
231 `pp-shadow-expansion-list' are not expanded, in order to make the code
232 look nicer."
233
234 (interactive "P")
235 (pp-macroexpand-internal 'macroexpand replace))
236
237 ;;;###autoload
238 (defun prettyexpand-all-sexp (&optional replace)
239 "Macro expand recursively the sexpression following point. Pretty print
240 expansion in a temporary buffer. With prefix argument, replace the
241 original sexpression by its expansion in the current buffer.
242 However, calls to macros specified in the variable
243 `pp-shadow-expansion-list' are not expanded, in order to make the code
244 look nicer."
245 (interactive "P")
246 (pp-macroexpand-internal 'pp-macroexpand-all replace))
247
248 (define-key emacs-lisp-mode-map '(control meta m) 'macroexpand-sexp)
249 (define-key emacs-lisp-mode-map '(control meta M) 'macroexpand-all-sexp)
250 (define-key emacs-lisp-mode-map '(control symbol m) 'prettyexpand-sexp)
251 (define-key emacs-lisp-mode-map '(control symbol M) 'prettyexpand-all-sexp)
252
253 (define-key lisp-interaction-mode-map '(control meta m) 'macroexpand-sexp)
254 (define-key lisp-interaction-mode-map '(control meta M) 'macroexpand-all-sexp)
255 (define-key lisp-interaction-mode-map '(control symbol m) 'prettyexpand-sexp)
256 (define-key lisp-interaction-mode-map '(control symbol M) 'prettyexpand-all-sexp)
257
258
259 ;; Macro expansion (internals)
260
261 (defvar pp-shadow-expansion-list
262 (mapcar 'list '(block eval-when defun* defmacro* function* setf))
263 "The value of this variable is given as the optional environment
264 argument of the macroexpand functions. Forms specified in this list are
265 not expanded.")
266
267 (defun pp-macroexpand-internal
268 (macroexpand-function replace &optional dont-shadow)
269 "Macro expand the sexp that starts at point, using
270 MACROEXPAND-FUNCTION. If REPLACE is non-nil, replace the original
271 text by its expansion, otherwise pretty print the expansion in a
272 temporary buffer. With optional argument DONT-SHADOW non-nil, do not
273 use the `pp-shadow-expansion-list' to inhibit expansion of some
274 forms."
275
276 (interactive)
277 (let ((expansion
278 (funcall
279 macroexpand-function
280 (let ((stab (syntax-table)))
281 (unwind-protect
282 (save-excursion
283 (set-syntax-table emacs-lisp-mode-syntax-table)
284 ;; (forward-sexp 1)
285 (read (current-buffer)))
286 (set-syntax-table stab)))
287 (if dont-shadow
288 nil
289 pp-shadow-expansion-list))))
290 (save-excursion
291 (if replace
292 (let ((start (point))
293 (end (progn (forward-sexp 1) (point))))
294 (delete-region start end)
295 (pp-internal expansion))
296 (with-output-to-temp-buffer pp-macroexpand-buffer-name
297 (set-buffer pp-macroexpand-buffer-name)
298 (erase-buffer)
299 (emacs-lisp-mode)
300 (pp-internal expansion))))))
301
302 ;; Internal pretty print functions
303
304 (defun pp-internal (form &optional title)
305 "Pretty print FORM in in the current buffer.
306 Optional string TITEL is inserted before the pretty print."
307 (let (start)
308 (if title (princ title))
309 (setq start (point))
310 ;; print-escape-newlines must be t, otherwise we cannot use
311 ;; (current-column) to detect good line breaks
312 (let ((print-escape-newlines t)
313 (print-gensym t)
314 )
315 (prin1 form (current-buffer))
316 (goto-char start)
317 (pp-internal-sexp))))
318
319 (defun pp-internal-sexp ()
320 "Pretty print the following sexp.
321 Point must be on or before the first character."
322
323 (skip-chars-forward " \n\t")
324 (let* ((char (following-char))
325 (ch-class (char-syntax char))
326 (start (point)))
327
328 (cond
329 ;; open paren
330 ((eq char ?\()
331 (down-list 1)
332 (if (memq (char-syntax (following-char)) '(?_ ?w))
333 (let ((symbol (read (current-buffer))))
334 (cond ((fboundp symbol)
335 (goto-char start)
336 (pp-internal-function symbol))
337 ((memq symbol '(lambda macro))
338 (pp-internal-lambda))
339 (t
340 (goto-char start)
341 (pp-internal-list))))
342 (up-list -1)
343 (pp-internal-list)))
344
345 ;;symbols & strings
346 ((memq ch-class '(?_ ; symbol
347 ?w ; word
348 ?\" ; string
349 ?\\ ; escape
350 ?\' ; quote (for uninterned symbols)
351 )) (forward-sexp 1))
352
353 ;; vector
354 ((eq char ?\[) (pp-internal-list))
355
356 ;; error otherwise
357 (t (error "pp-internal-sexp: character class not treated yet: `%c'"
358 ch-class)))))
359
360 (defun pp-internal-function (func)
361 "Pretty print a functuion call.
362 Point must be on the open paren. the function symbol may be passed as an
363 optional argument."
364 (let ((start (point))
365 (too-large (>= (save-excursion
366 (forward-sexp 1)
367 (current-column))
368 fill-column))
369 (indent-info (get func lisp-indent-function)))
370 (down-list 1)
371 ;; skip over function name
372 (forward-sexp 1)
373 (cond
374 ((memq func '(let let*)) (pp-internal-let))
375
376 ((eq func 'cond) (pp-internal-cond))
377
378 ((memq func '(if while with-output-to-temp-buffer catch block))
379 (pp-internal-sexp)
380 (pp-internal-body 't))
381
382 ((eq func 'quote) (pp-internal-quote))
383
384 ((memq func '(progn
385 prog1 prog2
386 save-window-excursion
387 save-excursion
388 save-restriction))
389 (pp-internal-body 't))
390
391 ((memq func '(defun defmacro defsubst defun* defmacro*))
392 (pp-internal-def))
393
394 ((eq func 'loop) (pp-internal-loop))
395
396 ('t (pp-internal-body too-large)))))
397
398 (defun pp-internal-def ()
399 (forward-sexp 1) ; skip name
400 (if (looking-at " nil") ; replace nil by ()
401 (replace-match " ()")
402 (forward-sexp 1))
403 (if (looking-at " \"")
404 ;; comment string. Replace all escaped linefeeds by real ones
405 (let ((limit (save-excursion (forward-sexp 1) (point-marker))))
406 (newline-and-indent)
407 (while (re-search-forward "\\\\n" limit t)
408 (replace-match "\n" nil nil))
409 (goto-char limit)))
410 (pp-internal-body 't))
411
412 (defun pp-internal-list ()
413 "Pretty print a list or a vector.
414 Point must be on the open paren."
415 (let ((too-large (>= (save-excursion
416 (forward-sexp 1)
417 (current-column))
418 fill-column)))
419 (down-list 1)
420 (pp-internal-sexp)
421 (pp-internal-body too-large)))
422
423 (defun pp-internal-body (&optional force-indent)
424 "Prety print a body of sexp. Stop after reaching a `)'. If argument
425 FORCE-INDENT is non-nil, break line after each sexpression of the
426 body."
427 (skip-chars-forward " \n\t")
428 (let (ch-class)
429 ;; while not closing paren
430 (while (/= (setq ch-class (char-syntax (following-char))) ?\))
431 (if force-indent (newline-and-indent))
432 (pp-internal-sexp))
433 (up-list 1)))
434
435 (defun pp-internal-loop ()
436 "Prety print a loop body. Stop after reaching a `)'.
437 Line breaks are done before the following keywords: "
438 (forward-sexp 1)
439 (skip-chars-forward " \n\t")
440 (let (ch-class)
441 ;; while not closing paren
442 (while (/= (setq ch-class (char-syntax (following-char))) ?\))
443 (if (not (looking-at "for\\|repeat\\|with\\|while\\|until\\|always\\|never\\|thereis\\|collect\\|append\\|nconc\\|sum\\|count\\|maximize\\|minimize\\|if\\|when\\|else\\|unless\\|do\\W\\|initially\\|finally\\|return\\|named"))
444 (pp-internal-sexp)
445 (newline-and-indent)
446 (forward-sexp 1))
447 (skip-chars-forward " \n\t"))
448 (up-list 1)))
449
450 (defun pp-internal-body-list ()
451 (let ((too-large (>= (save-excursion
452 (forward-sexp 1)
453 (current-column))
454 fill-column))
455 ch-class)
456 (down-list 1)
457 (pp-internal-sexp)
458 (while (/= (setq ch-class (char-syntax (following-char))) ?\))
459 (if too-large (newline-and-indent))
460 (pp-internal-sexp))
461 (up-list 1)))
462
463 (defun pp-internal-lambda ()
464 (forward-sexp 1) ; arguments
465 (pp-internal-body 't))
466
467 (defun pp-internal-let ()
468 "Pretty print a let-like form.
469 Cursor is behind funtion symbol."
470 (down-list 1)
471 (while (not (= (following-char) ?\)))
472 (if (= (following-char) ?\()
473 (pp-internal-body-list)
474 (forward-sexp 1))
475 (if (not (= (following-char) ?\)))
476 (newline-and-indent)))
477 (up-list 1)
478 (pp-internal-body 't))
479
480 (defun pp-internal-cond ()
481 "Pretty print a cond-like form.
482 Cursor is behind funtion symbol."
483 (skip-chars-forward " \n\t")
484 (while (not (= (following-char) ?\)))
485 (pp-internal-body-list)
486 (if (not (= (following-char) ?\)))
487 (newline-and-indent)))
488 (up-list 1))
489
490
491 (defun pp-internal-quote ()
492 "Pretty print a quoted list.
493 Cursor is behind the symbol quote."
494 (skip-chars-forward " \n\t")
495 (let ((end (point)))
496 (backward-sexp 1)
497 (delete-region (point) end)
498 (up-list -1)
499 (setq end (point))
500 (forward-sexp 1)
501 (delete-char -1)
502 (goto-char end)
503 (delete-char 1)
504 (insert "'")
505 (if (= (char-syntax (following-char)) ?\()
506 ;; don't print it as sexp, because it could be (let ... ) or
507 ;; (cond ... ) or whatever.
508 (pp-internal-list)
509 (pp-internal-sexp))))
510
511
512 ;; Stolen form Dave Gillespies cl-extra.el
513 (defun pp-macroexpand-all (form &optional env)
514 "Expand all macro calls through a Lisp FORM.
515 This also does some trivial optimizations to make the form prettier."
516 (setq form (macroexpand form env))
517 (cond
518 ((not (consp form)) form)
519 ((memq (car form) '(let let*))
520 (if (null (nth 1 form))
521 (pp-macroexpand-all (cons 'progn (cdr (cdr form))) env)
522 (cons (car form)
523 (cons (pp-macroexpand-lets (nth 1 form) env)
524 (pp-macroexpand-body (cdr (cdr form)) env)))))
525 ((eq (car form) 'cond)
526 (cons (car form)
527 (mapcar (function (lambda (x) (pp-macroexpand-body x env)))
528 (cdr form))))
529 ((eq (car form) 'condition-case)
530 (cons (car form)
531 (cons (nth 1 form)
532 (cons (pp-macroexpand-all (nth 2 form) env)
533 (pp-macroexpand-lets
534 (cdr (cdr (cdr form))) env)))))
535 ((memq (car form) '(quote function))
536 (if (eq (car-safe (nth 1 form)) 'lambda)
537 (list (car form)
538 (cons 'lambda
539 (cons (car (cdr (car (cdr form))))
540 (pp-macroexpand-body
541 (cdr (cdr (car (cdr form)))) env))))
542 form))
543 ((memq (car form) '(defun defmacro))
544 (cons (car form)
545 (cons (nth 1 form)
546 (pp-macroexpand-body (cdr (cdr form)) env))))
547 ((and (eq (car form) 'progn) (not (cdr (cdr form))))
548 (pp-macroexpand-all (nth 1 form) env))
549 (t
550 (cons (car form) (pp-macroexpand-body (cdr form) env)))))
551
552 (defun pp-macroexpand-body (body &optional env)
553 (mapcar (function (lambda (x) (pp-macroexpand-all x env))) body))
554
555 (defun pp-macroexpand-lets (list &optional env)
556 (mapcar (function
557 (lambda (x)
558 (if (consp x) (cons (car x) (pp-macroexpand-body (cdr x) env))
559 x))) list))
560
561 (run-hooks 'pp-load-hook)
562 (provide 'pp)
563
564 ;; end pp.el