Disassemble TBZ and TBNZ on ARM64.
[sbcl.git] / src / code / sharpm.lisp
blob46f79fa3c9d3c637990199b4c888fa65de9f0784
1 ;;;; This software is part of the SBCL system. See the README file for
2 ;;;; more information.
3 ;;;;
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*))
14 ;;; FIXME: Is it standard to ignore numeric args instead of raising errors?
15 (defun ignore-numarg (sub-char numarg)
16 (when 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))
23 (let* ((list (read-list stream nil))
24 (list-length
25 (handler-case (length list)
26 (type-error ()
27 (simple-reader-error stream "Improper list in #(): ~S." list)))))
28 (declare (list list)
29 (fixnum list-length))
30 (cond (*read-suppress* nil)
31 ((and length (> list-length length))
32 (simple-reader-error
33 stream
34 "Vector longer than the specified length: #~S~S."
35 length list))
36 (length
37 (when (and (plusp length) (null list))
38 (simple-reader-error
39 stream "Vector of length ~D can't be initialized from ()" length))
40 ;; the syntax `#n(foo ,@bar) is not well-defined. [See lp#1096043.]
41 ;; We take it to mean that the vector as read should be padded to
42 ;; length 'n'. It could be argued that 'n' is the length after
43 ;; expansion, but that's not easy, not to mention unportable.
44 (fill (replace (make-array length) list)
45 (car (last list)) :start list-length))
47 (coerce list 'vector)))))
49 (defun sharp-star (stream ignore numarg)
50 (declare (ignore ignore))
51 (declare (type (or null fixnum) numarg))
52 (binding* (((buffer escape-appearedp) (read-extended-token stream))
53 (input-len (token-buf-fill-ptr buffer))
54 (bstring (token-buf-string buffer)))
55 (cond (*read-suppress* nil)
56 (escape-appearedp
57 (simple-reader-error stream
58 "An escape character appeared after #*."))
59 ((and numarg (zerop input-len) (not (zerop numarg)))
60 (simple-reader-error
61 stream
62 "You have to give a little bit for non-zero #* bit-vectors."))
63 ((or (null numarg) (>= numarg input-len))
64 (do ((bvec
65 (make-array (or numarg input-len)
66 :element-type 'bit
67 :initial-element
68 (if (and (plusp input-len)
69 (char= (char bstring (1- input-len)) #\1))
70 1 0)))
71 (i 0 (1+ i)))
72 ((= i input-len) bvec)
73 (declare (index i) (optimize (sb!c::insert-array-bounds-checks 0)))
74 (let ((char (char bstring i)))
75 (setf (elt bvec i)
76 (case char
77 (#\0 0)
78 (#\1 1)
79 (t (simple-reader-error
80 stream "illegal element given for bit-vector: ~S"
81 char)))))))
83 (simple-reader-error
84 stream
85 "Bit vector is longer than specified length #~A*~A"
86 numarg
87 (copy-token-buf-string buffer))))))
89 (defun sharp-A (stream ignore dimensions)
90 (declare (ignore ignore))
91 (when *read-suppress*
92 (read stream t nil t)
93 (return-from sharp-A nil))
94 (unless dimensions
95 (simple-reader-error stream "No dimensions argument to #A."))
96 (collect ((dims))
97 (let* ((*bq-error*
98 (if (zerop *backquote-depth*)
99 *bq-error*
100 "Comma inside a backquoted array (not a list or general vector.)"))
101 (*backquote-depth* 0)
102 (contents (read stream t nil t))
103 (seq contents))
104 (dotimes (axis dimensions
105 (make-array (dims) :initial-contents contents))
106 (unless (typep seq 'sequence)
107 (simple-reader-error stream
108 "#~WA axis ~W is not a sequence:~% ~S"
109 dimensions axis seq))
110 (let ((len (length seq)))
111 (dims len)
112 (unless (or (= axis (1- dimensions))
113 ;; ANSI: "If some dimension of the array whose
114 ;; representation is being parsed is found to be
115 ;; 0, all dimensions to the right (i.e., the
116 ;; higher numbered dimensions) are also
117 ;; considered to be 0."
118 (= len 0))
119 (setq seq (elt seq 0))))))))
121 ;;;; reading structure instances: the #S readmacro
123 (defun sharp-S (stream sub-char numarg)
124 (ignore-numarg sub-char numarg)
125 (when *read-suppress*
126 (read stream t nil t)
127 (return-from sharp-S nil))
128 (let* ((*bq-error*
129 (if (zerop *backquote-depth*)
130 *bq-error*
131 "Comma inside backquoted structure (not a list or general vector.)"))
132 (body (if (char= (read-char stream t) #\( )
133 (let ((*backquote-depth* 0))
134 (read-list stream nil))
135 (simple-reader-error stream "non-list following #S"))))
136 (unless (listp body)
137 (simple-reader-error stream "non-list following #S: ~S" body))
138 (unless (symbolp (car body))
139 (simple-reader-error stream
140 "Structure type is not a symbol: ~S"
141 (car body)))
142 (let ((classoid (find-classoid (car body) nil)))
143 (unless (typep classoid 'structure-classoid)
144 (simple-reader-error stream
145 "~S is not a defined structure type."
146 (car body)))
147 (let ((default-constructor (dd-default-constructor
148 (layout-info (classoid-layout classoid)))))
149 (unless default-constructor
150 (simple-reader-error
151 stream
152 "The ~S structure does not have a default constructor."
153 (car body)))
154 (when (and (atom (rest body))
155 (not (null (rest body))))
156 (simple-reader-error stream "improper list for #S: ~S." body))
157 (apply (fdefinition default-constructor)
158 (loop for tail on (rest body) by #'cddr
159 with slot-name = (and (consp tail) (car tail))
160 do (progn
161 (when (null (cdr tail))
162 (simple-reader-error
163 stream
164 "the arglist for the ~S constructor in #S ~
165 has an odd length: ~S."
166 (car body) (rest body)))
167 (when (or (atom (cdr tail))
168 (and (atom (cddr tail))
169 (not (null (cddr tail)))))
170 (simple-reader-error
171 stream
172 "the arglist for the ~S constructor in #S ~
173 is improper: ~S."
174 (car body) (rest body)))
175 (when (not (typep (car tail) 'string-designator))
176 (simple-reader-error
177 stream
178 "a slot name in #S is not a string ~
179 designator: ~S."
180 slot-name))
181 (when (not (keywordp slot-name))
182 (warn 'structure-initarg-not-keyword
183 :format-control
184 "in #S ~S, the use of non-keywords ~
185 as slot specifiers is deprecated: ~S."
186 :format-arguments
187 (list (car body) slot-name))))
188 collect (intern (string (car tail)) *keyword-package*)
189 collect (cadr tail)))))))
191 ;;;; reading numbers: the #B, #C, #O, #R, and #X readmacros
193 (defun sharp-B (stream sub-char numarg)
194 (ignore-numarg sub-char numarg)
195 (sharp-R stream sub-char 2))
197 (defun sharp-C (stream sub-char numarg)
198 (ignore-numarg sub-char numarg)
199 ;; The next thing had better be a list of two numbers.
200 (let ((cnum (read stream t nil t)))
201 (when *read-suppress* (return-from sharp-C nil))
202 (if (and (listp cnum) (= (length cnum) 2))
203 (complex (car cnum) (cadr cnum))
204 (simple-reader-error stream
205 "illegal complex number format: #C~S"
206 cnum))))
208 (defun sharp-O (stream sub-char numarg)
209 (ignore-numarg sub-char numarg)
210 (sharp-R stream sub-char 8))
212 (defun sharp-R (stream sub-char radix)
213 (cond (*read-suppress*
214 (read-extended-token stream)
215 nil)
216 ((not radix)
217 (simple-reader-error stream "radix missing in #R"))
218 ((not (<= 2 radix 36))
219 (simple-reader-error stream "illegal radix for #R: ~D." radix))
221 ;; FIXME: (read-from-string "#o#x1f") should not work!
222 ;; The token should be comprised strictly of digits in the radix,
223 ;; though the docs say this is undefined behavior, so it's ok,
224 ;; other than it being something we should complain about
225 ;; for portability reasons.
226 (let ((res (let ((*read-base* radix))
227 (read stream t nil t))))
228 (unless (typep res 'rational)
229 (simple-reader-error stream
230 "#~A (base ~D.) value is not a rational: ~S."
231 sub-char
232 radix
233 res))
234 res))))
236 (defun sharp-X (stream sub-char numarg)
237 (ignore-numarg sub-char numarg)
238 (sharp-R stream sub-char 16))
240 ;;;; reading circular data: the #= and ## readmacros
242 ;;; objects already seen by CIRCLE-SUBST
243 (defvar *sharp-equal-circle-table*)
244 (declaim (type hash-table *sharp-equal-circle-table*))
246 ;; This function is kind of like NSUBLIS, but checks for circularities and
247 ;; substitutes in arrays and structures as well as lists. The first arg is an
248 ;; alist of the things to be replaced assoc'd with the things to replace them.
249 (defun circle-subst (old-new-alist tree)
250 (cond ((not (typep tree '(or cons (array t) instance funcallable-instance)))
251 (let ((entry (find tree old-new-alist :key #'second)))
252 (if entry (third entry) tree)))
253 ((null (gethash tree *sharp-equal-circle-table*))
254 (setf (gethash tree *sharp-equal-circle-table*) t)
255 (cond ((consp tree)
256 (let ((a (circle-subst old-new-alist (car tree)))
257 (d (circle-subst old-new-alist (cdr tree))))
258 (unless (eq a (car tree))
259 (rplaca tree a))
260 (unless (eq d (cdr tree))
261 (rplacd tree d))))
262 ((arrayp tree)
263 (with-array-data ((data tree) (start) (end))
264 (declare (fixnum start end))
265 (do ((i start (1+ i)))
266 ((>= i end))
267 (let* ((old (aref data i))
268 (new (circle-subst old-new-alist old)))
269 (unless (eq old new)
270 (setf (aref data i) new))))))
271 ((typep tree 'instance)
272 ;; We don't grovel the layout.
273 (do-instance-tagged-slot (i tree)
274 (let* ((old (%instance-ref tree i))
275 (new (circle-subst old-new-alist old)))
276 (unless (eq old new)
277 (setf (%instance-ref tree i) new)))))
278 ((typep tree 'funcallable-instance)
279 (do ((i 1 (1+ i))
280 (end (- (1+ (get-closure-length tree)) sb!vm:funcallable-instance-info-offset)))
281 ((= i end))
282 (let* ((old (%funcallable-instance-info tree i))
283 (new (circle-subst old-new-alist old)))
284 (unless (eq old new)
285 (setf (%funcallable-instance-info tree i) new))))))
286 tree)
287 (t tree)))
289 ;;; Sharp-equal works as follows. When a label is assigned (i.e. when
290 ;;; #= is called) we GENSYM a symbol is which is used as an
291 ;;; unforgeable tag. *SHARP-SHARP-ALIST* maps the integer tag to this
292 ;;; gensym.
294 ;;; When SHARP-SHARP encounters a reference to a label, it returns the
295 ;;; symbol assoc'd with the label. Resolution of the reference is
296 ;;; deferred until the read done by #= finishes. Any already resolved
297 ;;; tags (in *SHARP-EQUAL-ALIST*) are simply returned.
299 ;;; After reading of the #= form is completed, we add an entry to
300 ;;; *SHARP-EQUAL-ALIST* that maps the gensym tag to the resolved
301 ;;; object. Then for each entry in the *SHARP-SHARP-ALIST, the current
302 ;;; object is searched and any uses of the gensysm token are replaced
303 ;;; with the actual value.
304 (defvar *sharp-sharp-alist* ())
306 (defun sharp-equal (stream ignore label)
307 (declare (ignore ignore))
308 (when *read-suppress* (return-from sharp-equal (values)))
309 (unless label
310 (simple-reader-error stream "missing label for #=" label))
311 (when (or (assoc label *sharp-sharp-alist*)
312 (assoc label *sharp-equal-alist*))
313 (simple-reader-error stream "multiply defined label: #~D=" label))
314 (let* ((tag (gensym))
315 (*sharp-sharp-alist* (acons label tag *sharp-sharp-alist*))
316 (obj (read stream t nil t)))
317 (when (eq obj tag)
318 (simple-reader-error stream
319 "must tag something more than just #~D#"
320 label))
321 (push (list label tag obj) *sharp-equal-alist*)
322 (let ((*sharp-equal-circle-table* (make-hash-table :test 'eq :size 20)))
323 (circle-subst *sharp-equal-alist* obj))))
325 (defun sharp-sharp (stream ignore label)
326 (declare (ignore ignore))
327 (when *read-suppress* (return-from sharp-sharp nil))
328 (unless label
329 (simple-reader-error stream "missing label for ##" label))
331 (let ((entry (assoc label *sharp-equal-alist*)))
332 (if entry
333 (third entry)
334 (let (;; Has this label been defined previously? (Don't read
335 ;; ANSI "2.4.8.15 Sharpsign Equal-Sign" and worry that
336 ;; it requires you to implement forward references,
337 ;; because forward references are disallowed in
338 ;; "2.4.8.16 Sharpsign Sharpsign".)
339 (pair (assoc label *sharp-sharp-alist*)))
340 (unless pair
341 (simple-reader-error stream
342 "reference to undefined label #~D#"
343 label))
344 (cdr pair)))))
346 ;;;; conditional compilation: the #+ and #- readmacros
348 (defun sharp-plus-minus (stream sub-char numarg)
349 (ignore-numarg sub-char numarg)
350 (if (char= (if (featurep (let ((*package* *keyword-package*)
351 (*reader-package* nil)
352 (*read-suppress* nil))
353 (read stream t nil t)))
354 #\+ #\-) sub-char)
355 (read stream t nil t)
356 (let ((*read-suppress* t))
357 (read stream t nil t)
358 (values))))
360 ;;;; reading miscellaneous objects: the #P, #\, and #| readmacros
362 (defun sharp-P (stream sub-char numarg)
363 (ignore-numarg sub-char numarg)
364 (let ((namestring (read stream t nil t)))
365 (unless *read-suppress*
366 (parse-namestring namestring))))
368 (defun sharp-backslash (stream backslash numarg)
369 (ignore-numarg backslash numarg)
370 (let ((buf (read-extended-token-escaped stream)))
371 (cond (*read-suppress* nil)
372 ((= (token-buf-fill-ptr buf) 1)
373 (char (token-buf-string buf) 0))
374 ;; NAME-CHAR is specified as case-insensitive
375 ((name-char (sized-token-buf-string buf)))
377 (simple-reader-error stream
378 "unrecognized character name: ~S"
379 (copy-token-buf-string buf))))))
381 (defun sharp-vertical-bar (stream sub-char numarg)
382 (ignore-numarg sub-char numarg)
383 (handler-bind
384 ((character-decoding-error
385 #'(lambda (decoding-error)
386 (declare (ignorable decoding-error))
387 (style-warn
388 'sb!kernel::character-decoding-error-in-dispatch-macro-char-comment
389 :sub-char sub-char :position (file-position stream) :stream stream)
390 (invoke-restart 'attempt-resync))))
391 (let ((stream (in-synonym-of stream)))
392 (macrolet ((munch (get-char &optional finish)
393 `(do ((level 1)
394 (prev ,get-char char)
395 (char ,get-char ,get-char))
396 (())
397 (cond ((and (char= prev #\|) (char= char #\#))
398 (setq level (1- level))
399 (when (zerop level)
400 ,finish
401 (return (values)))
402 (setq char ,get-char))
403 ((and (char= prev #\#) (char= char #\|))
404 (setq char ,get-char)
405 (setq level (1+ level)))))))
406 (if (ansi-stream-p stream)
407 (prepare-for-fast-read-char stream
408 (munch (fast-read-char) (done-with-fast-read-char)))
409 ;; fundamental-stream
410 (munch (read-char stream t)))))))
412 ;;;; a grab bag of other sharp readmacros: #', #:, and #.
414 (defun sharp-quote (stream sub-char numarg)
415 (ignore-numarg sub-char numarg)
416 ;; The fourth arg tells READ that this is a recursive call.
417 `(function ,(read stream t nil t)))
419 ;;; Read an uninterned symbol.
420 ;;; Unescaped whitespace terminates the token, however a token comprised
421 ;;; of zero characters is an edge-case that is not extremely portable other
422 ;;; than for a few well-known uses, such as the incontrovertible fact that
423 ;;; "#* foo" is two tokens: an empty bit-vector followed by a symbol.
424 ;;; But different behaviors can be observed for #: in other implementations:
425 ;;; (read-from-string "#: foo") => #:FOO
426 ;;; (read-from-string "#: foo") => ERROR "token expected"
427 (defun sharp-colon (stream sub-char numarg)
428 (ignore-numarg sub-char numarg)
429 (multiple-value-bind (buffer escapep colon) (read-extended-token stream)
430 (unless *read-suppress*
431 (casify-read-buffer buffer)
432 (let ((token (copy-token-buf-string buffer)))
433 (cond (colon
434 (simple-reader-error
435 stream "The symbol following #: contains a package marker: ~S"
436 token))
437 ;; We'd like to signal errors on tokens that look like numbers,
438 ;; but doing that is actually nontrivial. None of the possible
439 ;; ways to test for numeric syntax are great:
440 ;; - using SYMBOL-QUOTEP to see if it says that the symbol would
441 ;; print using escapes could produce false positives
442 ;; because it's seldom wrong to use vertical bars.
443 ;; - calling READ-FROM-STRING to see if it returns a number
444 ;; would demand a new string stream.
445 ;; - a potential number with _ and/or ^ should not be allowed.
446 ;; An acceptable rough cut is to use PARSE-INTEGER even though it
447 ;; won't help to reject ratios or floating point syntax.
448 ((and (not escapep)
449 (multiple-value-bind (num end)
450 (parse-integer token :radix *read-base* :junk-allowed t)
451 (and num (= end (length token)))))
452 (simple-reader-error
453 stream "The symbol following #: has numeric syntax: ~S"
454 token))
456 (make-symbol token)))))))
458 (defvar *read-eval* t
459 #!+sb-doc
460 "If false, then the #. read macro is disabled.")
462 (defun sharp-dot (stream sub-char numarg)
463 (ignore-numarg sub-char numarg)
464 (let ((*backquote-depth* 0))
465 (let ((expr (read stream t nil t)))
466 (unless *read-suppress*
467 (unless *read-eval*
468 (simple-reader-error stream "can't read #. while *READ-EVAL* is NIL"))
469 (eval expr)))))
471 (defun sharp-illegal (stream sub-char ignore)
472 (declare (ignore ignore))
473 (simple-reader-error stream "illegal sharp macro character: ~S" sub-char))
475 ;;; for cold init: Install SHARPM stuff in the current *READTABLE*.
476 (defun !sharpm-cold-init ()
477 (make-dispatch-macro-character #\# t)
478 (set-dispatch-macro-character #\# #\\ #'sharp-backslash)
479 (set-dispatch-macro-character #\# #\' #'sharp-quote)
480 (set-dispatch-macro-character #\# #\( #'sharp-left-paren)
481 (set-dispatch-macro-character #\# #\* #'sharp-star)
482 (set-dispatch-macro-character #\# #\: #'sharp-colon)
483 (set-dispatch-macro-character #\# #\. #'sharp-dot)
484 ;; This used to set the dispatch-function for pairs of alphabetics, but
485 ;; {SET,GET}-DISPATCH-MACRO-CHARACTER and READ-DISPATCH-CHAR
486 ;; all use CHAR-UPCASE on the sub-char, so it makes no difference.
487 (set-dispatch-macro-character #\# #\r #'sharp-R)
488 (set-dispatch-macro-character #\# #\b #'sharp-B)
489 (set-dispatch-macro-character #\# #\o #'sharp-O)
490 (set-dispatch-macro-character #\# #\x #'sharp-X)
491 (set-dispatch-macro-character #\# #\a #'sharp-A)
492 (set-dispatch-macro-character #\# #\s #'sharp-S)
493 (set-dispatch-macro-character #\# #\= #'sharp-equal)
494 (set-dispatch-macro-character #\# #\# #'sharp-sharp)
495 (set-dispatch-macro-character #\# #\+ #'sharp-plus-minus)
496 (set-dispatch-macro-character #\# #\- #'sharp-plus-minus)
497 (set-dispatch-macro-character #\# #\c #'sharp-C)
498 (set-dispatch-macro-character #\# #\| #'sharp-vertical-bar)
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)))