diff options
| author | Richard M. Stallman | 1999-08-03 17:27:46 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1999-08-03 17:27:46 +0000 |
| commit | 9e062b6cc0b94f41969070fec398b922c5210737 (patch) | |
| tree | ba07572f9d4597f3e12c065b3940c05899fd87c6 /src | |
| parent | 08f87e3ce5f6bd5c1b1f017866937ad54b641a76 (diff) | |
| download | emacs-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.c | 145 |
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 | ||
| 409 | static Lisp_Object read0 (), read1 (), read_list (), read_vector (); | 409 | static Lisp_Object read0 (), read1 (), read_list (), read_vector (); |
| 410 | static int read_multibyte (); | 410 | static int read_multibyte (); |
| 411 | static Lisp_Object substitute_object_recurse (); | ||
| 412 | static 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. */ | ||
| 2186 | static Lisp_Object seen_list; | ||
| 2187 | |||
| 2188 | static void | ||
| 2189 | substitute_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 | |||
| 2225 | static Lisp_Object | ||
| 2226 | substitute_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. */ | ||
| 2295 | static void | ||
| 2296 | substitute_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 | } |