diff options
Diffstat (limited to 'src/lread.c')
| -rw-r--r-- | src/lread.c | 239 |
1 files changed, 139 insertions, 100 deletions
diff --git a/src/lread.c b/src/lread.c index 7c554ba8536..dbaadce4b40 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -103,8 +103,20 @@ static Lisp_Object read_objects_map; | |||
| 103 | (to reduce allocations), or nil. */ | 103 | (to reduce allocations), or nil. */ |
| 104 | static Lisp_Object read_objects_completed; | 104 | static Lisp_Object read_objects_completed; |
| 105 | 105 | ||
| 106 | /* File for get_file_char to read from. Use by load. */ | 106 | /* File and lookahead for get-file-char and get-emacs-mule-file-char |
| 107 | static FILE *instream; | 107 | to read from. Used by Fload. */ |
| 108 | static struct infile | ||
| 109 | { | ||
| 110 | /* The input stream. */ | ||
| 111 | FILE *stream; | ||
| 112 | |||
| 113 | /* Lookahead byte count. */ | ||
| 114 | signed char lookahead; | ||
| 115 | |||
| 116 | /* Lookahead bytes, in reverse order. Keep these here because it is | ||
| 117 | not portable to ungetc more than one byte at a time. */ | ||
| 118 | unsigned char buf[MAX_MULTIBYTE_LENGTH - 1]; | ||
| 119 | } *infile; | ||
| 108 | 120 | ||
| 109 | /* For use within read-from-string (this reader is non-reentrant!!) */ | 121 | /* For use within read-from-string (this reader is non-reentrant!!) */ |
| 110 | static ptrdiff_t read_from_string_index; | 122 | static ptrdiff_t read_from_string_index; |
| @@ -149,7 +161,7 @@ static Lisp_Object Vloads_in_progress; | |||
| 149 | static int read_emacs_mule_char (int, int (*) (int, Lisp_Object), | 161 | static int read_emacs_mule_char (int, int (*) (int, Lisp_Object), |
| 150 | Lisp_Object); | 162 | Lisp_Object); |
| 151 | 163 | ||
| 152 | static void readevalloop (Lisp_Object, FILE *, Lisp_Object, bool, | 164 | static void readevalloop (Lisp_Object, struct infile *, Lisp_Object, bool, |
| 153 | Lisp_Object, Lisp_Object, | 165 | Lisp_Object, Lisp_Object, |
| 154 | Lisp_Object, Lisp_Object); | 166 | Lisp_Object, Lisp_Object); |
| 155 | 167 | ||
| @@ -340,14 +352,13 @@ readchar (Lisp_Object readcharfun, bool *multibyte) | |||
| 340 | len = BYTES_BY_CHAR_HEAD (c); | 352 | len = BYTES_BY_CHAR_HEAD (c); |
| 341 | while (i < len) | 353 | while (i < len) |
| 342 | { | 354 | { |
| 343 | c = (*readbyte) (-1, readcharfun); | 355 | buf[i++] = c = (*readbyte) (-1, readcharfun); |
| 344 | if (c < 0 || ! TRAILING_CODE_P (c)) | 356 | if (c < 0 || ! TRAILING_CODE_P (c)) |
| 345 | { | 357 | { |
| 346 | while (--i > 1) | 358 | for (i -= c < 0; 0 < --i; ) |
| 347 | (*readbyte) (buf[i], readcharfun); | 359 | (*readbyte) (buf[i], readcharfun); |
| 348 | return BYTE8_TO_CHAR (buf[0]); | 360 | return BYTE8_TO_CHAR (buf[0]); |
| 349 | } | 361 | } |
| 350 | buf[i++] = c; | ||
| 351 | } | 362 | } |
| 352 | return STRING_CHAR (buf); | 363 | return STRING_CHAR (buf); |
| 353 | } | 364 | } |
| @@ -362,8 +373,9 @@ skip_dyn_bytes (Lisp_Object readcharfun, ptrdiff_t n) | |||
| 362 | if (FROM_FILE_P (readcharfun)) | 373 | if (FROM_FILE_P (readcharfun)) |
| 363 | { | 374 | { |
| 364 | block_input (); /* FIXME: Not sure if it's needed. */ | 375 | block_input (); /* FIXME: Not sure if it's needed. */ |
| 365 | fseek (instream, n, SEEK_CUR); | 376 | fseek (infile->stream, n - infile->lookahead, SEEK_CUR); |
| 366 | unblock_input (); | 377 | unblock_input (); |
| 378 | infile->lookahead = 0; | ||
| 367 | } | 379 | } |
| 368 | else | 380 | else |
| 369 | { /* We're not reading directly from a file. In that case, it's difficult | 381 | { /* We're not reading directly from a file. In that case, it's difficult |
| @@ -385,8 +397,9 @@ skip_dyn_eof (Lisp_Object readcharfun) | |||
| 385 | if (FROM_FILE_P (readcharfun)) | 397 | if (FROM_FILE_P (readcharfun)) |
| 386 | { | 398 | { |
| 387 | block_input (); /* FIXME: Not sure if it's needed. */ | 399 | block_input (); /* FIXME: Not sure if it's needed. */ |
| 388 | fseek (instream, 0, SEEK_END); | 400 | fseek (infile->stream, 0, SEEK_END); |
| 389 | unblock_input (); | 401 | unblock_input (); |
| 402 | infile->lookahead = 0; | ||
| 390 | } | 403 | } |
| 391 | else | 404 | else |
| 392 | while (READCHAR >= 0); | 405 | while (READCHAR >= 0); |
| @@ -459,15 +472,13 @@ readbyte_for_lambda (int c, Lisp_Object readcharfun) | |||
| 459 | 472 | ||
| 460 | 473 | ||
| 461 | static int | 474 | static int |
| 462 | readbyte_from_file (int c, Lisp_Object readcharfun) | 475 | readbyte_from_stdio (void) |
| 463 | { | 476 | { |
| 464 | if (c >= 0) | 477 | if (infile->lookahead) |
| 465 | { | 478 | return infile->buf[--infile->lookahead]; |
| 466 | block_input (); | 479 | |
| 467 | ungetc (c, instream); | 480 | int c; |
| 468 | unblock_input (); | 481 | FILE *instream = infile->stream; |
| 469 | return 0; | ||
| 470 | } | ||
| 471 | 482 | ||
| 472 | block_input (); | 483 | block_input (); |
| 473 | 484 | ||
| @@ -487,6 +498,19 @@ readbyte_from_file (int c, Lisp_Object readcharfun) | |||
| 487 | } | 498 | } |
| 488 | 499 | ||
| 489 | static int | 500 | static int |
| 501 | readbyte_from_file (int c, Lisp_Object readcharfun) | ||
| 502 | { | ||
| 503 | if (c >= 0) | ||
| 504 | { | ||
| 505 | eassert (infile->lookahead < sizeof infile->buf); | ||
| 506 | infile->buf[infile->lookahead++] = c; | ||
| 507 | return 0; | ||
| 508 | } | ||
| 509 | |||
| 510 | return readbyte_from_stdio (); | ||
| 511 | } | ||
| 512 | |||
| 513 | static int | ||
| 490 | readbyte_from_string (int c, Lisp_Object readcharfun) | 514 | readbyte_from_string (int c, Lisp_Object readcharfun) |
| 491 | { | 515 | { |
| 492 | Lisp_Object string = XCAR (readcharfun); | 516 | Lisp_Object string = XCAR (readcharfun); |
| @@ -508,7 +532,7 @@ readbyte_from_string (int c, Lisp_Object readcharfun) | |||
| 508 | } | 532 | } |
| 509 | 533 | ||
| 510 | 534 | ||
| 511 | /* Read one non-ASCII character from INSTREAM. The character is | 535 | /* Read one non-ASCII character from INFILE. The character is |
| 512 | encoded in `emacs-mule' and the first byte is already read in | 536 | encoded in `emacs-mule' and the first byte is already read in |
| 513 | C. */ | 537 | C. */ |
| 514 | 538 | ||
| @@ -530,14 +554,13 @@ read_emacs_mule_char (int c, int (*readbyte) (int, Lisp_Object), Lisp_Object rea | |||
| 530 | buf[i++] = c; | 554 | buf[i++] = c; |
| 531 | while (i < len) | 555 | while (i < len) |
| 532 | { | 556 | { |
| 533 | c = (*readbyte) (-1, readcharfun); | 557 | buf[i++] = c = (*readbyte) (-1, readcharfun); |
| 534 | if (c < 0xA0) | 558 | if (c < 0xA0) |
| 535 | { | 559 | { |
| 536 | while (--i > 1) | 560 | for (i -= c < 0; 0 < --i; ) |
| 537 | (*readbyte) (buf[i], readcharfun); | 561 | (*readbyte) (buf[i], readcharfun); |
| 538 | return BYTE8_TO_CHAR (buf[0]); | 562 | return BYTE8_TO_CHAR (buf[0]); |
| 539 | } | 563 | } |
| 540 | buf[i++] = c; | ||
| 541 | } | 564 | } |
| 542 | 565 | ||
| 543 | if (len == 2) | 566 | if (len == 2) |
| @@ -572,6 +595,20 @@ read_emacs_mule_char (int c, int (*readbyte) (int, Lisp_Object), Lisp_Object rea | |||
| 572 | } | 595 | } |
| 573 | 596 | ||
| 574 | 597 | ||
| 598 | /* An in-progress substitution of OBJECT for PLACEHOLDER. */ | ||
| 599 | struct subst | ||
| 600 | { | ||
| 601 | Lisp_Object object; | ||
| 602 | Lisp_Object placeholder; | ||
| 603 | |||
| 604 | /* Hash table of subobjects of OBJECT that might be circular. If | ||
| 605 | Qt, all such objects might be circular. */ | ||
| 606 | Lisp_Object completed; | ||
| 607 | |||
| 608 | /* List of subobjects of OBJECT that have already been visited. */ | ||
| 609 | Lisp_Object seen; | ||
| 610 | }; | ||
| 611 | |||
| 575 | static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object, | 612 | static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object, |
| 576 | Lisp_Object); | 613 | Lisp_Object); |
| 577 | static Lisp_Object read0 (Lisp_Object); | 614 | static Lisp_Object read0 (Lisp_Object); |
| @@ -580,9 +617,8 @@ static Lisp_Object read1 (Lisp_Object, int *, bool); | |||
| 580 | static Lisp_Object read_list (bool, Lisp_Object); | 617 | static Lisp_Object read_list (bool, Lisp_Object); |
| 581 | static Lisp_Object read_vector (Lisp_Object, bool); | 618 | static Lisp_Object read_vector (Lisp_Object, bool); |
| 582 | 619 | ||
| 583 | static Lisp_Object substitute_object_recurse (Lisp_Object, Lisp_Object, | 620 | static Lisp_Object substitute_object_recurse (struct subst *, Lisp_Object); |
| 584 | Lisp_Object); | 621 | static void substitute_in_interval (INTERVAL, void *); |
| 585 | static void substitute_in_interval (INTERVAL, Lisp_Object); | ||
| 586 | 622 | ||
| 587 | 623 | ||
| 588 | /* Get a character from the tty. */ | 624 | /* Get a character from the tty. */ |
| @@ -779,11 +815,9 @@ DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0, | |||
| 779 | doc: /* Don't use this yourself. */) | 815 | doc: /* Don't use this yourself. */) |
| 780 | (void) | 816 | (void) |
| 781 | { | 817 | { |
| 782 | register Lisp_Object val; | 818 | if (!infile) |
| 783 | block_input (); | 819 | error ("get-file-char misused"); |
| 784 | XSETINT (val, getc_unlocked (instream)); | 820 | return make_number (readbyte_from_stdio ()); |
| 785 | unblock_input (); | ||
| 786 | return val; | ||
| 787 | } | 821 | } |
| 788 | 822 | ||
| 789 | 823 | ||
| @@ -1028,6 +1062,15 @@ suffix_p (Lisp_Object string, const char *suffix) | |||
| 1028 | return string_len >= suffix_len && !strcmp (SSDATA (string) + string_len - suffix_len, suffix); | 1062 | return string_len >= suffix_len && !strcmp (SSDATA (string) + string_len - suffix_len, suffix); |
| 1029 | } | 1063 | } |
| 1030 | 1064 | ||
| 1065 | static void | ||
| 1066 | close_infile_unwind (void *arg) | ||
| 1067 | { | ||
| 1068 | FILE *stream = arg; | ||
| 1069 | eassert (infile == NULL || infile->stream == stream); | ||
| 1070 | infile = NULL; | ||
| 1071 | fclose (stream); | ||
| 1072 | } | ||
| 1073 | |||
| 1031 | DEFUN ("load", Fload, Sload, 1, 5, 0, | 1074 | DEFUN ("load", Fload, Sload, 1, 5, 0, |
| 1032 | doc: /* Execute a file of Lisp code named FILE. | 1075 | doc: /* Execute a file of Lisp code named FILE. |
| 1033 | First try FILE with `.elc' appended, then try with `.el', then try | 1076 | First try FILE with `.elc' appended, then try with `.el', then try |
| @@ -1347,7 +1390,7 @@ Return t if the file exists and loads successfully. */) | |||
| 1347 | } | 1390 | } |
| 1348 | if (! stream) | 1391 | if (! stream) |
| 1349 | report_file_error ("Opening stdio stream", file); | 1392 | report_file_error ("Opening stdio stream", file); |
| 1350 | set_unwind_protect_ptr (fd_index, fclose_unwind, stream); | 1393 | set_unwind_protect_ptr (fd_index, close_infile_unwind, stream); |
| 1351 | 1394 | ||
| 1352 | if (! NILP (Vpurify_flag)) | 1395 | if (! NILP (Vpurify_flag)) |
| 1353 | Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list); | 1396 | Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list); |
| @@ -1370,19 +1413,23 @@ Return t if the file exists and loads successfully. */) | |||
| 1370 | specbind (Qinhibit_file_name_operation, Qnil); | 1413 | specbind (Qinhibit_file_name_operation, Qnil); |
| 1371 | specbind (Qload_in_progress, Qt); | 1414 | specbind (Qload_in_progress, Qt); |
| 1372 | 1415 | ||
| 1373 | instream = stream; | 1416 | struct infile input; |
| 1417 | input.stream = stream; | ||
| 1418 | input.lookahead = 0; | ||
| 1419 | infile = &input; | ||
| 1420 | |||
| 1374 | if (lisp_file_lexically_bound_p (Qget_file_char)) | 1421 | if (lisp_file_lexically_bound_p (Qget_file_char)) |
| 1375 | Fset (Qlexical_binding, Qt); | 1422 | Fset (Qlexical_binding, Qt); |
| 1376 | 1423 | ||
| 1377 | if (! version || version >= 22) | 1424 | if (! version || version >= 22) |
| 1378 | readevalloop (Qget_file_char, stream, hist_file_name, | 1425 | readevalloop (Qget_file_char, &input, hist_file_name, |
| 1379 | 0, Qnil, Qnil, Qnil, Qnil); | 1426 | 0, Qnil, Qnil, Qnil, Qnil); |
| 1380 | else | 1427 | else |
| 1381 | { | 1428 | { |
| 1382 | /* We can't handle a file which was compiled with | 1429 | /* We can't handle a file which was compiled with |
| 1383 | byte-compile-dynamic by older version of Emacs. */ | 1430 | byte-compile-dynamic by older version of Emacs. */ |
| 1384 | specbind (Qload_force_doc_strings, Qt); | 1431 | specbind (Qload_force_doc_strings, Qt); |
| 1385 | readevalloop (Qget_emacs_mule_file_char, stream, hist_file_name, | 1432 | readevalloop (Qget_emacs_mule_file_char, &input, hist_file_name, |
| 1386 | 0, Qnil, Qnil, Qnil, Qnil); | 1433 | 0, Qnil, Qnil, Qnil, Qnil); |
| 1387 | } | 1434 | } |
| 1388 | unbind_to (count, Qnil); | 1435 | unbind_to (count, Qnil); |
| @@ -1813,7 +1860,7 @@ readevalloop_eager_expand_eval (Lisp_Object val, Lisp_Object macroexpand) | |||
| 1813 | 1860 | ||
| 1814 | static void | 1861 | static void |
| 1815 | readevalloop (Lisp_Object readcharfun, | 1862 | readevalloop (Lisp_Object readcharfun, |
| 1816 | FILE *stream, | 1863 | struct infile *infile0, |
| 1817 | Lisp_Object sourcename, | 1864 | Lisp_Object sourcename, |
| 1818 | bool printflag, | 1865 | bool printflag, |
| 1819 | Lisp_Object unibyte, Lisp_Object readfun, | 1866 | Lisp_Object unibyte, Lisp_Object readfun, |
| @@ -1913,7 +1960,7 @@ readevalloop (Lisp_Object readcharfun, | |||
| 1913 | if (b && first_sexp) | 1960 | if (b && first_sexp) |
| 1914 | whole_buffer = (BUF_PT (b) == BUF_BEG (b) && BUF_ZV (b) == BUF_Z (b)); | 1961 | whole_buffer = (BUF_PT (b) == BUF_BEG (b) && BUF_ZV (b) == BUF_Z (b)); |
| 1915 | 1962 | ||
| 1916 | instream = stream; | 1963 | infile = infile0; |
| 1917 | read_next: | 1964 | read_next: |
| 1918 | c = READCHAR; | 1965 | c = READCHAR; |
| 1919 | if (c == ';') | 1966 | if (c == ';') |
| @@ -2003,7 +2050,7 @@ readevalloop (Lisp_Object readcharfun, | |||
| 2003 | } | 2050 | } |
| 2004 | 2051 | ||
| 2005 | build_load_history (sourcename, | 2052 | build_load_history (sourcename, |
| 2006 | stream || whole_buffer); | 2053 | infile0 || whole_buffer); |
| 2007 | 2054 | ||
| 2008 | unbind_to (count, Qnil); | 2055 | unbind_to (count, Qnil); |
| 2009 | } | 2056 | } |
| @@ -2629,6 +2676,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 2629 | bool uninterned_symbol = false; | 2676 | bool uninterned_symbol = false; |
| 2630 | bool multibyte; | 2677 | bool multibyte; |
| 2631 | char stackbuf[MAX_ALLOCA]; | 2678 | char stackbuf[MAX_ALLOCA]; |
| 2679 | current_thread->stack_top = stackbuf; | ||
| 2632 | 2680 | ||
| 2633 | *pch = 0; | 2681 | *pch = 0; |
| 2634 | 2682 | ||
| @@ -2943,11 +2991,17 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 2943 | saved_doc_string_size = nskip + extra; | 2991 | saved_doc_string_size = nskip + extra; |
| 2944 | } | 2992 | } |
| 2945 | 2993 | ||
| 2946 | saved_doc_string_position = file_tell (instream); | 2994 | FILE *instream = infile->stream; |
| 2995 | saved_doc_string_position = (file_tell (instream) | ||
| 2996 | - infile->lookahead); | ||
| 2947 | 2997 | ||
| 2948 | /* Copy that many characters into saved_doc_string. */ | 2998 | /* Copy that many bytes into saved_doc_string. */ |
| 2999 | i = 0; | ||
| 3000 | for (int n = min (nskip, infile->lookahead); 0 < n; n--) | ||
| 3001 | saved_doc_string[i++] | ||
| 3002 | = c = infile->buf[--infile->lookahead]; | ||
| 2949 | block_input (); | 3003 | block_input (); |
| 2950 | for (i = 0; i < nskip && c >= 0; i++) | 3004 | for (; i < nskip && 0 <= c; i++) |
| 2951 | saved_doc_string[i] = c = getc_unlocked (instream); | 3005 | saved_doc_string[i] = c = getc_unlocked (instream); |
| 2952 | unblock_input (); | 3006 | unblock_input (); |
| 2953 | 3007 | ||
| @@ -3067,7 +3121,8 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3067 | } | 3121 | } |
| 3068 | else | 3122 | else |
| 3069 | { | 3123 | { |
| 3070 | Fsubstitute_object_in_subtree (tem, placeholder); | 3124 | Flread__substitute_object_in_subtree |
| 3125 | (tem, placeholder, read_objects_completed); | ||
| 3071 | 3126 | ||
| 3072 | /* ...and #n# will use the real value from now on. */ | 3127 | /* ...and #n# will use the real value from now on. */ |
| 3073 | i = hash_lookup (h, number, &hash); | 3128 | i = hash_lookup (h, number, &hash); |
| @@ -3424,6 +3479,24 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3424 | if (! NILP (result)) | 3479 | if (! NILP (result)) |
| 3425 | return unbind_to (count, result); | 3480 | return unbind_to (count, result); |
| 3426 | } | 3481 | } |
| 3482 | if (!quoted && multibyte) | ||
| 3483 | { | ||
| 3484 | int ch = STRING_CHAR ((unsigned char *) read_buffer); | ||
| 3485 | switch (ch) | ||
| 3486 | { | ||
| 3487 | case 0x2018: /* LEFT SINGLE QUOTATION MARK */ | ||
| 3488 | case 0x2019: /* RIGHT SINGLE QUOTATION MARK */ | ||
| 3489 | case 0x201B: /* SINGLE HIGH-REVERSED-9 QUOTATION MARK */ | ||
| 3490 | case 0x201C: /* LEFT DOUBLE QUOTATION MARK */ | ||
| 3491 | case 0x201D: /* RIGHT DOUBLE QUOTATION MARK */ | ||
| 3492 | case 0x201F: /* DOUBLE HIGH-REVERSED-9 QUOTATION MARK */ | ||
| 3493 | case 0x301E: /* DOUBLE PRIME QUOTATION MARK */ | ||
| 3494 | case 0xFF02: /* FULLWIDTH QUOTATION MARK */ | ||
| 3495 | case 0xFF07: /* FULLWIDTH APOSTROPHE */ | ||
| 3496 | xsignal2 (Qinvalid_read_syntax, build_string ("strange quote"), | ||
| 3497 | CALLN (Fstring, make_number (ch))); | ||
| 3498 | } | ||
| 3499 | } | ||
| 3427 | { | 3500 | { |
| 3428 | Lisp_Object result; | 3501 | Lisp_Object result; |
| 3429 | ptrdiff_t nbytes = p - read_buffer; | 3502 | ptrdiff_t nbytes = p - read_buffer; |
| @@ -3473,26 +3546,16 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3473 | } | 3546 | } |
| 3474 | } | 3547 | } |
| 3475 | 3548 | ||
| 3476 | 3549 | DEFUN ("lread--substitute-object-in-subtree", | |
| 3477 | /* List of nodes we've seen during substitute_object_in_subtree. */ | 3550 | Flread__substitute_object_in_subtree, |
| 3478 | static Lisp_Object seen_list; | 3551 | Slread__substitute_object_in_subtree, 3, 3, 0, |
| 3479 | 3552 | doc: /* In OBJECT, replace every occurrence of PLACEHOLDER with OBJECT. | |
| 3480 | DEFUN ("substitute-object-in-subtree", Fsubstitute_object_in_subtree, | 3553 | COMPLETED is a hash table of objects that might be circular, or is t |
| 3481 | Ssubstitute_object_in_subtree, 2, 2, 0, | 3554 | if any object might be circular. */) |
| 3482 | doc: /* Replace every reference to PLACEHOLDER in OBJECT with OBJECT. */) | 3555 | (Lisp_Object object, Lisp_Object placeholder, Lisp_Object completed) |
| 3483 | (Lisp_Object object, Lisp_Object placeholder) | ||
| 3484 | { | 3556 | { |
| 3485 | Lisp_Object check_object; | 3557 | struct subst subst = { object, placeholder, completed, Qnil }; |
| 3486 | 3558 | Lisp_Object check_object = substitute_object_recurse (&subst, object); | |
| 3487 | /* We haven't seen any objects when we start. */ | ||
| 3488 | seen_list = Qnil; | ||
| 3489 | |||
| 3490 | /* Make all the substitutions. */ | ||
| 3491 | check_object | ||
| 3492 | = substitute_object_recurse (object, placeholder, object); | ||
| 3493 | |||
| 3494 | /* Clear seen_list because we're done with it. */ | ||
| 3495 | seen_list = Qnil; | ||
| 3496 | 3559 | ||
| 3497 | /* The returned object here is expected to always eq the | 3560 | /* The returned object here is expected to always eq the |
| 3498 | original. */ | 3561 | original. */ |
| @@ -3501,26 +3564,12 @@ DEFUN ("substitute-object-in-subtree", Fsubstitute_object_in_subtree, | |||
| 3501 | return Qnil; | 3564 | return Qnil; |
| 3502 | } | 3565 | } |
| 3503 | 3566 | ||
| 3504 | /* Feval doesn't get called from here, so no gc protection is needed. */ | ||
| 3505 | #define SUBSTITUTE(get_val, set_val) \ | ||
| 3506 | do { \ | ||
| 3507 | Lisp_Object old_value = get_val; \ | ||
| 3508 | Lisp_Object true_value \ | ||
| 3509 | = substitute_object_recurse (object, placeholder, \ | ||
| 3510 | old_value); \ | ||
| 3511 | \ | ||
| 3512 | if (!EQ (old_value, true_value)) \ | ||
| 3513 | { \ | ||
| 3514 | set_val; \ | ||
| 3515 | } \ | ||
| 3516 | } while (0) | ||
| 3517 | |||
| 3518 | static Lisp_Object | 3567 | static Lisp_Object |
| 3519 | substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Object subtree) | 3568 | substitute_object_recurse (struct subst *subst, Lisp_Object subtree) |
| 3520 | { | 3569 | { |
| 3521 | /* If we find the placeholder, return the target object. */ | 3570 | /* If we find the placeholder, return the target object. */ |
| 3522 | if (EQ (placeholder, subtree)) | 3571 | if (EQ (subst->placeholder, subtree)) |
| 3523 | return object; | 3572 | return subst->object; |
| 3524 | 3573 | ||
| 3525 | /* For common object types that can't contain other objects, don't | 3574 | /* For common object types that can't contain other objects, don't |
| 3526 | bother looking them up; we're done. */ | 3575 | bother looking them up; we're done. */ |
| @@ -3530,15 +3579,16 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj | |||
| 3530 | return subtree; | 3579 | return subtree; |
| 3531 | 3580 | ||
| 3532 | /* If we've been to this node before, don't explore it again. */ | 3581 | /* If we've been to this node before, don't explore it again. */ |
| 3533 | if (!EQ (Qnil, Fmemq (subtree, seen_list))) | 3582 | if (!EQ (Qnil, Fmemq (subtree, subst->seen))) |
| 3534 | return subtree; | 3583 | return subtree; |
| 3535 | 3584 | ||
| 3536 | /* If this node can be the entry point to a cycle, remember that | 3585 | /* If this node can be the entry point to a cycle, remember that |
| 3537 | we've seen it. It can only be such an entry point if it was made | 3586 | we've seen it. It can only be such an entry point if it was made |
| 3538 | by #n=, which means that we can find it as a value in | 3587 | by #n=, which means that we can find it as a value in |
| 3539 | read_objects_completed. */ | 3588 | COMPLETED. */ |
| 3540 | if (hash_lookup (XHASH_TABLE (read_objects_completed), subtree, NULL) >= 0) | 3589 | if (EQ (subst->completed, Qt) |
| 3541 | seen_list = Fcons (subtree, seen_list); | 3590 | || hash_lookup (XHASH_TABLE (subst->completed), subtree, NULL) >= 0) |
| 3591 | subst->seen = Fcons (subtree, subst->seen); | ||
| 3542 | 3592 | ||
| 3543 | /* Recurse according to subtree's type. | 3593 | /* Recurse according to subtree's type. |
| 3544 | Every branch must return a Lisp_Object. */ | 3594 | Every branch must return a Lisp_Object. */ |
| @@ -3565,19 +3615,15 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj | |||
| 3565 | if (SUB_CHAR_TABLE_P (subtree)) | 3615 | if (SUB_CHAR_TABLE_P (subtree)) |
| 3566 | i = 2; | 3616 | i = 2; |
| 3567 | for ( ; i < length; i++) | 3617 | for ( ; i < length; i++) |
| 3568 | SUBSTITUTE (AREF (subtree, i), | 3618 | ASET (subtree, i, |
| 3569 | ASET (subtree, i, true_value)); | 3619 | substitute_object_recurse (subst, AREF (subtree, i))); |
| 3570 | return subtree; | 3620 | return subtree; |
| 3571 | } | 3621 | } |
| 3572 | 3622 | ||
| 3573 | case Lisp_Cons: | 3623 | case Lisp_Cons: |
| 3574 | { | 3624 | XSETCAR (subtree, substitute_object_recurse (subst, XCAR (subtree))); |
| 3575 | SUBSTITUTE (XCAR (subtree), | 3625 | XSETCDR (subtree, substitute_object_recurse (subst, XCDR (subtree))); |
| 3576 | XSETCAR (subtree, true_value)); | 3626 | return subtree; |
| 3577 | SUBSTITUTE (XCDR (subtree), | ||
| 3578 | XSETCDR (subtree, true_value)); | ||
| 3579 | return subtree; | ||
| 3580 | } | ||
| 3581 | 3627 | ||
| 3582 | case Lisp_String: | 3628 | case Lisp_String: |
| 3583 | { | 3629 | { |
| @@ -3585,11 +3631,8 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj | |||
| 3585 | substitute_in_interval contains part of the logic. */ | 3631 | substitute_in_interval contains part of the logic. */ |
| 3586 | 3632 | ||
| 3587 | INTERVAL root_interval = string_intervals (subtree); | 3633 | INTERVAL root_interval = string_intervals (subtree); |
| 3588 | AUTO_CONS (arg, object, placeholder); | ||
| 3589 | |||
| 3590 | traverse_intervals_noorder (root_interval, | 3634 | traverse_intervals_noorder (root_interval, |
| 3591 | &substitute_in_interval, arg); | 3635 | substitute_in_interval, subst); |
| 3592 | |||
| 3593 | return subtree; | 3636 | return subtree; |
| 3594 | } | 3637 | } |
| 3595 | 3638 | ||
| @@ -3601,12 +3644,10 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj | |||
| 3601 | 3644 | ||
| 3602 | /* Helper function for substitute_object_recurse. */ | 3645 | /* Helper function for substitute_object_recurse. */ |
| 3603 | static void | 3646 | static void |
| 3604 | substitute_in_interval (INTERVAL interval, Lisp_Object arg) | 3647 | substitute_in_interval (INTERVAL interval, void *arg) |
| 3605 | { | 3648 | { |
| 3606 | Lisp_Object object = Fcar (arg); | 3649 | set_interval_plist (interval, |
| 3607 | Lisp_Object placeholder = Fcdr (arg); | 3650 | substitute_object_recurse (arg, interval->plist)); |
| 3608 | |||
| 3609 | SUBSTITUTE (interval->plist, set_interval_plist (interval, true_value)); | ||
| 3610 | } | 3651 | } |
| 3611 | 3652 | ||
| 3612 | 3653 | ||
| @@ -4704,7 +4745,7 @@ syms_of_lread (void) | |||
| 4704 | { | 4745 | { |
| 4705 | defsubr (&Sread); | 4746 | defsubr (&Sread); |
| 4706 | defsubr (&Sread_from_string); | 4747 | defsubr (&Sread_from_string); |
| 4707 | defsubr (&Ssubstitute_object_in_subtree); | 4748 | defsubr (&Slread__substitute_object_in_subtree); |
| 4708 | defsubr (&Sintern); | 4749 | defsubr (&Sintern); |
| 4709 | defsubr (&Sintern_soft); | 4750 | defsubr (&Sintern_soft); |
| 4710 | defsubr (&Sunintern); | 4751 | defsubr (&Sunintern); |
| @@ -5017,8 +5058,6 @@ that are loaded before your customizations are read! */); | |||
| 5017 | read_objects_map = Qnil; | 5058 | read_objects_map = Qnil; |
| 5018 | staticpro (&read_objects_completed); | 5059 | staticpro (&read_objects_completed); |
| 5019 | read_objects_completed = Qnil; | 5060 | read_objects_completed = Qnil; |
| 5020 | staticpro (&seen_list); | ||
| 5021 | seen_list = Qnil; | ||
| 5022 | 5061 | ||
| 5023 | Vloads_in_progress = Qnil; | 5062 | Vloads_in_progress = Qnil; |
| 5024 | staticpro (&Vloads_in_progress); | 5063 | staticpro (&Vloads_in_progress); |