1.0.11.1: Handle set-but-empty environment variables
[sbcl.git] / src / code / pp-backq.lisp
1 ;;;; pretty-printing of backquote expansions
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!IMPL")
13
14 (defun backq-unparse-expr (form splicing)
15   (ecase splicing
16     ((nil)
17      `(backq-comma ,form))
18     ((t)
19      `((backq-comma-at ,form)))
20     (:nconc
21      `((backq-comma-dot ,form)))
22     ))
23
24 (defun backq-unparse (form &optional splicing)
25   #!+sb-doc
26   "Given a lisp form containing the magic functions BACKQ-LIST, BACKQ-LIST*,
27   BACKQ-APPEND, etc. produced by the backquote reader macro, will return a
28   corresponding backquote input form. In this form, `,' `,@' and `,.' are
29   represented by lists whose cars are BACKQ-COMMA, BACKQ-COMMA-AT, and
30   BACKQ-COMMA-DOT respectively, and whose cadrs are the form after the comma.
31   SPLICING indicates whether a comma-escape return should be modified for
32   splicing with other forms: a value of T or :NCONC meaning that an extra
33   level of parentheses should be added."
34   (cond
35    ((atom form)
36     (backq-unparse-expr form splicing))
37    ((not (null (cdr (last form))))
38     ;; FIXME: this probably throws a recursive error
39     (bug "found illegal dotted backquote form: ~S" form))
40    (t
41     (case (car form)
42       (backq-list
43        (mapcar #'backq-unparse (cdr form)))
44       (backq-list*
45        (do ((tail (cdr form) (cdr tail))
46             (accum nil))
47            ((null (cdr tail))
48             (nconc (nreverse accum)
49                    (backq-unparse (car tail) t)))
50          (push (backq-unparse (car tail)) accum)))
51       (backq-append
52        (apply #'append
53               (mapcar (lambda (el) (backq-unparse el t))
54                       (cdr form))))
55       (backq-nconc
56        (apply #'append
57               (mapcar (lambda (el) (backq-unparse el :nconc))
58                       (cdr form))))
59       (backq-cons
60        (cons (backq-unparse (cadr form) nil)
61              (backq-unparse (caddr form) t)))
62       (backq-vector
63        (coerce (backq-unparse (cadr form)) 'vector))
64       (quote
65        (cond
66          ((atom (cadr form)) (cadr form))
67          ((and (consp (cadr form))
68                (member (caadr form) *backq-tokens*))
69           (backq-unparse-expr form splicing))
70          (t (cons (backq-unparse `(quote ,(caadr form)))
71                   (backq-unparse `(quote ,(cdadr form)))))))
72       (t
73        (backq-unparse-expr form splicing))))))
74
75 (defun pprint-backquote (stream form &rest noise)
76   (declare (ignore noise))
77   (write-char #\` stream)
78   (write (backq-unparse form) :stream stream))
79
80 (defun pprint-backq-comma (stream form &rest noise)
81   (declare (ignore noise))
82   (ecase (car form)
83     (backq-comma
84      (write-char #\, stream))
85     (backq-comma-at
86      (write-string ",@" stream))
87     (backq-comma-dot
88      (write-string ",." stream)))
89   ;; Ha!  an example of where the per-process specials for stream
90   ;; attributes rather than per-stream actually makes life easier.
91   ;; Since all of the attributes are shared in the dynamic state, we
92   ;; can do... -- CSR, 2003-09-30
93   ;;
94   ;; [...] above referred to the trick of printing to a string stream,
95   ;; and then simply printing the resulting sequence to the pretty
96   ;; stream, possibly with a space prepended.  However, this doesn't
97   ;; work for pretty streams which need to do margin calculations.  Oh
98   ;; well.  It was good while it lasted.  -- CSR, 2003-12-15
99   (let ((output (with-output-to-string (s)
100                   (write (cadr form) :stream s))))
101     (unless (= (length output) 0)
102       (when (and (eql (car form) 'backq-comma)
103                  (or (char= (char output 0) #\.)
104                      (char= (char output 0) #\@)))
105         (write-char #\Space stream))
106       (write (cadr form) :stream stream))))
107
108 ;;; This is called by !PPRINT-COLD-INIT, fairly late, because
109 ;;; SET-PPRINT-DISPATCH doesn't work until the compiler works.
110 ;;;
111 ;;; FIXME: It might be cleaner to just make these be toplevel forms and
112 ;;; enforce the delay by putting this file late in the build sequence.
113 (defun !backq-pp-cold-init ()
114   (set-pprint-dispatch '(cons (eql backq-list)) #'pprint-backquote)
115   (set-pprint-dispatch '(cons (eql backq-list*)) #'pprint-backquote)
116   (set-pprint-dispatch '(cons (eql backq-append)) #'pprint-backquote)
117   (set-pprint-dispatch '(cons (eql backq-nconc)) #'pprint-backquote)
118   (set-pprint-dispatch '(cons (eql backq-cons)) #'pprint-backquote)
119   (set-pprint-dispatch '(cons (eql backq-vector)) #'pprint-backquote)
120
121   (set-pprint-dispatch '(cons (eql backq-comma)) #'pprint-backq-comma)
122   (set-pprint-dispatch '(cons (eql backq-comma-at)) #'pprint-backq-comma)
123   (set-pprint-dispatch '(cons (eql backq-comma-dot)) #'pprint-backq-comma))