Mercurial > emacs
changeset 25165:8b9110694bfa
(read1): Added circular reading code to #N=.
(SUBSTITUTE): New macro.
(seen_list): New variable.
(substitute_object_in_subtree): New function.
(substitute_object_recurse): New function.
(substitute_in_interval): New function.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Tue, 03 Aug 1999 17:27:46 +0000 |
parents | 8e7561d048f5 |
children | e8ec0085ff7b |
files | src/lread.c |
diffstat | 1 files changed, 144 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lread.c Tue Aug 03 15:59:18 1999 +0000 +++ b/src/lread.c Tue Aug 03 17:27:46 1999 +0000 @@ -408,6 +408,9 @@ static Lisp_Object read0 (), read1 (), read_list (), read_vector (); static int read_multibyte (); +static Lisp_Object substitute_object_recurse (); +static void substitute_object_in_subtree (), substitute_in_interval (); + /* Get a character from the tty. */ @@ -1806,8 +1809,23 @@ /* #n=object returns object, but associates it with n for #n#. */ if (c == '=') { + /* Make a placeholder for #n# to use temporarily */ + Lisp_Object placeholder; + Lisp_Object cell; + + placeholder = Fcons(Qnil, Qnil); + cell = Fcons (make_number (n), placeholder); + read_objects = Fcons (cell, read_objects); + + /* Read the object itself. */ tem = read0 (readcharfun); - read_objects = Fcons (Fcons (make_number (n), tem), read_objects); + + /* Now put it everywhere the placeholder was... */ + substitute_object_in_subtree (tem, placeholder); + + /* ...and #n# will use the real value from now on. */ + Fsetcdr (cell, tem); + return tem; } /* #n# returns a previously read object. */ @@ -2163,6 +2181,129 @@ } } + +/* List of nodes we've seen during substitute_object_in_subtree. */ +static Lisp_Object seen_list; + +static void +substitute_object_in_subtree (object, placeholder) + Lisp_Object object; + Lisp_Object placeholder; +{ + Lisp_Object check_object; + + /* We haven't seen any objects when we start. */ + seen_list = Qnil; + + /* Make all the substitutions. */ + check_object + = substitute_object_recurse (object, placeholder, object); + + /* Clear seen_list because we're done with it. */ + seen_list = Qnil; + + /* The returned object here is expected to always eq the + original. */ + if (!EQ (check_object, object)) + error ("Unexpected mutation error in reader"); +} + +/* Feval doesn't get called from here, so no gc protection is needed. */ +#define SUBSTITUTE(get_val, set_val) \ +{ \ + Lisp_Object old_value = get_val; \ + Lisp_Object true_value \ + = substitute_object_recurse (object, placeholder,\ + old_value); \ + \ + if (!EQ (old_value, true_value)) \ + { \ + set_val; \ + } \ +} + +static Lisp_Object +substitute_object_recurse (object, placeholder, subtree) + Lisp_Object object; + Lisp_Object placeholder; + Lisp_Object subtree; +{ + /* If we find the placeholder, return the target object. */ + if (EQ (placeholder, subtree)) + return object; + + /* If we've been to this node before, don't explore it again. */ + if (!EQ (Qnil, Fmemq (subtree, seen_list))) + return subtree; + + /* If this node can be the entry point to a cycle, remember that + we've seen it. It can only be such an entry point if it was made + by #n=, which means that we can find it as a value in + read_objects. */ + if (!EQ (Qnil, Frassq (subtree, read_objects))) + seen_list = Fcons (subtree, seen_list); + + /* Recurse according to subtree's type. + Every branch must return a Lisp_Object. */ + switch (XTYPE (subtree)) + { + case Lisp_Vectorlike: + { + int i; + int length = Flength(subtree); + for (i = 0; i < length; i++) + { + Lisp_Object idx = make_number (i); + SUBSTITUTE (Faref (subtree, idx), + Faset (subtree, idx, true_value)); + } + return subtree; + } + + case Lisp_Cons: + { + SUBSTITUTE (Fcar_safe (subtree), + Fsetcar (subtree, true_value)); + SUBSTITUTE (Fcdr_safe (subtree), + Fsetcdr (subtree, true_value)); + return subtree; + } + +#ifdef USE_TEXT_PROPERTIES + case Lisp_String: + { + /* Check for text properties in each interval. + substitute_in_interval contains part of the logic. */ + + INTERVAL root_interval = XSTRING (subtree)->intervals; + Lisp_Object arg = Fcons (object, placeholder); + + traverse_intervals (root_interval, 1, 0, + &substitute_in_interval, arg); + + return subtree; + } +#endif /* defined USE_TEXT_PROPERTIES */ + + /* Other types don't recurse any further. */ + default: + return subtree; + } +} + +/* Helper function for substitute_object_recurse. */ +static void +substitute_in_interval (interval, arg) + INTERVAL interval; + Lisp_Object arg; +{ + Lisp_Object object = Fcar (arg); + Lisp_Object placeholder = Fcdr (arg); + + SUBSTITUTE(interval->plist, interval->plist = true_value); +} + + #ifdef LISP_FLOAT_TYPE #define LEAD_INT 1 @@ -3306,4 +3447,6 @@ staticpro (&read_objects); read_objects = Qnil; + staticpro (&seen_list); + }