1 ;;;; code to manipulate symbols (but not packages, which are handled
4 ;;;; Many of these definitions are trivial interpreter entries to
5 ;;;; functions open-coded by the compiler.
7 ;;;; This software is part of the SBCL system. See the README file for
10 ;;;; This software is derived from the CMU CL system, which was
11 ;;;; written at Carnegie Mellon University and released into the
12 ;;;; public domain. The software is in the public domain and is
13 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
14 ;;;; files for more information.
16 (in-package "SB!IMPL")
18 (declaim (maybe-inline get get2 get3 %put getf remprop %putf get-properties keywordp))
20 (defun symbol-value (symbol)
22 "Return SYMBOL's current bound value."
23 (declare (optimize (safety 1)))
24 (symbol-value symbol))
26 (defun boundp (symbol)
28 "Return non-NIL if SYMBOL is bound to a value."
31 (defun set (symbol new-value)
33 "Set SYMBOL's value cell to NEW-VALUE."
34 (declare (type symbol symbol))
35 (about-to-modify-symbol-value symbol 'set new-value)
36 (%set-symbol-value symbol new-value))
38 (defun %set-symbol-value (symbol new-value)
39 (%set-symbol-value symbol new-value))
41 (defun symbol-global-value (symbol)
43 "Return the SYMBOL's current global value. Identical to SYMBOL-VALUE,
44 in single-threaded builds: in multithreaded builds bound values are
45 distinct from the global value. Can also be SETF."
46 (declare (optimize (safety 1)))
47 (symbol-global-value symbol))
49 (defun set-symbol-global-value (symbol new-value)
50 (about-to-modify-symbol-value symbol 'set new-value)
51 (sb!kernel:%set-symbol-global-value symbol new-value))
53 (declaim (inline %makunbound))
54 (defun %makunbound (symbol)
55 (%set-symbol-value symbol (%primitive sb!c:make-unbound-marker)))
57 (defun makunbound (symbol)
59 "Make SYMBOL unbound, removing any value it may currently have."
60 (with-single-package-locked-error (:symbol symbol "unbinding the symbol ~A")
61 (when (and (info :variable :always-bound symbol))
62 (error "Can't make ~A variable unbound: ~S" 'always-bound symbol))
63 (about-to-modify-symbol-value symbol 'makunbound)
67 ;;; Return the built-in hash value for SYMBOL.
68 (defun symbol-hash (symbol)
71 (defun symbol-function (symbol)
73 "Return SYMBOL's current function definition. Settable with SETF."
74 (%coerce-name-to-fun symbol))
76 (defun (setf symbol-function) (new-value symbol)
77 (declare (type symbol symbol) (type function new-value))
78 (with-single-package-locked-error
79 (:symbol symbol "setting the symbol-function of ~A")
80 (setf (%coerce-name-to-fun symbol) new-value)))
82 (defun symbol-plist (symbol)
84 "Return SYMBOL's property list."
85 (symbol-plist symbol))
87 (defun %set-symbol-plist (symbol new-value)
88 (setf (symbol-plist symbol) new-value))
90 (defun symbol-name (symbol)
92 "Return SYMBOL's name as a string."
95 (defun symbol-package (symbol)
97 "Return the package SYMBOL was interned in, or NIL if none."
98 (symbol-package symbol))
100 (defun %set-symbol-package (symbol package)
101 (declare (type symbol symbol))
102 (%set-symbol-package symbol package))
104 (defun make-symbol (string)
106 "Make and return a new symbol with the STRING as its print name."
107 (declare (type string string))
108 (%make-symbol (if (simple-string-p string)
112 (defun get (symbol indicator &optional (default nil))
114 "Look on the property list of SYMBOL for the specified INDICATOR. If this
115 is found, return the associated value, else return DEFAULT."
116 (get3 symbol indicator default))
118 (defun get2 (symbol indicator)
119 (get3 symbol indicator nil))
122 (do ((pl (symbol-plist symbol) (cdr cdr-pl)))
124 (setf cdr-pl (cdr pl))
126 (error "~S has an odd number of items in its property list."
128 ((eq (car pl) indicator)
129 (return (car cdr-pl)))))))
132 (defun get3 (symbol indicator default)
134 (do ((pl (symbol-plist symbol) (cdr cdr-pl)))
136 (setq cdr-pl (cdr pl))
138 (error "~S has an odd number of items in its property list."
140 ((eq (car pl) indicator)
141 (return (car cdr-pl)))))))
143 (defun %put (symbol indicator value)
145 "The VALUE is added as a property of SYMBOL under the specified INDICATOR.
147 (do ((pl (symbol-plist symbol) (cddr pl)))
149 (setf (symbol-plist symbol)
150 (list* indicator value (symbol-plist symbol)))
152 (cond ((endp (cdr pl))
153 (error "~S has an odd number of items in its property list."
155 ((eq (car pl) indicator)
156 (rplaca (cdr pl) value)
159 (defun remprop (symbol indicator)
161 "Look on property list of SYMBOL for property with specified
162 INDICATOR. If found, splice this indicator and its value out of
163 the plist, and return the tail of the original list starting with
164 INDICATOR. If not found, return () with no side effects.
166 NOTE: The ANSI specification requires REMPROP to return true (not false)
167 or false (the symbol NIL). Portable code should not rely on any other value."
168 (do ((pl (symbol-plist symbol) (cddr pl))
171 (cond ((atom (cdr pl))
172 (error "~S has an odd number of items in its property list."
174 ((eq (car pl) indicator)
175 (cond (prev (rplacd (cdr prev) (cddr pl)))
177 (setf (symbol-plist symbol) (cddr pl))))
180 (defun getf (place indicator &optional (default ()))
182 "Search the property list stored in PLACE for an indicator EQ to INDICATOR.
183 If one is found, return the corresponding value, else return DEFAULT."
184 (do ((plist place (cddr plist)))
185 ((null plist) default)
186 (cond ((atom (cdr plist))
187 (error 'simple-type-error
188 :format-control "malformed property list: ~S."
189 :format-arguments (list place)
191 :expected-type 'cons))
192 ((eq (car plist) indicator)
193 (return (cadr plist))))))
195 (defun %putf (place property new-value)
196 (declare (type list place))
197 (do ((plist place (cddr plist)))
198 ((endp plist) (list* property new-value place))
199 (declare (type list plist))
200 (when (eq (car plist) property)
201 (setf (cadr plist) new-value)
204 (defun get-properties (place indicator-list)
206 "Like GETF, except that INDICATOR-LIST is a list of indicators which will
207 be looked for in the property list stored in PLACE. Three values are
208 returned, see manual for details."
209 (do ((plist place (cddr plist)))
210 ((null plist) (values nil nil nil))
211 (cond ((atom (cdr plist))
212 (error 'simple-type-error
213 :format-control "malformed property list: ~S."
214 :format-arguments (list place)
216 :expected-type 'cons))
217 ((memq (car plist) indicator-list)
218 (return (values (car plist) (cadr plist) plist))))))
220 (defun copy-symbol (symbol &optional (copy-props nil) &aux new-symbol)
222 "Make and return a new uninterned symbol with the same print name
223 as SYMBOL. If COPY-PROPS is false, the new symbol is neither bound
224 nor fbound and has no properties, else it has a copy of SYMBOL's
225 function, value and property list."
226 (declare (type symbol symbol))
227 (setq new-symbol (make-symbol (symbol-name symbol)))
229 (%set-symbol-value new-symbol
230 (%primitive sb!c:fast-symbol-value symbol))
231 (setf (symbol-plist new-symbol)
232 (copy-list (symbol-plist symbol)))
233 (when (fboundp symbol)
234 (setf (symbol-function new-symbol) (symbol-function symbol))))
237 ;;; FIXME: This declaration should be redundant.
238 (declaim (special *keyword-package*))
240 (defun keywordp (object)
242 "Return true if Object is a symbol in the \"KEYWORD\" package."
243 (and (symbolp object)
244 (eq (symbol-package object) *keyword-package*)))
246 ;;;; GENSYM and friends
248 (defun %make-symbol-name (prefix counter)
249 (with-output-to-string (s)
250 (write-string prefix s)
251 (%output-integer-in-base counter 10 s)))
253 (defvar *gensym-counter* 0
255 "counter for generating unique GENSYM symbols")
256 (declaim (type unsigned-byte *gensym-counter*))
258 (defun gensym (&optional (thing "G"))
260 "Creates a new uninterned symbol whose name is a prefix string (defaults
261 to \"G\"), followed by a decimal number. Thing, when supplied, will
262 alter the prefix if it is a string, or be used for the decimal number
263 if it is a number, of this symbol. The default value of the number is
264 the current value of *gensym-counter* which is incremented each time
266 (let ((old *gensym-counter*))
267 (unless (numberp thing)
268 (let ((new (etypecase old
270 (unsigned-byte (1+ old)))))
271 (declare (optimize (speed 3) (safety 0) (inhibit-warnings 3)))
272 (setq *gensym-counter* new)))
273 (multiple-value-bind (prefix int)
275 (simple-string (values thing old))
276 (unsigned-byte (values "G" thing))
277 (string (values (coerce thing 'simple-string) old)))
278 (declare (simple-string prefix))
279 (make-symbol (%make-symbol-name prefix int)))))
281 (defvar *gentemp-counter* 0)
282 (declaim (type unsigned-byte *gentemp-counter*))
284 (defun gentemp (&optional (prefix "T") (package (sane-package)))
286 "Creates a new symbol interned in package PACKAGE with the given PREFIX."
287 (declare (type string prefix))
288 (loop for name = (%make-symbol-name prefix (incf *gentemp-counter*))
289 while (nth-value 1 (find-symbol name package))
290 finally (return (values (intern name package)))))
292 ;;; This function is to be called just before a change which would affect the
293 ;;; symbol value. We don't absolutely have to call this function before such
294 ;;; changes, since such changes to constants are given as undefined behavior,
295 ;;; it's nice to do so. To circumvent this you need code like this:
298 ;;; (defun set-foo (x) (setq foo x))
299 ;;; (defconstant foo 42)
301 ;;; foo => 13, (constantp 'foo) => t
303 ;;; ...in which case you frankly deserve to lose.
304 (defun about-to-modify-symbol-value (symbol action &optional (new-value nil valuep) bind)
305 (declare (symbol symbol))
306 (flet ((describe-action ()
308 (set "set SYMBOL-VALUE of ~S")
310 (compare-and-swap "compare-and-swap SYMBOL-VALUE of ~S")
311 (defconstant "define ~S as a constant")
312 (makunbound "make ~S unbound"))))
313 (let ((kind (info :variable :kind symbol)))
314 (multiple-value-bind (what continue)
315 (cond ((eq :constant kind)
317 (values "Veritas aeterna. (can't ~@?)" nil))
319 (values "Nihil ex nihil. (can't ~@?)" nil))
321 (values "Can't ~@?." nil))
323 (values "Constant modification: attempt to ~@?." t))))
324 ((and bind (eq :global kind))
325 (values "Can't ~@? (global variable)." nil)))
328 (cerror "Modify the constant." what (describe-action) symbol)
329 (error what (describe-action) symbol)))
331 ;; :VARIABLE :TYPE is in the db only if it is declared, so no need to
333 (let ((type (info :variable :type symbol)))
334 (unless (sb!kernel::%%typep new-value type nil)
335 (let ((spec (type-specifier type)))
336 (error 'simple-type-error
337 :format-control "~@<Cannot ~@? to ~S, not of type ~S.~:@>"
338 :format-arguments (list (describe-action) symbol new-value spec)
340 :expected-type spec))))))))