1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; This software is derived from the CMU CL system, which was
5 ;;;; written at Carnegie Mellon University and released into the
6 ;;;; public domain. The software is in the public domain and is
7 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
8 ;;;; files for more information.
10 (in-package "SB!IMPL")
12 (declaim (special *read-suppress* *standard-readtable* *bq-vector-flag*))
14 ;;; FIXME: Is it standard to ignore numeric args instead of raising errors?
15 (defun ignore-numarg (sub-char numarg)
17 (warn "A numeric argument was ignored in #~W~A." numarg sub-char)))
19 ;;;; reading arrays and vectors: the #(, #*, and #A readmacros
21 (defun sharp-left-paren (stream ignore length)
22 (declare (ignore ignore) (special *backquote-count*))
23 (let* ((list (read-list stream nil))
24 (list-length (handler-case (length list)
26 (simple-reader-error stream
27 "Improper list in #(): ~S."
31 (cond (*read-suppress* nil)
32 ((and length (> list-length length))
35 "Vector longer than the specified length: #~S~S."
37 ((zerop *backquote-count*)
39 (fill (replace (make-array length) list)
42 (coerce list 'vector)))
44 (cons *bq-vector-flag*
47 (make-list (- length list-length)
48 :initial-element (car (last list))))
51 (defun sharp-star (stream ignore numarg)
52 (declare (ignore ignore))
53 (multiple-value-bind (bstring escape-appearedp) (read-extended-token stream)
54 (declare (simple-string bstring))
55 (cond (*read-suppress* nil)
57 (simple-reader-error stream
58 "An escape character appeared after #*."))
59 ((and numarg (zerop (length bstring)) (not (zerop numarg)))
62 "You have to give a little bit for non-zero #* bit-vectors."))
63 ((or (null numarg) (>= (the fixnum numarg) (length bstring)))
64 (let* ((len1 (length bstring))
66 (len2 (or numarg len1))
67 (bvec (make-array len2 :element-type 'bit
69 (declare (fixnum len1 last1 len2))
74 (setq char (elt bstring (if (< i len1) i last1)))
76 (cond ((char= char #\0) 0)
81 "illegal element given for bit-vector: ~S"
87 "Bit vector is longer than specified length #~A*~A"
91 (defun sharp-A (stream ignore dimensions)
92 (declare (ignore ignore))
95 (return-from sharp-A nil))
97 (simple-reader-error stream "No dimensions argument to #A."))
100 (if (zerop *backquote-count*)
102 "Comma inside a backquoted array (not a list or general vector.)"))
103 (*backquote-count* 0)
104 (contents (read stream t nil t))
106 (dotimes (axis dimensions
107 (make-array (dims) :initial-contents contents))
108 (unless (typep seq 'sequence)
109 (simple-reader-error stream
110 "#~WA axis ~W is not a sequence:~% ~S"
111 dimensions axis seq))
112 (let ((len (length seq)))
114 (unless (or (= axis (1- dimensions))
115 ;; ANSI: "If some dimension of the array whose
116 ;; representation is being parsed is found to be
117 ;; 0, all dimensions to the right (i.e., the
118 ;; higher numbered dimensions) are also
119 ;; considered to be 0."
121 (setq seq (elt seq 0))))))))
123 ;;;; reading structure instances: the #S readmacro
125 (defun sharp-S (stream sub-char numarg)
126 (ignore-numarg sub-char numarg)
127 (when *read-suppress*
128 (read stream t nil t)
129 (return-from sharp-S nil))
131 (if (zerop *backquote-count*)
133 "Comma inside backquoted structure (not a list or general vector.)"))
134 (*backquote-count* 0)
135 (body (if (char= (read-char stream t) #\( )
136 (let ((*backquote-count* 0))
137 (read-list stream nil))
138 (simple-reader-error stream "non-list following #S"))))
140 (simple-reader-error stream "non-list following #S: ~S" body))
141 (unless (symbolp (car body))
142 (simple-reader-error stream
143 "Structure type is not a symbol: ~S"
145 (let ((classoid (find-classoid (car body) nil)))
146 (unless (typep classoid 'structure-classoid)
147 (simple-reader-error stream
148 "~S is not a defined structure type."
150 (let ((default-constructor (dd-default-constructor
151 (layout-info (classoid-layout classoid)))))
152 (unless default-constructor
155 "The ~S structure does not have a default constructor."
157 (when (and (atom (rest body))
158 (not (null (rest body))))
159 (simple-reader-error stream "improper list for #S: ~S." body))
160 (apply (fdefinition default-constructor)
161 (loop for tail on (rest body) by #'cddr
162 with slot-name = (and (consp tail) (car tail))
164 (when (null (cdr tail))
167 "the arglist for the ~S constructor in #S ~
168 has an odd length: ~S."
169 (car body) (rest body)))
170 (when (or (atom (cdr tail))
171 (and (atom (cddr tail))
172 (not (null (cddr tail)))))
175 "the arglist for the ~S constructor in #S ~
177 (car body) (rest body)))
178 (when (not (typep (car tail) 'string-designator))
181 "a slot name in #S is not a string ~
184 (when (not (keywordp slot-name))
185 (warn 'structure-initarg-not-keyword
187 "in #S ~S, the use of non-keywords ~
188 as slot specifiers is deprecated: ~S."
190 (list (car body) slot-name))))
191 collect (intern (string (car tail)) *keyword-package*)
192 collect (cadr tail)))))))
194 ;;;; reading numbers: the #B, #C, #O, #R, and #X readmacros
196 (defun sharp-B (stream sub-char numarg)
197 (ignore-numarg sub-char numarg)
198 (sharp-R stream sub-char 2))
200 (defun sharp-C (stream sub-char numarg)
201 (ignore-numarg sub-char numarg)
202 ;; The next thing had better be a list of two numbers.
203 (let ((cnum (read stream t nil t)))
204 (when *read-suppress* (return-from sharp-C nil))
205 (if (and (listp cnum) (= (length cnum) 2))
206 (complex (car cnum) (cadr cnum))
207 (simple-reader-error stream
208 "illegal complex number format: #C~S"
211 (defun sharp-O (stream sub-char numarg)
212 (ignore-numarg sub-char numarg)
213 (sharp-R stream sub-char 8))
215 (defun sharp-R (stream sub-char radix)
216 (cond (*read-suppress*
217 (read-extended-token stream)
220 (simple-reader-error stream "radix missing in #R"))
221 ((not (<= 2 radix 36))
222 (simple-reader-error stream "illegal radix for #R: ~D." radix))
224 (let ((res (let ((*read-base* radix))
225 (read stream t nil t))))
226 (unless (typep res 'rational)
227 (simple-reader-error stream
228 "#~A (base ~D.) value is not a rational: ~S."
234 (defun sharp-X (stream sub-char numarg)
235 (ignore-numarg sub-char numarg)
236 (sharp-R stream sub-char 16))
238 ;;;; reading circular data: the #= and ## readmacros
240 ;;; objects already seen by CIRCLE-SUBST
241 (defvar *sharp-equal-circle-table*)
242 (declaim (type hash-table *sharp-equal-circle-table*))
244 ;; This function is kind of like NSUBLIS, but checks for circularities and
245 ;; substitutes in arrays and structures as well as lists. The first arg is an
246 ;; alist of the things to be replaced assoc'd with the things to replace them.
247 (defun circle-subst (old-new-alist tree)
248 (cond ((not (typep tree '(or cons (array t) instance funcallable-instance)))
249 (let ((entry (find tree old-new-alist :key #'second)))
250 (if entry (third entry) tree)))
251 ((null (gethash tree *sharp-equal-circle-table*))
252 (setf (gethash tree *sharp-equal-circle-table*) t)
254 (let ((a (circle-subst old-new-alist (car tree)))
255 (d (circle-subst old-new-alist (cdr tree))))
256 (unless (eq a (car tree))
258 (unless (eq d (cdr tree))
261 (with-array-data ((data tree) (start) (end))
262 (declare (fixnum start end))
263 (do ((i start (1+ i)))
265 (let* ((old (aref data i))
266 (new (circle-subst old-new-alist old)))
268 (setf (aref data i) new))))))
269 ((typep tree 'instance)
270 (let* ((n-untagged (layout-n-untagged-slots (%instance-layout tree)))
271 (n-tagged (- (%instance-length tree) n-untagged)))
272 ;; N-TAGGED includes the layout as well (at index 0), which
276 (let* ((old (%instance-ref tree i))
277 (new (circle-subst old-new-alist old)))
279 (setf (%instance-ref tree i) new))))
282 (let* ((old (%raw-instance-ref/word tree i))
283 (new (circle-subst old-new-alist old)))
285 (setf (%raw-instance-ref/word tree i) new))))))
286 ((typep tree 'funcallable-instance)
288 (end (- (1+ (get-closure-length tree)) sb!vm:funcallable-instance-info-offset)))
290 (let* ((old (%funcallable-instance-info tree i))
291 (new (circle-subst old-new-alist old)))
293 (setf (%funcallable-instance-info tree i) new))))))
297 ;;; Sharp-equal works as follows. When a label is assigned (i.e. when
298 ;;; #= is called) we GENSYM a symbol is which is used as an
299 ;;; unforgeable tag. *SHARP-SHARP-ALIST* maps the integer tag to this
302 ;;; When SHARP-SHARP encounters a reference to a label, it returns the
303 ;;; symbol assoc'd with the label. Resolution of the reference is
304 ;;; deferred until the read done by #= finishes. Any already resolved
305 ;;; tags (in *SHARP-EQUAL-ALIST*) are simply returned.
307 ;;; After reading of the #= form is completed, we add an entry to
308 ;;; *SHARP-EQUAL-ALIST* that maps the gensym tag to the resolved
309 ;;; object. Then for each entry in the *SHARP-SHARP-ALIST, the current
310 ;;; object is searched and any uses of the gensysm token are replaced
311 ;;; with the actual value.
312 (defvar *sharp-sharp-alist* ())
314 (defun sharp-equal (stream ignore label)
315 (declare (ignore ignore))
316 (when *read-suppress* (return-from sharp-equal (values)))
318 (simple-reader-error stream "missing label for #=" label))
319 (when (or (assoc label *sharp-sharp-alist*)
320 (assoc label *sharp-equal-alist*))
321 (simple-reader-error stream "multiply defined label: #~D=" label))
322 (let* ((tag (gensym))
323 (*sharp-sharp-alist* (acons label tag *sharp-sharp-alist*))
324 (obj (read stream t nil t)))
326 (simple-reader-error stream
327 "must tag something more than just #~D#"
329 (push (list label tag obj) *sharp-equal-alist*)
330 (let ((*sharp-equal-circle-table* (make-hash-table :test 'eq :size 20)))
331 (circle-subst *sharp-equal-alist* obj))))
333 (defun sharp-sharp (stream ignore label)
334 (declare (ignore ignore))
335 (when *read-suppress* (return-from sharp-sharp nil))
337 (simple-reader-error stream "missing label for ##" label))
339 (let ((entry (assoc label *sharp-equal-alist*)))
342 (let (;; Has this label been defined previously? (Don't read
343 ;; ANSI "2.4.8.15 Sharpsign Equal-Sign" and worry that
344 ;; it requires you to implement forward references,
345 ;; because forward references are disallowed in
346 ;; "2.4.8.16 Sharpsign Sharpsign".)
347 (pair (assoc label *sharp-sharp-alist*)))
349 (simple-reader-error stream
350 "reference to undefined label #~D#"
354 ;;;; conditional compilation: the #+ and #- readmacros
356 (flet ((guts (stream not-p)
357 (unless (if (let ((*package* *keyword-package*)
358 (*read-suppress* nil))
359 (featurep (read stream t nil t)))
362 (let ((*read-suppress* t))
363 (read stream t nil t)))
366 (defun sharp-plus (stream sub-char numarg)
367 (ignore-numarg sub-char numarg)
370 (defun sharp-minus (stream sub-char numarg)
371 (ignore-numarg sub-char numarg)
374 ;;;; reading miscellaneous objects: the #P, #\, and #| readmacros
376 (defun sharp-P (stream sub-char numarg)
377 (ignore-numarg sub-char numarg)
378 (let ((namestring (read stream t nil t)))
379 (unless *read-suppress*
380 (parse-namestring namestring))))
382 (defun sharp-backslash (stream backslash numarg)
383 (ignore-numarg backslash numarg)
384 (let ((charstring (read-extended-token-escaped stream)))
385 (declare (simple-string charstring))
386 (cond (*read-suppress* nil)
387 ((= (the fixnum (length charstring)) 1)
389 ((name-char charstring))
391 (simple-reader-error stream
392 "unrecognized character name: ~S"
395 (defun sharp-vertical-bar (stream sub-char numarg)
396 (ignore-numarg sub-char numarg)
398 ((character-decoding-error
399 #'(lambda (decoding-error)
400 (declare (ignorable decoding-error))
402 'sb!kernel::character-decoding-error-in-dispatch-macro-char-comment
403 :sub-char sub-char :position (file-position stream) :stream stream)
404 (invoke-restart 'attempt-resync))))
405 (let ((stream (in-synonym-of stream)))
406 (if (ansi-stream-p stream)
407 (prepare-for-fast-read-char stream
409 (prev (fast-read-char) char)
410 (char (fast-read-char) (fast-read-char)))
412 (cond ((and (char= prev #\|) (char= char #\#))
413 (setq level (1- level))
415 (done-with-fast-read-char)
417 (setq char (fast-read-char)))
418 ((and (char= prev #\#) (char= char #\|))
419 (setq char (fast-read-char))
420 (setq level (1+ level))))))
421 ;; fundamental-stream
423 (prev (read-char stream t) char)
424 (char (read-char stream t) (read-char stream t)))
426 (cond ((and (char= prev #\|) (char= char #\#))
427 (setq level (1- level))
430 (setq char (read-char stream t)))
431 ((and (char= prev #\#) (char= char #\|))
432 (setq char (read-char stream t))
433 (setq level (1+ level)))))))))
435 ;;;; a grab bag of other sharp readmacros: #', #:, and #.
437 (defun sharp-quote (stream sub-char numarg)
438 (ignore-numarg sub-char numarg)
439 ;; The fourth arg tells READ that this is a recursive call.
440 `(function ,(read stream t nil t)))
442 (defun sharp-colon (stream sub-char numarg)
443 (ignore-numarg sub-char numarg)
444 (multiple-value-bind (token escapep colon) (read-extended-token stream)
445 (declare (simple-string token) (ignore escapep))
447 (*read-suppress* nil)
450 stream "The symbol following #: contains a package marker: ~S" token))
452 (make-symbol token)))))
454 (defvar *read-eval* t
456 "If false, then the #. read macro is disabled.")
458 (defun sharp-dot (stream sub-char numarg)
459 (ignore-numarg sub-char numarg)
460 (let ((token (read stream t nil t)))
461 (unless *read-suppress*
463 (simple-reader-error stream "can't read #. while *READ-EVAL* is NIL"))
466 (defun sharp-illegal (stream sub-char ignore)
467 (declare (ignore ignore))
468 (simple-reader-error stream "illegal sharp macro character: ~S" sub-char))
470 ;;; for cold init: Install SHARPM stuff in the current *READTABLE*.
471 (defun !sharpm-cold-init ()
472 (make-dispatch-macro-character #\# t)
473 (set-dispatch-macro-character #\# #\\ #'sharp-backslash)
474 (set-dispatch-macro-character #\# #\' #'sharp-quote)
475 (set-dispatch-macro-character #\# #\( #'sharp-left-paren)
476 (set-dispatch-macro-character #\# #\* #'sharp-star)
477 (set-dispatch-macro-character #\# #\: #'sharp-colon)
478 (set-dispatch-macro-character #\# #\. #'sharp-dot)
479 (set-dispatch-macro-character #\# #\R #'sharp-R)
480 (set-dispatch-macro-character #\# #\r #'sharp-R)
481 (set-dispatch-macro-character #\# #\B #'sharp-B)
482 (set-dispatch-macro-character #\# #\b #'sharp-B)
483 (set-dispatch-macro-character #\# #\O #'sharp-O)
484 (set-dispatch-macro-character #\# #\o #'sharp-O)
485 (set-dispatch-macro-character #\# #\X #'sharp-X)
486 (set-dispatch-macro-character #\# #\x #'sharp-X)
487 (set-dispatch-macro-character #\# #\A #'sharp-A)
488 (set-dispatch-macro-character #\# #\a #'sharp-A)
489 (set-dispatch-macro-character #\# #\S #'sharp-S)
490 (set-dispatch-macro-character #\# #\s #'sharp-S)
491 (set-dispatch-macro-character #\# #\= #'sharp-equal)
492 (set-dispatch-macro-character #\# #\# #'sharp-sharp)
493 (set-dispatch-macro-character #\# #\+ #'sharp-plus)
494 (set-dispatch-macro-character #\# #\- #'sharp-minus)
495 (set-dispatch-macro-character #\# #\C #'sharp-C)
496 (set-dispatch-macro-character #\# #\c #'sharp-C)
497 (set-dispatch-macro-character #\# #\| #'sharp-vertical-bar)
498 (set-dispatch-macro-character #\# #\p #'sharp-P)
499 (set-dispatch-macro-character #\# #\P #'sharp-P)
500 (set-dispatch-macro-character #\# #\) #'sharp-illegal)
501 (set-dispatch-macro-character #\# #\< #'sharp-illegal)
502 (set-dispatch-macro-character #\# #\Space #'sharp-illegal)
503 (dolist (cc '#.(list tab-char-code form-feed-char-code return-char-code
504 line-feed-char-code backspace-char-code))
505 (set-dispatch-macro-character #\# (code-char cc) #'sharp-illegal)))