(in-package "SB!IMPL")
-(declaim (maybe-inline get get2 get3 %put getf remprop %putf get-properties keywordp))
+(declaim (maybe-inline get get3 %put getf remprop %putf get-properties keywordp))
(defun symbol-value (symbol)
#!+sb-doc
(declare (optimize (safety 1)))
(symbol-value symbol))
+#-sb-xc-host
+(define-compiler-macro symbol-value (&whole form symbol &environment env)
+ (when (sb!xc:constantp symbol env)
+ (let ((name (constant-form-value symbol env)))
+ (when (symbolp name)
+ (check-deprecated-variable name))))
+ form)
+
(defun boundp (symbol)
#!+sb-doc
"Return non-NIL if SYMBOL is bound to a value."
(declaim (inline %makunbound))
(defun %makunbound (symbol)
- (%set-symbol-value symbol (%primitive sb!c:make-other-immediate-type
- 0 sb!vm:unbound-marker-widetag)))
+ (%set-symbol-value symbol (%primitive sb!c:make-unbound-marker)))
(defun makunbound (symbol)
#!+sb-doc
is found, return the associated value, else return DEFAULT."
(get3 symbol indicator default))
-(defun get2 (symbol indicator)
- (get3 symbol indicator nil))
-#|
- (let (cdr-pl)
- (do ((pl (symbol-plist symbol) (cdr cdr-pl)))
- ((atom pl) nil)
- (setf cdr-pl (cdr pl))
- (cond ((atom cdr-pl)
- (error "~S has an odd number of items in its property list."
- symbol))
- ((eq (car pl) indicator)
- (return (car cdr-pl)))))))
-|#
-
(defun get3 (symbol indicator default)
(let (cdr-pl)
(do ((pl (symbol-plist symbol) (cdr cdr-pl)))
(multiple-value-bind (prefix int)
(etypecase thing
(simple-string (values thing old))
- (fixnum (values "G" thing))
+ (unsigned-byte (values "G" thing))
(string (values (coerce thing 'simple-string) old)))
(declare (simple-string prefix))
(make-symbol (%make-symbol-name prefix int)))))
(loop for name = (%make-symbol-name prefix (incf *gentemp-counter*))
while (nth-value 1 (find-symbol name package))
finally (return (values (intern name package)))))
+
+;;; This function is to be called just before a change which would affect the
+;;; symbol value. We don't absolutely have to call this function before such
+;;; changes, since such changes to constants are given as undefined behavior,
+;;; it's nice to do so. To circumvent this you need code like this:
+;;;
+;;; (defvar foo)
+;;; (defun set-foo (x) (setq foo x))
+;;; (defconstant foo 42)
+;;; (set-foo 13)
+;;; foo => 13, (constantp 'foo) => t
+;;;
+;;; ...in which case you frankly deserve to lose.
+(defun about-to-modify-symbol-value (symbol action &optional (new-value nil valuep) bind)
+ (declare (symbol symbol))
+ (flet ((describe-action ()
+ (ecase action
+ (set "set SYMBOL-VALUE of ~S")
+ (progv "bind ~S")
+ (compare-and-swap "compare-and-swap SYMBOL-VALUE of ~S")
+ (defconstant "define ~S as a constant")
+ (makunbound "make ~S unbound"))))
+ (let ((kind (info :variable :kind symbol)))
+ (multiple-value-bind (what continue)
+ (cond ((eq :constant kind)
+ (cond ((eq symbol t)
+ (values "Veritas aeterna. (can't ~@?)" nil))
+ ((eq symbol nil)
+ (values "Nihil ex nihil. (can't ~@?)" nil))
+ ((keywordp symbol)
+ (values "Can't ~@?." nil))
+ (t
+ (values "Constant modification: attempt to ~@?." t))))
+ ((and bind (eq :global kind))
+ (values "Can't ~@? (global variable)." nil)))
+ (when what
+ (if continue
+ (cerror "Modify the constant." what (describe-action) symbol)
+ (error what (describe-action) symbol)))
+ (when valuep
+ ;; :VARIABLE :TYPE is in the db only if it is declared, so no need to
+ ;; check.
+ (let ((type (info :variable :type symbol)))
+ (unless (sb!kernel::%%typep new-value type nil)
+ (let ((spec (type-specifier type)))
+ (error 'simple-type-error
+ :format-control "~@<Cannot ~@? to ~S, not of type ~S.~:@>"
+ :format-arguments (list (describe-action) symbol new-value spec)
+ :datum new-value
+ :expected-type spec))))))))
+ (values))