diff options
| author | Noam Postavsky | 2017-05-28 17:01:05 -0400 |
|---|---|---|
| committer | Noam Postavsky | 2017-05-31 07:45:43 -0400 |
| commit | a415c8bccb917c247792c4ce8e77b2512b3414d6 (patch) | |
| tree | 222b1fd62276c7220ed06b13e2125e51e96c567c | |
| parent | 94306c8b0d61a53b19dcee18475ea8692b001f5d (diff) | |
| download | emacs-a415c8bccb917c247792c4ce8e77b2512b3414d6.tar.gz emacs-a415c8bccb917c247792c4ce8e77b2512b3414d6.zip | |
cl-print: handle circular objects when `print-circle' is nil (Bug#27117)
* lisp/emacs-lisp/cl-print.el (cl-print--currently-printing): New variable.
(cl-print-object): When `print-circle' is nil, bind it to a list of
objects that are currently printing to avoid printing the same object
endlessly.
* test/lisp/emacs-lisp/cl-print-tests.el (cl-print-circle): New test.
| -rw-r--r-- | lisp/emacs-lisp/cl-print.el | 35 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/cl-print-tests.el | 8 |
2 files changed, 32 insertions, 11 deletions
diff --git a/lisp/emacs-lisp/cl-print.el b/lisp/emacs-lisp/cl-print.el index 65c86d2b65e..70ccaac17b3 100644 --- a/lisp/emacs-lisp/cl-print.el +++ b/lisp/emacs-lisp/cl-print.el | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | "If non-nil, try and make sure the result can be `read'.") | 37 | "If non-nil, try and make sure the result can be `read'.") |
| 38 | 38 | ||
| 39 | (defvar cl-print--number-table nil) | 39 | (defvar cl-print--number-table nil) |
| 40 | (defvar cl-print--currently-printing nil) | ||
| 40 | 41 | ||
| 41 | ;;;###autoload | 42 | ;;;###autoload |
| 42 | (cl-defgeneric cl-print-object (object stream) | 43 | (cl-defgeneric cl-print-object (object stream) |
| @@ -59,8 +60,9 @@ call other entry points instead, such as `cl-prin1'." | |||
| 59 | (princ "(" stream) | 60 | (princ "(" stream) |
| 60 | (cl-print-object car stream) | 61 | (cl-print-object car stream) |
| 61 | (while (and (consp object) | 62 | (while (and (consp object) |
| 62 | (not (and cl-print--number-table | 63 | (not (if cl-print--number-table |
| 63 | (numberp (gethash object cl-print--number-table))))) | 64 | (numberp (gethash object cl-print--number-table)) |
| 65 | (memq object cl-print--currently-printing)))) | ||
| 64 | (princ " " stream) | 66 | (princ " " stream) |
| 65 | (cl-print-object (pop object) stream)) | 67 | (cl-print-object (pop object) stream)) |
| 66 | (when object | 68 | (when object |
| @@ -156,15 +158,26 @@ call other entry points instead, such as `cl-prin1'." | |||
| 156 | 158 | ||
| 157 | (cl-defmethod cl-print-object :around (object stream) | 159 | (cl-defmethod cl-print-object :around (object stream) |
| 158 | ;; FIXME: Only put such an :around method on types where it's relevant. | 160 | ;; FIXME: Only put such an :around method on types where it's relevant. |
| 159 | (let ((n (if cl-print--number-table (gethash object cl-print--number-table)))) | 161 | (cond |
| 160 | (if (not (numberp n)) | 162 | (print-circle |
| 161 | (cl-call-next-method) | 163 | (let ((n (gethash object cl-print--number-table))) |
| 162 | (if (> n 0) | 164 | (if (not (numberp n)) |
| 163 | ;; Already printed. Just print a reference. | 165 | (cl-call-next-method) |
| 164 | (progn (princ "#" stream) (princ n stream) (princ "#" stream)) | 166 | (if (> n 0) |
| 165 | (puthash object (- n) cl-print--number-table) | 167 | ;; Already printed. Just print a reference. |
| 166 | (princ "#" stream) (princ (- n) stream) (princ "=" stream) | 168 | (progn (princ "#" stream) (princ n stream) (princ "#" stream)) |
| 167 | (cl-call-next-method))))) | 169 | (puthash object (- n) cl-print--number-table) |
| 170 | (princ "#" stream) (princ (- n) stream) (princ "=" stream) | ||
| 171 | (cl-call-next-method))))) | ||
| 172 | ((let ((already-printing (memq object cl-print--currently-printing))) | ||
| 173 | (when already-printing | ||
| 174 | ;; Currently printing, just print reference to avoid endless | ||
| 175 | ;; recursion. | ||
| 176 | (princ "#" stream) | ||
| 177 | (princ (length (cdr already-printing)) stream)))) | ||
| 178 | (t (let ((cl-print--currently-printing | ||
| 179 | (cons object cl-print--currently-printing))) | ||
| 180 | (cl-call-next-method))))) | ||
| 168 | 181 | ||
| 169 | (defvar cl-print--number-index nil) | 182 | (defvar cl-print--number-index nil) |
| 170 | 183 | ||
diff --git a/test/lisp/emacs-lisp/cl-print-tests.el b/test/lisp/emacs-lisp/cl-print-tests.el index 772601fe87d..dfbe18d7844 100644 --- a/test/lisp/emacs-lisp/cl-print-tests.el +++ b/test/lisp/emacs-lisp/cl-print-tests.el | |||
| @@ -47,4 +47,12 @@ | |||
| 47 | "\\`(#1=#s(foo 1 2 3) #1#)\\'" | 47 | "\\`(#1=#s(foo 1 2 3) #1#)\\'" |
| 48 | (cl-prin1-to-string (list x x))))))) | 48 | (cl-prin1-to-string (list x x))))))) |
| 49 | 49 | ||
| 50 | (ert-deftest cl-print-circle () | ||
| 51 | (let ((x '(#1=(a . #1#) #1#))) | ||
| 52 | (let ((print-circle nil)) | ||
| 53 | (should (string-match "\\`((a . #[0-9]) (a . #[0-9]))\\'" | ||
| 54 | (cl-prin1-to-string x)))) | ||
| 55 | (let ((print-circle t)) | ||
| 56 | (should (equal "(#1=(a . #1#) #1#)" (cl-prin1-to-string x)))))) | ||
| 57 | |||
| 50 | ;;; cl-print-tests.el ends here. | 58 | ;;; cl-print-tests.el ends here. |