1 ;;;; cold-boot-only readmacro syntax
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-COLD")
16 ;;;; definition of #!+ and #!- as a mechanism analogous to #+/#-,
17 ;;;; but redirectable to any list of features. (This is handy when
18 ;;;; cross-compiling for making a distinction between features of the
19 ;;;; host Common Lisp and features of the target SBCL.)
21 ;;; the feature list for the target system
22 (export '*shebang-features*)
23 (declaim (type symbol *shebang-features*))
24 (defvar *shebang-features*)
26 (defun feature-in-list-p (feature list)
28 (symbol (member feature list :test #'eq))
29 (cons (flet ((subfeature-in-list-p (subfeature)
30 (feature-in-list-p subfeature list)))
31 (ecase (first feature)
32 (:or (some #'subfeature-in-list-p (rest feature)))
33 (:and (every #'subfeature-in-list-p (rest feature)))
34 (:not (let ((rest (cdr feature)))
35 (if (or (null (car rest)) (cdr rest))
36 (error "wrong number of terms in compound feature ~S"
38 (not (subfeature-in-list-p (second feature)))))))))))
39 (compile 'feature-in-list-p)
41 (defun shebang-reader (stream sub-character infix-parameter)
42 (declare (ignore sub-character))
44 (error "illegal read syntax: #~DT" infix-parameter))
45 (let ((next-char (read-char stream)))
46 (unless (find next-char "+-")
47 (error "illegal read syntax: #!~C" next-char))
48 ;; When test is not satisfied
49 ;; FIXME: clearer if order of NOT-P and (NOT NOT-P) were reversed? then
50 ;; would become "unless test is satisfied"..
51 (when (let* ((*package* (find-package "KEYWORD"))
53 (not-p (char= next-char #\-))
54 (feature (read stream)))
55 (if (feature-in-list-p feature *shebang-features*)
58 ;; Read (and discard) a form from input.
59 (let ((*read-suppress* t))
60 (read stream t nil t))))
62 (compile 'shebang-reader)
64 (set-dispatch-macro-character #\# #\! #'shebang-reader)
66 ;;;; FIXME: Would it be worth implementing this?
68 ;;;; readmacro syntax to remove spaces from FORMAT strings at compile time
69 ;;;; instead of leaving them to be skipped over at runtime
71 ;;; a counter of the number of bytes that we think we've avoided having to
72 ;;; compile into the system by virtue of doing compile-time processing
73 (defvar *shebang-double-quote--approx-bytes-saved* 0)
75 ;;; Read a string, strip out any #\~ #\NEWLINE whitespace sequence,
76 ;;; and return the result. (This is a subset of the processing performed
77 ;;; by FORMAT, but we perform it at compile time instead of postponing
78 ;;; it until run-time.
79 (defun shebang-double-quote (stream)
80 (labels ((rc () (read-char stream))
82 ;; Putting non-standard characters in the compiler source is
83 ;; generally a bad idea, since we'd like to be really portable.
84 ;; It's specifically a bad idea in strings intended to be
85 ;; processed by SHEBANG-DOUBLE-QUOTE, because there seems to be no
86 ;; portable way to test a non-STANDARD-CHAR for whitespaceness.
87 ;; (The most common problem would be to put a #\TAB -- which is
88 ;; not a STANDARD-CHAR -- into the string. If this is part of the
89 ;; to-be-skipped-over whitespace after a #\~ #\NEWLINE sequence in
90 ;; the string, it won't work, because it won't be recognized as
92 (unless (typep char 'standard-char)
93 (warn "non-STANDARD-CHAR in #!\": ~C" result))
94 (or (char= char #\newline)
95 (char= char #\space)))
100 (unread-char char stream)
102 (do ((adj-string (make-array 0 :element-type 'char :adjustable t))
104 ((char= char #\") (coerce adj-string 'simple-string))
105 (cond ((char= char #\~)
106 (let ((next-char (read-char stream)))
107 (cond ((char= next-char #\newline)
108 (incf *shebang-double-quote--approx-bytes-saved*
111 (vector-push-extend char adj-string)
112 (vector-push-extend next-char adj-string)))))
114 (vector-push-extend char adj-string)
115 (vector-push-extend (rc) adj-string))
116 (t (vector-push-extend char adj-string))))))
118 (setf (gethash #\" *shebang-dispatch*)
119 #'shebang-double-quote)