1 ;;;; the backquote reader macro
3 ;;;; This software is part of the SBCL system. See the README file for
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.
12 (in-package "SB!IMPL")
14 ;;; The flags passed back by BACKQUOTIFY can be interpreted as follows:
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)
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)
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])
39 ;;;<hair> involves starting over again pretending you had read ".,a)" instead
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|))
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))))
60 (defun comma-macro (stream ignore)
61 (declare (ignore ignore))
62 (unless (> *backquote-count* 0)
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*)))
70 (cons *bq-at-flag* (read stream t nil t)))
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))))
77 ;;; This does the expansion from table 2.
78 (defun backquotify (stream code)
80 (cond ((null code) (values nil nil))
83 ;; Keywords are self-evaluating. Install after packages.
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*)
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))
102 ((eq aflag *bq-at-flag*)
106 (cond ((eq dflag 'append)
108 (t (list a (backquotify-1 dflag d)))))))
109 ((eq aflag *bq-dot-flag*)
113 (cond ((eq dflag 'nconc)
115 (t (list a (backquotify-1 dflag d)))))))
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))
129 (list a (backquotify-1 dflag d)))))))))))
131 ;;; This handles the <hair> cases.
136 ((or (numberp code) (eq code 't))
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))))
147 ;;; This handles table 1.
148 (defun backquotify-1 (flag thing)
149 (cond ((or (eq flag *bq-comma-flag*)
150 (member flag '(t nil)))
155 (cond ((null (cddr thing))
156 (cons 'backq-cons thing))
158 (cons 'backq-list* thing))))
160 (list 'backq-vector thing))
163 '((cons . backq-cons)
165 (append . backq-append)
166 (nconc . backq-nconc))
170 ;;;; magic BACKQ- versions of builtin functions
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))
189 (defun backq-vector (list)
190 (declare (list list))
191 (coerce list 'simple-vector))
195 ;;; Install BACKQ stuff in the current *READTABLE*.
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)