0.6.10.21:
[sbcl.git] / src / code / backq.lisp
1 ;;;; the backquote reader macro
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 ;;; The flags passed back by BACKQUOTIFY can be interpreted as follows:
15 ;;;
16 ;;;   |`,|: [a] => a
17 ;;;    NIL: [a] => a            ;the NIL flag is used only when a is NIL
18 ;;;      T: [a] => a            ;the T flag is used when a is self-evaluating
19 ;;;  QUOTE: [a] => (QUOTE a)
20 ;;; APPEND: [a] => (APPEND . a)
21 ;;;  NCONC: [a] => (NCONC . a)
22 ;;;   LIST: [a] => (LIST . a)
23 ;;;  LIST*: [a] => (LIST* . a)
24 ;;;
25 ;;; The flags are combined according to the following set of rules:
26 ;;;  ([a] means that a should be converted according to the previous table)
27 ;;;
28 ;;;   \ car  ||    otherwise    |    QUOTE or     |     |`,@|      |     |`,.|
29 ;;;cdr \     ||          |    T or NIL     |            |
30 ;;;================================================================================
31 ;;;  |`,|    || LIST* ([a] [d]) | LIST* ([a] [d]) | APPEND (a [d]) | NCONC  (a [d])
32 ;;;  NIL     || LIST    ([a])   | QUOTE    (a)    | <hair>    a    | <hair>    a
33 ;;;QUOTE or T|| LIST* ([a] [d]) | QUOTE  (a . d)  | APPEND (a [d]) | NCONC (a [d])
34 ;;; APPEND   || LIST* ([a] [d]) | LIST* ([a] [d]) | APPEND (a . d) | NCONC (a [d])
35 ;;; NCONC    || LIST* ([a] [d]) | LIST* ([a] [d]) | APPEND (a [d]) | NCONC (a . d)
36 ;;;  LIST    || LIST  ([a] . d) | LIST  ([a] . d) | APPEND (a [d]) | NCONC (a [d])
37 ;;;  LIST*   || LIST* ([a] . d) | LIST* ([a] . d) | APPEND (a [d]) | NCONC  (a [d])
38 ;;;
39 ;;;<hair> involves starting over again pretending you had read ".,a)" instead
40 ;;; of ",@a)"
41
42 (defvar *backquote-count* 0 #!+sb-doc "how deep we are into backquotes")
43 (defvar *bq-comma-flag* '(|,|))
44 (defvar *bq-at-flag* '(|,@|))
45 (defvar *bq-dot-flag* '(|,.|))
46 (defvar *bq-vector-flag* '(|bqv|))
47
48 ;;; the actual character macro
49 (defun backquote-macro (stream ignore)
50   (declare (ignore ignore))
51   (let ((*backquote-count* (1+ *backquote-count*)))
52     (multiple-value-bind (flag thing)
53         (backquotify stream (read stream t nil t))
54       (if (eq flag *bq-at-flag*)
55           (%reader-error stream ",@ after backquote in ~S" thing))
56       (if (eq flag *bq-dot-flag*)
57           (%reader-error stream ",. after backquote in ~S" thing))
58       (values (backquotify-1 flag thing) 'list))))
59
60 (defun comma-macro (stream ignore)
61   (declare (ignore ignore))
62   (unless (> *backquote-count* 0)
63     (when *read-suppress*
64       (return-from comma-macro nil))
65     (%reader-error stream "comma not inside a backquote"))
66   (let ((c (read-char stream))
67         (*backquote-count* (1- *backquote-count*)))
68     (values
69      (cond ((char= c #\@)
70             (cons *bq-at-flag* (read stream t nil t)))
71            ((char= c #\.)
72             (cons *bq-dot-flag* (read stream t nil t)))
73            (t (unread-char c stream)
74               (cons *bq-comma-flag* (read stream t nil t))))
75      'list)))
76
77 ;;; This does the expansion from table 2.
78 (defun backquotify (stream code)
79   (cond ((atom code)
80          (cond ((null code) (values nil nil))
81                ((or (numberp code)
82                     (eq code t))
83                 ;; Keywords are self-evaluating. Install after packages.
84                 (values t code))
85                (t (values 'quote code))))
86         ((or (eq (car code) *bq-at-flag*)
87              (eq (car code) *bq-dot-flag*))
88          (values (car code) (cdr code)))
89         ((eq (car code) *bq-comma-flag*)
90          (comma (cdr code)))
91         ((eq (car code) *bq-vector-flag*)
92          (multiple-value-bind (dflag d) (backquotify stream (cdr code))
93            (values 'vector (backquotify-1 dflag d))))
94         (t (multiple-value-bind (aflag a) (backquotify stream (car code))
95              (multiple-value-bind (dflag d) (backquotify stream (cdr code))
96                (if (eq dflag *bq-at-flag*)
97                    ;; Get the errors later.
98                    (%reader-error stream ",@ after dot in ~S" code))
99                (if (eq dflag *bq-dot-flag*)
100                    (%reader-error stream ",. after dot in ~S" code))
101                (cond
102                 ((eq aflag *bq-at-flag*)
103                  (if (null dflag)
104                      (comma a)
105                      (values 'append
106                              (cond ((eq dflag 'append)
107                                     (cons a d ))
108                                    (t (list a (backquotify-1 dflag d)))))))
109                 ((eq aflag *bq-dot-flag*)
110                  (if (null dflag)
111                      (comma a)
112                      (values 'nconc
113                              (cond ((eq dflag 'nconc)
114                                     (cons a d))
115                                    (t (list a (backquotify-1 dflag d)))))))
116                 ((null dflag)
117                  (if (member aflag '(quote t nil))
118                      (values 'quote (list a))
119                      (values 'list (list (backquotify-1 aflag a)))))
120                 ((member dflag '(quote t))
121                  (if (member aflag '(quote t nil))
122                      (values 'quote (cons a d ))
123                      (values 'list* (list (backquotify-1 aflag a)
124                                           (backquotify-1 dflag d)))))
125                 (t (setq a (backquotify-1 aflag a))
126                    (if (member dflag '(list list*))
127                        (values dflag (cons a d))
128                        (values 'list*
129                                (list a (backquotify-1 dflag d)))))))))))
130
131 ;;; This handles the <hair> cases.
132 (defun comma (code)
133   (cond ((atom code)
134          (cond ((null code)
135                 (values nil nil))
136                ((or (numberp code) (eq code 't))
137                 (values t code))
138                (t (values *bq-comma-flag* code))))
139         ((eq (car code) 'quote)
140          (values (car code) (cadr code)))
141         ((member (car code) '(append list list* nconc))
142          (values (car code) (cdr code)))
143         ((eq (car code) 'cons)
144          (values 'list* (cdr code)))
145         (t (values *bq-comma-flag* code))))
146
147 ;;; This handles table 1.
148 (defun backquotify-1 (flag thing)
149   (cond ((or (eq flag *bq-comma-flag*)
150              (member flag '(t nil)))
151          thing)
152         ((eq flag 'quote)
153          (list  'quote thing))
154         ((eq flag 'list*)
155          (cond ((null (cddr thing))
156                 (cons 'backq-cons thing))
157                (t
158                 (cons 'backq-list* thing))))
159         ((eq flag 'vector)
160          (list 'backq-vector thing))
161         (t (cons (cdr
162                   (assoc flag
163                          '((cons . backq-cons)
164                            (list . backq-list)
165                            (append . backq-append)
166                            (nconc . backq-nconc))
167                          :test #'equal))
168                  thing))))
169 \f
170 ;;;; magic BACKQ- versions of builtin functions
171
172 ;;; Define synonyms for the lisp functions we use, so that by using them, we
173 ;;; backquoted material will be recognizable to the pretty-printer.
174 (macrolet ((def-frob (b-name name)
175              (let ((args (gensym "ARGS")))
176                ;; FIXME: This function should be INLINE so that the lists
177                ;; aren't consed twice, but I ran into an optimizer bug the
178                ;; first time I tried to make this work for BACKQ-LIST. See
179                ;; whether there's still an optimizer bug, and fix it if so, and
180                ;; then make these INLINE.
181                `(defun ,b-name (&rest ,args)
182                   (apply #',name ,args)))))
183   (def-frob backq-list list)
184   (def-frob backq-list* list*)
185   (def-frob backq-append append)
186   (def-frob backq-nconc nconc)
187   (def-frob backq-cons cons))
188
189 (defun backq-vector (list)
190   (declare (list list))
191   (coerce list 'simple-vector))
192 \f
193 ;;;; initialization
194
195 ;;; Install BACKQ stuff in the current *READTABLE*.
196 ;;;
197 ;;; In the target Lisp, we have to wait to do this until the readtable has been
198 ;;; created. In the cross-compilation host Lisp, we can do this right away.
199 ;;; (You may ask: In the cross-compilation host, which already has its own
200 ;;; implementation of the backquote readmacro, why do we do this at all?
201 ;;; Because the cross-compilation host might -- as SBCL itself does -- express
202 ;;; the backquote expansion in terms of internal, nonportable functions. By
203 ;;; redefining backquote in terms of functions which are guaranteed to exist on
204 ;;; the target Lisp, we ensure that backquote expansions in code-generating
205 ;;; code work properly.)
206 (defun !backq-cold-init ()
207   (set-macro-character #\` #'backquote-macro)
208   (set-macro-character #\, #'comma-macro))
209 #+sb-xc-host (!backq-cold-init)