diff options
| author | Gemini Lasswell | 2017-02-16 22:08:03 -0800 |
|---|---|---|
| committer | Noam Postavsky | 2017-02-23 20:21:11 -0500 |
| commit | 8b912ab47bc91f54565f127abf24c97e5d46a1ba (patch) | |
| tree | 107d90118764ae7df4fe0957bb01846ad1a5c858 | |
| parent | ba6c382404a9fe598be72e64beb21a90161ebb91 (diff) | |
| download | emacs-8b912ab47bc91f54565f127abf24c97e5d46a1ba.tar.gz emacs-8b912ab47bc91f54565f127abf24c97e5d46a1ba.zip | |
Support read syntax for circular objects in Edebug (Bug#23660)
* lisp/emacs-lisp/edebug.el (edebug-read-special): New name
for edebug-read-function. Handle the read syntax for circular
objects.
(edebug-read-objects): New variable.
(edebug-read-and-maybe-wrap-form1): Reset edebug-read-objects.
* src/lread.c (Fsubstitute_object_in_subtree): Make
substitute_object_in_subtree into a Lisp primitive.
| -rw-r--r-- | lisp/emacs-lisp/edebug.el | 60 | ||||
| -rw-r--r-- | src/lread.c | 12 |
2 files changed, 55 insertions, 17 deletions
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index a8838046a4d..267fc573d3a 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el | |||
| @@ -755,6 +755,11 @@ Maybe clear the markers and delete the symbol's edebug property?" | |||
| 755 | (defvar edebug-offsets-stack nil) | 755 | (defvar edebug-offsets-stack nil) |
| 756 | (defvar edebug-current-offset nil) ; Top of the stack, for convenience. | 756 | (defvar edebug-current-offset nil) ; Top of the stack, for convenience. |
| 757 | 757 | ||
| 758 | ;; The association list of objects read with the #n=object form. | ||
| 759 | ;; Each member of the list has the form (n . object), and is used to | ||
| 760 | ;; look up the object for the corresponding #n# construct. | ||
| 761 | (defvar edebug-read-objects nil) | ||
| 762 | |||
| 758 | ;; We must store whether we just read a list with a dotted form that | 763 | ;; We must store whether we just read a list with a dotted form that |
| 759 | ;; is itself a list. This structure will be condensed, so the offsets | 764 | ;; is itself a list. This structure will be condensed, so the offsets |
| 760 | ;; must also be condensed. | 765 | ;; must also be condensed. |
| @@ -826,7 +831,7 @@ Maybe clear the markers and delete the symbol's edebug property?" | |||
| 826 | (backquote . edebug-read-backquote) | 831 | (backquote . edebug-read-backquote) |
| 827 | (comma . edebug-read-comma) | 832 | (comma . edebug-read-comma) |
| 828 | (lbracket . edebug-read-vector) | 833 | (lbracket . edebug-read-vector) |
| 829 | (hash . edebug-read-function) | 834 | (hash . edebug-read-special) |
| 830 | )) | 835 | )) |
| 831 | 836 | ||
| 832 | (defun edebug-read-storing-offsets (stream) | 837 | (defun edebug-read-storing-offsets (stream) |
| @@ -872,17 +877,47 @@ Maybe clear the markers and delete the symbol's edebug property?" | |||
| 872 | (edebug-storing-offsets opoint symbol) | 877 | (edebug-storing-offsets opoint symbol) |
| 873 | (edebug-read-storing-offsets stream))))) | 878 | (edebug-read-storing-offsets stream))))) |
| 874 | 879 | ||
| 875 | (defun edebug-read-function (stream) | 880 | (defun edebug-read-special (stream) |
| 876 | ;; Turn #'thing into (function thing) | 881 | "Read from STREAM a Lisp object beginning with #. |
| 877 | (forward-char 1) | 882 | Turn #'thing into (function thing) and handle the read syntax for |
| 878 | (cond ((eq ?\' (following-char)) | 883 | circular objects. Let `read' read everything else." |
| 879 | (forward-char 1) | 884 | (catch 'return |
| 880 | (list | 885 | (forward-char 1) |
| 881 | (edebug-storing-offsets (- (point) 2) 'function) | 886 | (let ((start (point))) |
| 882 | (edebug-read-storing-offsets stream))) | 887 | (cond |
| 883 | (t | 888 | ((eq ?\' (following-char)) |
| 884 | (backward-char 1) | 889 | (forward-char 1) |
| 885 | (read stream)))) | 890 | (throw 'return |
| 891 | (list | ||
| 892 | (edebug-storing-offsets (- (point) 2) 'function) | ||
| 893 | (edebug-read-storing-offsets stream)))) | ||
| 894 | ((and (>= (following-char) ?0) (<= (following-char) ?9)) | ||
| 895 | (while (and (>= (following-char) ?0) (<= (following-char) ?9)) | ||
| 896 | (forward-char 1)) | ||
| 897 | (let ((n (string-to-number (buffer-substring start (point))))) | ||
| 898 | (when (and read-circle | ||
| 899 | (<= n most-positive-fixnum)) | ||
| 900 | (cond | ||
| 901 | ((eq ?= (following-char)) | ||
| 902 | ;; Make a placeholder for #n# to use temporarily. | ||
| 903 | (let* ((placeholder (cons nil nil)) | ||
| 904 | (elem (cons n placeholder))) | ||
| 905 | (push elem edebug-read-objects) | ||
| 906 | ;; Read the object and then replace the placeholder | ||
| 907 | ;; with the object itself, wherever it occurs. | ||
| 908 | (forward-char 1) | ||
| 909 | (let ((obj (edebug-read-storing-offsets stream))) | ||
| 910 | (substitute-object-in-subtree obj placeholder) | ||
| 911 | (throw 'return (setf (cdr elem) obj))))) | ||
| 912 | ((eq ?# (following-char)) | ||
| 913 | ;; #n# returns a previously read object. | ||
| 914 | (let ((elem (assq n edebug-read-objects))) | ||
| 915 | (when (consp elem) | ||
| 916 | (forward-char 1) | ||
| 917 | (throw 'return (cdr elem)))))))))) | ||
| 918 | ;; Let read handle errors, radix notation, and anything else. | ||
| 919 | (goto-char (1- start)) | ||
| 920 | (read stream)))) | ||
| 886 | 921 | ||
| 887 | (defun edebug-read-list (stream) | 922 | (defun edebug-read-list (stream) |
| 888 | (forward-char 1) ; skip \( | 923 | (forward-char 1) ; skip \( |
| @@ -1074,6 +1109,7 @@ Maybe clear the markers and delete the symbol's edebug property?" | |||
| 1074 | edebug-offsets | 1109 | edebug-offsets |
| 1075 | edebug-offsets-stack | 1110 | edebug-offsets-stack |
| 1076 | edebug-current-offset ; reset to nil | 1111 | edebug-current-offset ; reset to nil |
| 1112 | edebug-read-objects | ||
| 1077 | ) | 1113 | ) |
| 1078 | (save-excursion | 1114 | (save-excursion |
| 1079 | (if (and (eq 'lparen (edebug-next-token-class)) | 1115 | (if (and (eq 'lparen (edebug-next-token-class)) |
diff --git a/src/lread.c b/src/lread.c index 094aa628eec..1b154b7326e 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -558,8 +558,6 @@ static Lisp_Object read_vector (Lisp_Object, bool); | |||
| 558 | 558 | ||
| 559 | static Lisp_Object substitute_object_recurse (Lisp_Object, Lisp_Object, | 559 | static Lisp_Object substitute_object_recurse (Lisp_Object, Lisp_Object, |
| 560 | Lisp_Object); | 560 | Lisp_Object); |
| 561 | static void substitute_object_in_subtree (Lisp_Object, | ||
| 562 | Lisp_Object); | ||
| 563 | static void substitute_in_interval (INTERVAL, Lisp_Object); | 561 | static void substitute_in_interval (INTERVAL, Lisp_Object); |
| 564 | 562 | ||
| 565 | 563 | ||
| @@ -2957,7 +2955,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 2957 | tem = read0 (readcharfun); | 2955 | tem = read0 (readcharfun); |
| 2958 | 2956 | ||
| 2959 | /* Now put it everywhere the placeholder was... */ | 2957 | /* Now put it everywhere the placeholder was... */ |
| 2960 | substitute_object_in_subtree (tem, placeholder); | 2958 | Fsubstitute_object_in_subtree (tem, placeholder); |
| 2961 | 2959 | ||
| 2962 | /* ...and #n# will use the real value from now on. */ | 2960 | /* ...and #n# will use the real value from now on. */ |
| 2963 | Fsetcdr (cell, tem); | 2961 | Fsetcdr (cell, tem); |
| @@ -3326,8 +3324,10 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3326 | /* List of nodes we've seen during substitute_object_in_subtree. */ | 3324 | /* List of nodes we've seen during substitute_object_in_subtree. */ |
| 3327 | static Lisp_Object seen_list; | 3325 | static Lisp_Object seen_list; |
| 3328 | 3326 | ||
| 3329 | static void | 3327 | DEFUN ("substitute-object-in-subtree", Fsubstitute_object_in_subtree, |
| 3330 | substitute_object_in_subtree (Lisp_Object object, Lisp_Object placeholder) | 3328 | Ssubstitute_object_in_subtree, 2, 2, 0, |
| 3329 | doc: /* Replace every reference to PLACEHOLDER in OBJECT with OBJECT. */) | ||
| 3330 | (Lisp_Object object, Lisp_Object placeholder) | ||
| 3331 | { | 3331 | { |
| 3332 | Lisp_Object check_object; | 3332 | Lisp_Object check_object; |
| 3333 | 3333 | ||
| @@ -3345,6 +3345,7 @@ substitute_object_in_subtree (Lisp_Object object, Lisp_Object placeholder) | |||
| 3345 | original. */ | 3345 | original. */ |
| 3346 | if (!EQ (check_object, object)) | 3346 | if (!EQ (check_object, object)) |
| 3347 | error ("Unexpected mutation error in reader"); | 3347 | error ("Unexpected mutation error in reader"); |
| 3348 | return Qnil; | ||
| 3348 | } | 3349 | } |
| 3349 | 3350 | ||
| 3350 | /* Feval doesn't get called from here, so no gc protection is needed. */ | 3351 | /* Feval doesn't get called from here, so no gc protection is needed. */ |
| @@ -4548,6 +4549,7 @@ syms_of_lread (void) | |||
| 4548 | { | 4549 | { |
| 4549 | defsubr (&Sread); | 4550 | defsubr (&Sread); |
| 4550 | defsubr (&Sread_from_string); | 4551 | defsubr (&Sread_from_string); |
| 4552 | defsubr (&Ssubstitute_object_in_subtree); | ||
| 4551 | defsubr (&Sintern); | 4553 | defsubr (&Sintern); |
| 4552 | defsubr (&Sintern_soft); | 4554 | defsubr (&Sintern_soft); |
| 4553 | defsubr (&Sunintern); | 4555 | defsubr (&Sunintern); |