aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard M. Stallman1999-08-03 17:27:46 +0000
committerRichard M. Stallman1999-08-03 17:27:46 +0000
commit9e062b6cc0b94f41969070fec398b922c5210737 (patch)
treeba07572f9d4597f3e12c065b3940c05899fd87c6 /src
parent08f87e3ce5f6bd5c1b1f017866937ad54b641a76 (diff)
downloademacs-9e062b6cc0b94f41969070fec398b922c5210737.tar.gz
emacs-9e062b6cc0b94f41969070fec398b922c5210737.zip
(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.
Diffstat (limited to 'src')
-rw-r--r--src/lread.c145
1 files changed, 144 insertions, 1 deletions
diff --git a/src/lread.c b/src/lread.c
index 479281c8c05..3821557cffb 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -408,6 +408,9 @@ unreadchar (readcharfun, c)
408 408
409static Lisp_Object read0 (), read1 (), read_list (), read_vector (); 409static Lisp_Object read0 (), read1 (), read_list (), read_vector ();
410static int read_multibyte (); 410static int read_multibyte ();
411static Lisp_Object substitute_object_recurse ();
412static void substitute_object_in_subtree (), substitute_in_interval ();
413
411 414
412/* Get a character from the tty. */ 415/* Get a character from the tty. */
413 416
@@ -1806,8 +1809,23 @@ read1 (readcharfun, pch, first_in_list)
1806 /* #n=object returns object, but associates it with n for #n#. */ 1809 /* #n=object returns object, but associates it with n for #n#. */
1807 if (c == '=') 1810 if (c == '=')
1808 { 1811 {
1812 /* Make a placeholder for #n# to use temporarily */
1813 Lisp_Object placeholder;
1814 Lisp_Object cell;
1815
1816 placeholder = Fcons(Qnil, Qnil);
1817 cell = Fcons (make_number (n), placeholder);
1818 read_objects = Fcons (cell, read_objects);
1819
1820 /* Read the object itself. */
1809 tem = read0 (readcharfun); 1821 tem = read0 (readcharfun);
1810 read_objects = Fcons (Fcons (make_number (n), tem), read_objects); 1822
1823 /* Now put it everywhere the placeholder was... */
1824 substitute_object_in_subtree (tem, placeholder);
1825
1826 /* ...and #n# will use the real value from now on. */
1827 Fsetcdr (cell, tem);
1828
1811 return tem; 1829 return tem;
1812 } 1830 }
1813 /* #n# returns a previously read object. */ 1831 /* #n# returns a previously read object. */
@@ -2163,6 +2181,129 @@ read1 (readcharfun, pch, first_in_list)
2163 } 2181 }
2164} 2182}
2165 2183
2184
2185/* List of nodes we've seen during substitute_object_in_subtree. */
2186static Lisp_Object seen_list;
2187
2188static void
2189substitute_object_in_subtree (object, placeholder)
2190 Lisp_Object object;
2191 Lisp_Object placeholder;
2192{
2193 Lisp_Object check_object;
2194
2195 /* We haven't seen any objects when we start. */
2196 seen_list = Qnil;
2197
2198 /* Make all the substitutions. */
2199 check_object
2200 = substitute_object_recurse (object, placeholder, object);
2201
2202 /* Clear seen_list because we're done with it. */
2203 seen_list = Qnil;
2204
2205 /* The returned object here is expected to always eq the
2206 original. */
2207 if (!EQ (check_object, object))
2208 error ("Unexpected mutation error in reader");
2209}
2210
2211/* Feval doesn't get called from here, so no gc protection is needed. */
2212#define SUBSTITUTE(get_val, set_val) \
2213{ \
2214 Lisp_Object old_value = get_val; \
2215 Lisp_Object true_value \
2216 = substitute_object_recurse (object, placeholder,\
2217 old_value); \
2218 \
2219 if (!EQ (old_value, true_value)) \
2220 { \
2221 set_val; \
2222 } \
2223}
2224
2225static Lisp_Object
2226substitute_object_recurse (object, placeholder, subtree)
2227 Lisp_Object object;
2228 Lisp_Object placeholder;
2229 Lisp_Object subtree;
2230{
2231 /* If we find the placeholder, return the target object. */
2232 if (EQ (placeholder, subtree))
2233 return object;
2234
2235 /* If we've been to this node before, don't explore it again. */
2236 if (!EQ (Qnil, Fmemq (subtree, seen_list)))
2237 return subtree;
2238
2239 /* If this node can be the entry point to a cycle, remember that
2240 we've seen it. It can only be such an entry point if it was made
2241 by #n=, which means that we can find it as a value in
2242 read_objects. */
2243 if (!EQ (Qnil, Frassq (subtree, read_objects)))
2244 seen_list = Fcons (subtree, seen_list);
2245
2246 /* Recurse according to subtree's type.
2247 Every branch must return a Lisp_Object. */
2248 switch (XTYPE (subtree))
2249 {
2250 case Lisp_Vectorlike:
2251 {
2252 int i;
2253 int length = Flength(subtree);
2254 for (i = 0; i < length; i++)
2255 {
2256 Lisp_Object idx = make_number (i);
2257 SUBSTITUTE (Faref (subtree, idx),
2258 Faset (subtree, idx, true_value));
2259 }
2260 return subtree;
2261 }
2262
2263 case Lisp_Cons:
2264 {
2265 SUBSTITUTE (Fcar_safe (subtree),
2266 Fsetcar (subtree, true_value));
2267 SUBSTITUTE (Fcdr_safe (subtree),
2268 Fsetcdr (subtree, true_value));
2269 return subtree;
2270 }
2271
2272#ifdef USE_TEXT_PROPERTIES
2273 case Lisp_String:
2274 {
2275 /* Check for text properties in each interval.
2276 substitute_in_interval contains part of the logic. */
2277
2278 INTERVAL root_interval = XSTRING (subtree)->intervals;
2279 Lisp_Object arg = Fcons (object, placeholder);
2280
2281 traverse_intervals (root_interval, 1, 0,
2282 &substitute_in_interval, arg);
2283
2284 return subtree;
2285 }
2286#endif /* defined USE_TEXT_PROPERTIES */
2287
2288 /* Other types don't recurse any further. */
2289 default:
2290 return subtree;
2291 }
2292}
2293
2294/* Helper function for substitute_object_recurse. */
2295static void
2296substitute_in_interval (interval, arg)
2297 INTERVAL interval;
2298 Lisp_Object arg;
2299{
2300 Lisp_Object object = Fcar (arg);
2301 Lisp_Object placeholder = Fcdr (arg);
2302
2303 SUBSTITUTE(interval->plist, interval->plist = true_value);
2304}
2305
2306
2166#ifdef LISP_FLOAT_TYPE 2307#ifdef LISP_FLOAT_TYPE
2167 2308
2168#define LEAD_INT 1 2309#define LEAD_INT 1
@@ -3306,4 +3447,6 @@ You cannot count on them to still be there!");
3306 3447
3307 staticpro (&read_objects); 3448 staticpro (&read_objects);
3308 read_objects = Qnil; 3449 read_objects = Qnil;
3450 staticpro (&seen_list);
3451
3309} 3452}