X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcode%2Fearly-extensions.lisp;h=028707c8baea741dfa228fbe6f4c7b4c95fd553c;hb=d4345a2363f9cbf440e6a5d52f8451c4f903cefd;hp=bde43c174e916d2b50bd99956f47ff228ef65eb5;hpb=11802a47e04b0dbfbfec03d8b438fb59f84ce35d;p=sbcl.git diff --git a/src/code/early-extensions.lisp b/src/code/early-extensions.lisp index bde43c1..028707c 100644 --- a/src/code/early-extensions.lisp +++ b/src/code/early-extensions.lisp @@ -430,7 +430,6 @@ (eq (car clause) 'ignore)))) (cdr decl)))) decls)) - ;;; just like DOLIST, but with one-dimensional arrays (defmacro dovector ((elt vector &optional result) &body body) (multiple-value-bind (forms decls) (parse-body body :doc-string-allowed nil) @@ -464,6 +463,19 @@ `(with-locked-system-table (,n-table) ,iter-form) iter-form)))))) + +;;; Executes BODY for all entries of PLIST with KEY and VALUE bound to +;;; the respective keys and values. +(defmacro doplist ((key val) plist &body body) + (with-unique-names (tail) + `(let ((,tail ,plist) ,key ,val) + (loop (when (null ,tail) (return nil)) + (setq ,key (pop ,tail)) + (when (null ,tail) + (error "malformed plist, odd number of elements")) + (setq ,val (pop ,tail)) + (progn ,@body))))) + ;;;; hash cache utility @@ -826,7 +838,7 @@ (let* ((name (first spec)) (exp-temp (gensym "ONCE-ONLY"))) `(let ((,exp-temp ,(second spec)) - (,name (gensym ,(symbol-name name)))) + (,name (sb!xc:gensym ,(symbol-name name)))) `(let ((,,name ,,exp-temp)) ,,(frob (rest specs) body)))))))) @@ -1140,6 +1152,8 @@ ;;; deprecated.texinfo. ;;; ;;; EARLY: +;;; - SB-THREAD::GET-MUTEX, since 1.0.37.33 (04/2010) -> Late: 01/2013 +;;; ^- initially deprecated without compile-time warning, hence the schedule ;;; - SB-THREAD::SPINLOCK (type), since 1.0.53.11 (08/2011) -> Late: 08/2012 ;;; - SB-THREAD::MAKE-SPINLOCK, since 1.0.53.11 (08/2011) -> Late: 08/2012 ;;; - SB-THREAD::WITH-SPINLOCK, since 1.0.53.11 (08/2011) -> Late: 08/2012 @@ -1152,9 +1166,11 @@ ;;; - SB-C::MERGE-TAIL-CALLS (policy), since 1.0.53.74 (11/2011) -> Late: 11/2012 ;;; - SB-EXT:QUIT, since 1.0.56.55 (05/2012) -> Late: 05/2013 ;;; - SB-UNIX:UNIX-EXIT, since 1.0.56.55 (05/2012) -> Late: 05/2013 +;;; - SB-DEBUG:*SHOW-ENTRY-POINT-DETAILS*, since 1.1.4.9 (02/2013) -> Late: 02/2014 ;;; ;;; LATE: ;;; - SB-SYS:OUTPUT-RAW-BYTES, since 1.0.8.16 (06/2007) -> Final: anytime +;;; Note: make sure CLX doesn't use it anymore! ;;; - SB-C::STACK-ALLOCATE-DYNAMIC-EXTENT (policy), since 1.0.19.7 -> Final: anytime ;;; - SB-C::STACK-ALLOCATE-VECTOR (policy), since 1.0.19.7 -> Final: anytime ;;; - SB-C::STACK-ALLOCATE-VALUE-CELLS (policy), since 1.0.19.7 -> Final: anytime @@ -1164,19 +1180,22 @@ (defmacro define-deprecated-function (state since name replacements lambda-list &body body) (let* ((replacements (normalize-deprecation-replacements replacements)) - (doc (let ((*package* (find-package :keyword))) - (apply #'format nil - "~@<~S has been deprecated as of SBCL ~A.~ - ~#[~; Use ~S instead.~; ~ - Use ~S or ~S instead.~:; ~ - Use~@{~#[~; or~] ~S~^,~} instead.~]~@:>" - name since replacements)))) + (doc + (let ((*package* (find-package :keyword)) + (*print-pretty* nil)) + (apply #'format nil + "~S has been deprecated as of SBCL ~A.~ + ~#[~;~2%Use ~S instead.~;~2%~ + Use ~S or ~S instead.~:;~2%~ + Use~@{~#[~; or~] ~S~^,~} instead.~]" + name since replacements)))) `(progn ,(ecase state ((:early :late) - `(defun ,name ,lambda-list - ,doc - ,@body)) + `(progn + (defun ,name ,lambda-list + ,doc + ,@body))) ((:final) `(progn (declaim (ftype (function * nil) ,name)) @@ -1186,6 +1205,21 @@ (setf (compiler-macro-function ',name) (deprecation-compiler-macro ,state ,since ',name ',replacements))))) +(defun check-deprecated-variable (name) + (let ((info (info :variable :deprecated name))) + (when info + (deprecation-warning (car info) (cdr info) name nil)))) + +(defmacro define-deprecated-variable (state since name &key (value nil valuep) replacement) + `(progn + (setf (info :variable :deprecated ',name) (cons ,state ,since)) + ,@(when (member state '(:early :late)) + `((defvar ,name ,@(when valuep (list value)) + ,(let ((*package* (find-package :keyword))) + (format nil + "~@<~S has been deprecated as of SBCL ~A~@[, use ~S instead~].~:>" + name since replacement))))))) + ;;; Anaphoric macros (defmacro awhen (test &body body) `(let ((it ,test)) @@ -1295,12 +1329,16 @@ ;;; Returns a list of members of LIST. Useful for dealing with circular lists. ;;; For a dotted list returns a secondary value of T -- in which case the ;;; primary return value does not include the dotted tail. -(defun list-members (list) +;;; If the maximum length is reached, return a secondary value of :MAYBE. +(defun list-members (list &key max-length) (when list (do ((tail (cdr list) (cdr tail)) - (members (list (car list)) (cons (car tail) members))) - ((or (not (consp tail)) (eq tail list)) - (values members (not (listp tail))))))) + (members (list (car list)) (cons (car tail) members)) + (count 0 (1+ count))) + ((or (not (consp tail)) (eq tail list) + (and max-length (>= count max-length))) + (values members (or (not (listp tail)) + (and (>= count max-length) :maybe))))))) ;;; Default evaluator mode (interpeter / compiler) @@ -1352,3 +1390,44 @@ to :INTERPRET, an interpreter will be used.") (if (eql x 0.0l0) (make-unportable-float :long-float-negative-zero) 0.0l0)))) + +;;; Signalling an error when trying to print an error condition is +;;; generally a PITA, so whatever the failure encountered when +;;; wondering about FILE-POSITION within a condition printer, 'tis +;;; better silently to give up than to try to complain. +(defun file-position-or-nil-for-error (stream &optional (pos nil posp)) + ;; Arguably FILE-POSITION shouldn't be signalling errors at all; but + ;; "NIL if this cannot be determined" in the ANSI spec doesn't seem + ;; absolutely unambiguously to prohibit errors when, e.g., STREAM + ;; has been closed so that FILE-POSITION is a nonsense question. So + ;; my (WHN) impression is that the conservative approach is to + ;; IGNORE-ERRORS. (I encountered this failure from within a homebrew + ;; defsystemish operation where the ERROR-STREAM had been CL:CLOSEd, + ;; I think by nonlocally exiting through a WITH-OPEN-FILE, by the + ;; time an error was reported.) + (if posp + (ignore-errors (file-position stream pos)) + (ignore-errors (file-position stream)))) + +(defun stream-error-position-info (stream &optional position) + (unless (interactive-stream-p stream) + (let ((now (file-position-or-nil-for-error stream)) + (pos position)) + (when (and (not pos) now (plusp now)) + ;; FILE-POSITION is the next character -- error is at the previous one. + (setf pos (1- now))) + (let (lineno colno) + (when (and pos + (< pos sb!xc:array-dimension-limit) + (file-position stream :start)) + (let ((string + (make-string pos :element-type (stream-element-type stream)))) + (when (= pos (read-sequence string stream)) + ;; Lines count from 1, columns from 0. It's stupid and traditional. + (setq lineno (1+ (count #\Newline string)) + colno (- pos (or (position #\Newline string :from-end t) 0))))) + (file-position-or-nil-for-error stream now)) + (remove-if-not #'second + (list (list :line lineno) + (list :column colno) + (list :file-position pos)))))))